Python Forum
[PyGame] Rect object penetrates wall on one side
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
[PyGame] Rect object penetrates wall on one side
#1
I have an issue I cannot seem to figure out on my own. I am trying to set a wall that my player object can't go through and I use a solution I have used in the past that works fine on player controlled objects, but not non-player controlled objects. Please see code below.

The code in this file that gives me problems are lines 55-64. I found out that if I reverse them to right,left,left,right the problematic wall changes from left to right.

What I don't get is why this has anything to say? I'm telling it to just block whatever side the object appears to be hitting. Yet it won't work for non-player controlled objects.


import pygame

#Color definitions
BLACK = (0,0,0)
BLUE = (10,10,128)
GREEN = (5,200,0)
YELLOW = (255,255,0)
RED = (255,0,0)
RED2 = (178,34,34)

#Screen width

SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600

pygame.init()

all_sprite_list = pygame.sprite.Group()


class Player(pygame.sprite.Sprite):
    def __init__(self,x,y):
        super().__init__()
        self.image = pygame.Surface([50,45])
        self.image.fill(RED)
        self.rect = self.image.get_rect()
        self.rect.y = y
        self.rect.x = x
        self.speedy = 0
        self.speedx = 0
        self.rect.x = 199
        self.rect.y = 240

        self.change_x = 0
        self.walls = None

    def changespeed(self,x,y):
        self.change_x += x
        self.change_y += y

    def update(self):


        self.rect.y += self.speedy
        self.rect.x += self.speedx

        if self.rect.x > 360:
            self.speedx = -2
            self.speedy = 0
        if self.rect.x <200:
            self.speedx = 2



        block_hit_list = pygame.sprite.spritecollide(self,self.walls, False)
        for block in block_hit_list:
            if self.change_x > 0:
                self.rect.left = block.rect.right
            else:
                self.rect.right = block.rect.left
            if self.change_x < 0:
                self.rect.right = block.rect.left
            else:
                self.rect.left = block.rect.right




class Wall(pygame.sprite.Sprite):
    def __init__(self,x,y,width,height):
        super().__init__()

        self.image = pygame.Surface([width, height])
        self.image.fill(GREEN)

        self.rect = self.image.get_rect()
        self.rect.x = x
        self.rect.y = y

#Wall init

wall_list = pygame.sprite.Group()

#Pygame definitions

screen = pygame.display.set_mode([SCREEN_WIDTH, SCREEN_HEIGHT])
pygame.display.set_caption('Ninja!')
all_sprite_list = pygame.sprite.Group()


clock = pygame.time.Clock()



#Test wall
wall = Wall(320,240,10,90)
wall_list.add(wall)
all_sprite_list.add(wall)




#Spawns player
player = Player(50,50)
all_sprite_list.add(player)
player.walls = wall_list


clock = pygame.time.Clock()

#Loop

done = False

while not done:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            done = True



    all_sprite_list.update()
    screen.fill(BLACK)
    all_sprite_list.draw(screen)
    pygame.display.flip()
    clock.tick(60)
    pygame.display.flip()

pygame.quit()
Reply
#2
I just commented out these lines of code which seem to be redundant and now it works as I might expect it to. Let me know if you agree.
Edit:
Nope, sorry. Now it penetrates from the other direction Blush
		for block in block_hit_list:
			if self.change_x > 0:
				self.rect.left = block.rect.right
			else:
				self.rect.right = block.rect.left
			'''
			if self.change_x < 0:
				self.rect.right = block.rect.left
			else:
				self.rect.left = block.rect.right
			''' 
Reply
#3
Thanks for the suggestion, but excluding those lines just changes the problem from the left wall to the right wall.

Additionally, I dug through the web yesterday and did find one other person who had gone with a very similar solution to his problem, and he had also done it like I did with both if/else statements. Which just adds to my confusion as to why it wont work. Could it be that I'm not updating the graphics after those lines?

I did a trigger sequence where I print something every time the condition is correct, and I found that line 57-58 responds correctly, but the other ones didn't. It almost as if those lines never gets passed.
Reply
#4
Okay... I think I got it now.
import pygame
 
#Color definitions
BLACK = (0,0,0)
BLUE = (10,10,128)
GREEN = (5,200,0)
YELLOW = (255,255,0)
RED = (255,0,0)
RED2 = (178,34,34)
 
#Screen width
 
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
 
pygame.init()
 
all_sprite_list = pygame.sprite.Group()
 
 
class Player(pygame.sprite.Sprite):
	def __init__(self,x,y):
		super().__init__()
		self.image = pygame.Surface([50,45])
		self.image.fill(RED)
		self.rect = self.image.get_rect()
		self.rect.y = y
		self.rect.x = x
		self.speedy = 0
		self.speedx = 0
		self.rect.x = 499
		self.rect.y = 240
 
		self.change_x = 0
		self.walls = None
 
	def changespeed(self,x,y):
		self.change_x += x
		self.change_y += y
 
	def update(self):
 
 
		self.rect.y += self.speedy
		self.rect.x += self.speedx
 
		if self.rect.x > 360:
			self.speedx = -2
			self.speedy = 0
		if self.rect.x <200:
			self.speedx = 2
 
 
 
		block_hit_list = pygame.sprite.spritecollide(self,self.walls, False)
		if len (block_hit_list) != 0 :
			self.speedx = 0
 
 
 
class Wall(pygame.sprite.Sprite):
	def __init__(self,x,y,width,height):
		super().__init__()
 
		self.image = pygame.Surface([width, height])
		self.image.fill(GREEN)
 
		self.rect = self.image.get_rect()
		self.rect.x = x
		self.rect.y = y
 
#Wall init
 
wall_list = pygame.sprite.Group()
 
#Pygame definitions
 
screen = pygame.display.set_mode([SCREEN_WIDTH, SCREEN_HEIGHT])
pygame.display.set_caption('Ninja!')
all_sprite_list = pygame.sprite.Group()
 
 
clock = pygame.time.Clock()
 
 
 
#Test wall
wall = Wall(320,240,10,90)
wall_list.add(wall)
all_sprite_list.add(wall)
 
 
 
 
#Spawns player
player = Player(50,50)
all_sprite_list.add(player)
player.walls = wall_list
 
 
clock = pygame.time.Clock()
 
#Loop
 
done = False
 
while not done:
	for event in pygame.event.get():
		if event.type == pygame.QUIT:
			done = True
 
 
 
	all_sprite_list.update()
	screen.fill(BLACK)
	all_sprite_list.draw(screen)
	pygame.display.flip()
	clock.tick(60)
	pygame.display.flip()
 
pygame.quit()
Jan_97 likes this post
Reply
#5
Yes this works. Thank you.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Make a wall in turtle module Jan_97 2 7,173 Aug-18-2021, 08:47 PM
Last Post: Jan_97
  [PyGame] printing integers on pygame.draw.rect Shyckh 1 2,528 Aug-22-2020, 11:44 AM
Last Post: metulburr
  rect object not loading BlueClaw 2 4,163 Dec-11-2019, 04:25 PM
Last Post: BlueClaw
  Multiple wall collision in pacman rustyjoe 4 4,120 Aug-11-2019, 08:08 AM
Last Post: rustyjoe
  [PyGame] pygame.draw.rect function stretches across the screen instead of moving BubblesTheGiraffe 2 3,676 Jun-11-2019, 08:32 PM
Last Post: metulburr
  [PyGame] assigning rect to sprite pfaber11 1 2,203 May-18-2019, 05:39 PM
Last Post: metulburr

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020