Multiple wall collisions in python - python
I am creating a piece of code that involves a maze and doors that open when a button is hit. The problem is that when I put in the doors the player collision detects the doors but no longer detects the maze. I have put all my code down on here in hopes that if people can see any other problems they can help Thanks :)
import pygame, sys, random, time
#Setting up the colours
black = (0,0,0)
white = (255,255,255)
blue = (0,0,255)
green = (0,255,0)
red = (255,0,0)
orange = (248,100,1)
slateG = (112,128,144)
pink = (255,20,147)
dTurq = (0,206,209)
honeyD = (240,255,240)
maroon = (128,0,0)
goldenrod = (218,165,32)
sGreen = (0,255,127)
Fus = (255,0,255)
class player(pygame.sprite.Sprite):
change_x=0
change_y=0
#initialise the class
def __init__(self,x,y):
pygame.sprite.Sprite.__init__(self)
#the player will be 13x13
self.image = pygame.Surface([13,13])
self.image.fill(maroon)
self.rect = self.image.get_rect()
self.rect.top = y
self.rect.left = x
def changespeed(self,x,y): #this function changes the speed of the player
self.change_x+=x
self.change_y+=y
def updateWall(self,walls): #This is a collision detection function
old_x=self.rect.left
new_x = old_x+self.change_x
self.rect.left = new_x
collide = pygame.sprite.spritecollide(self,walls,False)
if collide:
self.rect.left = old_x
old_y = self.rect.top
new_y = old_y+self.change_y
self.rect.top = new_y
collide = pygame.sprite.spritecollide(self,walls,False)
if collide:
self.rect.top = old_y
def updateBarrier1(self,barriers):
gx=self.rect.left
nx = gx+self.change_x
self.rect.left = nx
collide = pygame.sprite.spritecollide(self,barriers,False)
if collide:
self.rect.left = gx
gy = self.rect.top
ny = gy+self.change_y
self.rect.top = ny
collide = pygame.sprite.spritecollide(self,barriers,False)
if collide:
self.rect.top = gy
class Wall(pygame.sprite.Sprite):
def __init__(self,x,y,width,height,color): #this sets up for the x/y coordinates, the width and the height and the colour of the wall
pygame.sprite.Sprite.__init__(self)
#how big will the wall be
self.image = pygame.Surface([width,height])
#what colour will the wall be
self.image.fill(color)
#initialising the x/y coordinates
self.rect = self.image.get_rect()
self.rect.top = y
self.rect.left = x
class Bar(pygame.sprite.Sprite):
def __init__(self,x,y,width,height,color):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface([width,height])
self.image.fill(color)
self.rect = self.image.get_rect()
self.rect.top = y
self.rect.left = x
class Button(pygame.sprite.Sprite):
def __init__(self,x,y,width,height,color):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface([width,height]) #the buttons dimensions
self.image.fill(color) #colour of the button
#x/y coordinates
self.rect = self.image.get_rect()
self.rect.top=y
self.rect.left=x
#Setting up the walls for the maze
def maze1():
wall_list = pygame.sprite.RenderPlain()
#Walls of maze
walls = [[0,0,20,390,goldenrod],[0,410,20,390,goldenrod],[0,0,1000,20,goldenrod],
[980,0,20,800,goldenrod],[0,780,980,20,goldenrod],[20,40,940,10,dTurq],
[950,40,10,350,dTurq],[950,410,10,350,dTurq],[40,750,370,10,dTurq],
[430,570,10,210,dTurq],[430,570,240,10,dTurq],[660,570,10,210,dTurq],
[690,550,10,210,dTurq],[690,750,260,10,dTurq],[400,550,10,210,dTurq],
[40,410,10,350,dTurq],[20,100,30,10,dTurq], [40,100,10,290,dTurq],
[50,410,460,10,green],[50,380,350,10,green],[430,380,100,10,green],
[530,380,10,100,green],[500,410,10,100,green],[500,510,60,10,green],
[550,510,10,30,green],[580,510,10,30,green],[400,540,160,10,dTurq],
[580,540,120,10,dTurq],[530,480,150,10,green],[680,430,10,60,green],
[580,510,130,10,green],[710,460,10,60,green],[680,430,250,10,green],
[710,460,190,10,green],[920,430,10,300,green],[890,460,10,230,green],
[820,720,100,10,green],[820,690,80,10,green],[810,690,10,40,green],
[550,410,400,10,sGreen],[550,210,10,200,sGreen],[250,210,300,10,sGreen],
[250,210,10,120,sGreen],[250,330,180,10,sGreen],[430,330,10,50,sGreen],
[580,380,370,10,sGreen],[580,180,10,200,sGreen],[220,180,360,10,sGreen],
[220,180,10,180,sGreen],[220,360,180,10,sGreen],[390,360,10,20,sGreen]]
for item in walls:
wall = Wall(item[0],item[1],item[2],item[3],item[4])
wall_list.add(wall)
return wall_list
def BarrierWhite():
barriers = pygame.sprite.RenderPlain()
barrier = [[500,540,10,40,white],[400,180,10,40,white]]
for item in barrier:
barrie = Bar(item[0],item[1],item[2],item[3],item[4])
barriers.add(barrie)
return barriers
def BarrierPink():
wall_list = pygame.sprite.RenderPlain()
walls = [[550,520,40,10,pink],[20,600,30,10,pink],[300,380,10,40,pink]]
for item in walls:
wall = Wall(item[0],item[1],item[2],item[3],item[4])
wall_list.add(wall)
return wall_list
def Buttons(): #Creating buttons
buttons = pygame.sprite.RenderPlain()
button1 = [[965,765,10,10,white]]
for item in button1:
button = Button(item[0],item[1],item[2],item[3],item[4])
buttons.add(button)
return buttons
def pinkButton():
pinkB = pygame.sprite.RenderPlain()
b = [[835,705,10,10,pink]]
for item in b:
button = Button(item[0],item[1],item[2],item[3],item[4])
pinkB.add(button)
return pinkB
#main line
pygame.init()
window = pygame.display.set_mode([1000,800])
background = pygame.Surface(window.get_size())
background = background.convert()
background.fill(black)
player = player(25,25)
movingsprt = pygame.sprite.RenderPlain()
movingsprt.add(player)
clock = pygame.time.Clock()
wall_list = maze1()
barriers = BarrierWhite()
buttons = Buttons()
B1 = pinkButton()
done = False
while done == False:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
#This makes the player move
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
player.changespeed(-6,0)
if event.key == pygame.K_RIGHT:
player.changespeed(6,0)
if event.key == pygame.K_UP:
player.changespeed(0,-6)
if event.key == pygame.K_DOWN:
player.changespeed(0,6)
#This stops the player from moving
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
player.changespeed(6,0)
if event.key == pygame.K_RIGHT:
player.changespeed(-6,0)
if event.key == pygame.K_UP:
player.changespeed(0,6)
if event.key == pygame.K_DOWN:
player.changespeed(0,-6)
player.updateWall(wall_list)
player.updateBarrier1(barriers)
window.fill(black)
movingsprt.draw(window)
barriers.draw(window)
wall_list.draw(window)
buttons.draw(window)
B1.draw(window)
pygame.display.flip()
clock.tick(40)
pygame.quit()
Also if someone could tell me how to put a countdown timer that will disable the player and display a game over sign that would be awesome too :D
Adding doors (or barriers as you call them in your code) makes the wall collision ineffective because of a design problem in your game.
Here's what you do in your main loop:
player.updateWall(wall_list)
player.updateBarrier1(barriers)
You first check with collisions for a wall, then check again for collisions with barriers.
The problem is that you incorporated the part that makes your character move in those updateWall and updateBarrier1 methods.
So for instance, if your character collides with a wall, but not with a door, the character will still move because the updateBarrier1 method will not detect a collision with a barrier (door) and will make him move.
Instead, you should do some methods called collides_wall and collides_barrier that return True or False and then replace the two previously quoted lines by:
if not player.collides_wall(wall_list) and not player.collides_barriers(barriers):
player.move()
With move a method that would move your player as you currently do in the updateSomething methods.
Note: Someone pointed out in the comments that you also don't need two separate methods for walls and barriers collision, because ultimately they are both sprites and you do exactly the same operations on both of them. So just add a collides method.
Related
I am having trouble coding my collision check function for my fps game. How can I write my collision function?
I am stuck on how to write my collision function in my player class. Also should I put my collision check function in my player class or should it be in my bullet class? I honestly don't know. I mean common sense says my bullet should have the collision check function in it, just because I want the top of my bullet checking if it hits a falling cement block sprite, but I don't know.... I would appreciate an answer on how to code my collision function. This would really help me out. My collision function is right below my shoot function in my player class. My code: import pygame pygame.init() #screen settings WIDTH = 1000 HEIGHT = 400 screen = pygame.display.set_mode((WIDTH, HEIGHT)) pygame.display.set_caption("AutoPilot") screen.fill((255, 255, 255)) #fps FPS = 120 clock = pygame.time.Clock() #load images bg = pygame.image.load('background/street.png').convert_alpha() # background bullets = pygame.image.load('car/bullet.png').convert_alpha() debris_img = pygame.image.load('debris/cement.png') #define game variables shoot = False #player class class Player(pygame.sprite.Sprite): def __init__(self, scale, speed): pygame.sprite.Sprite.__init__(self) self.bullet = pygame.image.load('car/bullet.png').convert_alpha() self.bullet_list = [] self.speed = speed #self.x = x #self.y = y self.moving = True self.frame = 0 self.flip = False self.direction = 0 #load car self.images = [] img = pygame.image.load('car/car.png').convert_alpha() img = pygame.transform.scale(img, (int(img.get_width()) * scale, (int(img.get_height()) * scale))) self.images.append(img) self.image = self.images[0] self.rect = self.image.get_rect() self.update_time = pygame.time.get_ticks() self.movingLeft = False self.movingRight = False self.rect.x = 465 self.rect.y = 325 #draw car to screen def draw(self): screen.blit(self.image, (self.rect.centerx, self.rect.centery)) #move car def move(self): #reset the movement variables dx = 0 dy = 0 #moving variables if self.movingLeft and self.rect.x > 33: dx -= self.speed self.flip = True self.direction = -1 if self.movingRight and self.rect.x < 900: dx += self.speed self.flip = False self.direction = 1 #update rectangle position self.rect.x += dx self.rect.y += dy #shoot def shoot(self): bullet = Bullet(self.rect.centerx + 18, self.rect.y + 30, self.direction) bullet_group.add(bullet) #def collision(self): #write code here #bullet class class Bullet(pygame.sprite.Sprite): def __init__(self, x, y, direction): pygame.sprite.Sprite.__init__(self) self.speed = 5 self.image = bullets self.rect = self.image.get_rect() self.rect.center = (x,y) self.direction = direction def update(self): self.rect.centery -= self.speed #check if bullet has gone off screen if self.rect.top < 1: self.kill() #debris class class Debris(pygame.sprite.Sprite): def __init__(self, x, y, scale, speed): pygame.sprite.Sprite.__init__(self) self.scale = scale self.x = x self.y = y self.speed = speed self.vy = 0 self.on_ground = True self.move = True self.health = 4 self.max_health = self.health self.alive = True #load debris self.image = debris_img self.rect = self.image.get_rect() self.rect.center = (x,y) ######################CAR/DEBRIS########################## player = Player(1,5) debris = Debris(300,15,1,5) ########################################################## #groups bullet_group = pygame.sprite.Group() debris_group = pygame.sprite.Group() debris_group.add(debris) #game runs here run = True while run: #draw street screen.blit(bg, [0, 0]) #update groups bullet_group.update() bullet_group.draw(screen) debris_group.update() debris_group.draw(screen) #draw car player.draw() player.move() for event in pygame.event.get(): if event.type == pygame.QUIT: run = False #check if key is down if event.type == pygame.KEYDOWN: if event.key == pygame.K_ESCAPE: run = False if event.key == pygame.K_a: player.movingLeft = True if event.key == pygame.K_d: player.movingRight = True if event.key == pygame.K_SPACE: player.shoot() shoot = True #check if key is up if event.type == pygame.KEYUP: if event.key == pygame.K_a: player.movingLeft = False if event.key == pygame.K_d: player.movingRight = False #update the display pygame.display.update() pygame.display.flip() clock.tick(FPS) pygame.quit()
I suggest reading How do I detect collision in pygame?. Use pygame.sprite.spritecollide() for the collision detection. Set the dokill argument True. So the bullets gat automatically destroyed. The following code is base on one of your previous questions: Check collision of bullet sprite hitting cement block sprite class Car(pygame.sprite.Sprite): # [...] def collision(self, debris_group): for debris in debris_group: if pygame.sprite.spritecollide(debris, bullet_group, True): debris.health -= 1 if debris.health <= 0: debris.kill()
Getting two moving objects from the same class to interact (pygame)
This is my Player class, I currently have both players interacting with the walls (which is a separate class in the code but not pasted onto this question) but I need a way to prevent players from walking through each other just as players can't walk through walls. The issue is that I can use self.rect.right = block.rect.left to prevent the player from going through the wall when its right side touches the left side of the wall but I cannot use self.rect.right = self.rect.left to prevent player one from going through player 2 because it does not specify that one refers to player one and the other refers to player 2. Any suggestions would be appreciated. class Player(pygame.sprite.Sprite): # Constructor function def __init__(self, x, y, colour): # Call the parent's constructor super().__init__() # Set height, width self.image = pygame.Surface([50, 50]) self.image.fill(colour) # Make our top-left corner the passed-in location. self.rect = self.image.get_rect() self.rect.y = y self.rect.x = x # Set speed vector self.change_x = 0 self.change_y = 0 self.walls = None def changespeed(self, x, y): self.change_x += x self.change_y += y def update(self): # Move left/right self.rect.x += self.change_x # Did this update cause us to hit a wall? block_hit_list = pygame.sprite.spritecollide(self, self.walls, False) for block in block_hit_list: # If we are moving right, set our right side to the left side of # the item we hit if self.change_x > 0: self.rect.right = block.rect.left else: # Otherwise if we are moving left, do the opposite. self.rect.left = block.rect.right # Move up/down self.rect.y += self.change_y # Check and see if we hit anything block_hit_list = pygame.sprite.spritecollide(self, self.walls, False) for block in block_hit_list: # Reset our position based on the top/bottom of the object. if self.change_y > 0: self.rect.bottom = block.rect.top else: self.rect.top = block.rect.bottom This is where I create the players as objects P1 = Player(200, 200, BLUE) P2 = Player(300, 300, WHITE) P1.walls = wall_list P2.walls = wall_list all_sprite_list.add(P1) all_sprite_list.add(P2) Full code: import pygame import ctypes user32 = ctypes.windll.user32 # Colors BLACK = (0, 0, 0) WHITE = (255, 255, 255) BLUE = (50, 50, 255) # Screen dimensions SCREEN_WIDTH = user32.GetSystemMetrics(78)#1600 SCREEN_HEIGHT = user32.GetSystemMetrics(79)#900 WALL_THICKNESS = 10 MAP_WIDTH = SCREEN_WIDTH - 300 #1300 MAP_HEIGHT = SCREEN_HEIGHT - 160 #700 HEIGHT = SCREEN_HEIGHT - MAP_HEIGHT #START CORDS = 150, 150 class Player(pygame.sprite.Sprite): # Constructor function def __init__(self, x, y, colour): # Call the parent's constructor super().__init__() # Set height, width self.image = pygame.Surface([50, 50]) self.image.fill(colour) # Make our top-left corner the passed-in location. self.rect = self.image.get_rect() self.rect.y = y self.rect.x = x # Set speed vector self.change_x = 0 self.change_y = 0 self.walls = None def changespeed(self, x, y): self.change_x += x self.change_y += y def update(self): # Move left/right self.rect.x += self.change_x # Did this update cause us to hit a wall? block_hit_list = pygame.sprite.spritecollide(self, self.walls, False) for block in block_hit_list: # If we are moving right, set our right side to the left side of # the item we hit if self.change_x > 0: self.rect.right = block.rect.left else: # Otherwise if we are moving left, do the opposite. self.rect.left = block.rect.right # Move up/down self.rect.y += self.change_y # Check and see if we hit anything block_hit_list = pygame.sprite.spritecollide(self, self.walls, False) for block in block_hit_list: # Reset our position based on the top/bottom of the object. if self.change_y > 0: self.rect.bottom = block.rect.top else: self.rect.top = block.rect.bottom class Wall(pygame.sprite.Sprite): def __init__(self, x, y, width, height): # Call the parent's constructor super().__init__() # Make a blue wall, of the size specified in the parameters self.image = pygame.Surface([width, height]) self.image.fill(BLUE) # Make our top-left corner the passed-in location. self.rect = self.image.get_rect() self.rect.y = y self.rect.x = x # Call this function so the Pygame library can initialize itself pygame.init() # Create an 800x600 sized screen screen = pygame.display.set_mode([SCREEN_WIDTH, SCREEN_HEIGHT], pygame.FULLSCREEN) # Set the title of the window pygame.display.set_caption('Haste') # List to hold all the sprites all_sprite_list = pygame.sprite.Group() # Make the walls. (x_pos, y_pos, width, height) wall_list = pygame.sprite.Group() #--------------------------------------------------------------------WALLS #OUTER WALL 700 1500 - 1490. 1300 wall = Wall(150, 150, WALL_THICKNESS, MAP_HEIGHT - 150)#map height (left verticle) wall_list.add(wall) all_sprite_list.add(wall) wall = Wall(160, 150, MAP_WIDTH, WALL_THICKNESS)#(top across) wall_list.add(wall) all_sprite_list.add(wall) wall = Wall(160, MAP_HEIGHT - 10, MAP_WIDTH, WALL_THICKNESS)#(bottom across) wall_list.add(wall) all_sprite_list.add(wall) wall = Wall(MAP_WIDTH + 150, 150, WALL_THICKNESS, MAP_HEIGHT - 150)#(right verticle) wall_list.add(wall) all_sprite_list.add(wall) # Create the player paddle object P1 = Player(200, 200, BLUE) P2 = Player(300, 300, WHITE) P1.walls = wall_list P2.walls = wall_list all_sprite_list.add(P1) all_sprite_list.add(P2) clock = pygame.time.Clock() done = False sped = 9 speed = -9 while not done: for event in pygame.event.get(): if event.type == pygame.QUIT: done = True elif event.type == pygame.KEYDOWN: if event.key == pygame.K_LEFT: P1.changespeed(speed, 0) if event.key == pygame.K_RIGHT: P1.changespeed(sped, 0) if event.key == pygame.K_UP: P1.changespeed(0, speed) if event.key == pygame.K_DOWN: P1.changespeed(0, sped) if event.key == pygame.K_a: P2.changespeed(speed, 0) if event.key == pygame.K_d: P2.changespeed(sped, 0) if event.key == pygame.K_w: P2.changespeed(0, speed) if event.key == pygame.K_s: P2.changespeed(0, sped) elif event.type == pygame.KEYUP: if event.key == pygame.K_LEFT: P1.changespeed(sped, 0) if event.key == pygame.K_RIGHT: P1.changespeed(speed, 0) if event.key == pygame.K_UP: P1.changespeed(0, sped) if event.key == pygame.K_DOWN: P1.changespeed(0, speed) if event.key == pygame.K_a: P2.changespeed(sped, 0) if event.key == pygame.K_d: P2.changespeed(speed, 0) if event.key == pygame.K_w: P2.changespeed(0, sped) if event.key == pygame.K_s: P2.changespeed(0, speed) all_sprite_list.update() screen.fill(BLACK) all_sprite_list.draw(screen) pygame.display.flip() clock.tick(60) pygame.quit()
I cannot use self.rect.right = self.rect.left ... Correct: you have to write your code to refer to each Player as appropriate. You cannot refer to both of them as self. Very simply, you have to use the appropriate variables, such as: P1.rect.right == P2.rect.left Whether you design this as a loop through player pairings, or check each player in turn against each of the others, depends on your system design. For instance, given only two players, you simply write a loop that flips between the two players: active, passive = P1, P2 # P1 is the currently active player while run_game: ... if active.rect.right == passive.rect.left: ... #avoid collision ... # Switch active player (take turns) at end of loop active, passive = passive, active
How can I make Pygame check if two images are colliding?
I've tried everything and cannot get how I check if my two blocks have collided. Here's my code: import pygame import random pygame.init() display_width = 600 display_height = 300 class player:#Just info for player width = 30 height = 30 x = display_width // 2 y = display_height - height - 5 a = x + 30 pic = 'SnakePart.png' thing = pygame.image.load(pic) def place(x,y):#function for placing player object gameDisplay.blit(player.thing, (player.x,player.y)) class enemy:#enemy info class width = 30 height = 30 x = random.randint(0,display_width - width) y = 1 a = x + 30 pic = 'Apple.png' thing = pygame.image.load(pic) speed = 10#sets speed def change_x(): enemy.x = random.randint(0,display_width - enemy.width) def change_y(): enemy.y += enemy.speed def make(x,y):#set up funtion gameDisplay.blit(enemy.thing, (x,y)) def respawn():#reseting enemy entity enemy.y = 1 gameDisplay.blit(enemy.thing, (enemy.x,enemy.y)) player.thing#uses the variables in the classes to set up the images for use enemy.thing black = (0,0,0) white = (255,255,255) player_height = 30 player_width = 30 clock = pygame.time.Clock() x_change = 0#This is to make movment gameDisplay = pygame.display.set_mode((display_width,display_height)) pygame.display.set_caption('Bullet Hell.') dodged = 0#counter will be used in the more polished vesion. while True: for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() quit() if event.type == pygame.KEYDOWN:#Checks for keypress, to make player entity move if event.key == pygame.K_RIGHT: x_change = 5 if event.key == pygame.K_LEFT: x_change = -5 if event.type == pygame.KEYUP: if event.key == pygame.K_RIGHT or pygame.K_LEFT: x_change = 0 player.x += x_change gameDisplay.fill(black) enemy.make(enemy.x,enemy.y) player.place(player.x,player.y) enemy.change_y() if enemy.y > display_height:#Brings enemy back to top once it has gotten to th bottom enemy.change_x() dodged += 1 enemy.respawn() pygame.display.update() clock.tick(60) It's all really the collision and I think I'll be good. Oh yeah, if you guys could also tell me how to display text that would be great!
Take a look at the pygame.Rect class and its collision detection methods. Give your objects rects as attributes which you get by calling the .get_rect() method of the images/surfaces. Update the coordinates of these rects each frame and in your main loop call player.rect.colliderect(enemy.rect) to check if the two rects collide. import pygame import random pygame.init() BLACK = pygame.Color('black') display = pygame.display.set_mode((600, 300)) # Create a rect with the dimensions of the screen at coords (0, 0). display_rect = display.get_rect() clock = pygame.time.Clock() # SNAKE_IMAGE = pygame.image.load('SnakePart.png').convert_alpha() # APPLE_IMAGE = pygame.image.load('Apple.png').convert_alpha() # Replacement images. SNAKE_IMAGE = pygame.Surface((30, 30)) SNAKE_IMAGE.fill((30, 150, 0)) APPLE_IMAGE = pygame.Surface((30, 30)) APPLE_IMAGE.fill((150, 30, 0)) class Player: def __init__(self): self.x = display_rect.w // 2 self.y = display_rect.h - 30 - 5 self.image = SNAKE_IMAGE # Create a rect with the size of the image at coords (0, 0). self.rect = self.image.get_rect() # Set the topleft coords of the rect. self.rect.x = self.x self.rect.y = self.y self.x_change = 0 def update(self): """Move the player.""" self.x += self.x_change # Always update the rect, because it's # needed for the collision detection. self.rect.x = self.x def draw(self, display): display.blit(self.image, self.rect) class Enemy: def __init__(self): self.x = random.randint(0, display_rect.w - 30) self.y = 1 self.image = APPLE_IMAGE # You can also pass the coords directly to `get_rect`. self.rect = self.image.get_rect(topleft=(self.x, self.y)) self.speed = 10 def change_x(self): self.x = random.randint(0, display_rect.w - self.rect.w) self.rect.x = self.x def change_y(self): self.y += self.speed self.rect.y = self.y def draw(self, display): display.blit(self.image, self.rect) def reset(self): """Reset self.y position.""" self.y = -30 player = Player() enemy = Enemy() dodged = 0 done = False while not done: for event in pygame.event.get(): if event.type == pygame.QUIT: done = True if event.type == pygame.KEYDOWN: if event.key == pygame.K_RIGHT: player.x_change = 5 if event.key == pygame.K_LEFT: player.x_change = -5 if event.type == pygame.KEYUP: if event.key == pygame.K_RIGHT or pygame.K_LEFT: player.x_change = 0 # Game logic. player.update() enemy.change_y() # Brings enemy back to top once it has gotten to th bottom if enemy.y > display_rect.h: enemy.change_x() dodged += 1 enemy.reset() # Check if the player and the rect collide. if player.rect.colliderect(enemy.rect): print('Collided!') # Draw everything. display.fill(BLACK) enemy.draw(display) player.draw(display) pygame.display.update() clock.tick(60) pygame.quit() I've changed some more things (btw, better call the images self.image not thing ;)) especially in the classes: The attributes of the classes should be in __init__ methods to make them instance attributes instead of class attributes (which get shared by all instances). Also, check out how to create instances of your classes. The methods should all have self as their first parameter (that's a reference to the instance). To access the attributes inside of the classes prepend them with self, e.g. self.x += self.x_change. The player.x += x_change line fits better inside the Player class' update method, so you can just update the position and other player attributes by calling player.update(). There's a convention that class names should be uppercase MyClass whereas instances should have lowercase names my_instance.
Python, having trouble controlling enemy sprite
Complete novice, new to programming in general. I am trying to write a side scroller game in python, using pygame. I have created three different libraries for my sprite classes for: the player, the enemy, and the land. I made the land a sprite so that the player can interact (collide) with different objects in the land class and not be able to pass through them. The issue I am having is that I want the enemy sprite to interact with the land sprite as well. Ideally, I want the enemy sprites to start at point "x" and be set in motion (-2) until it comes into contact with the land sprite, at which point I want it to reverse direction. I have been trying everything I can think of, and searching online for a solution to make this work with no success. It seems like it should be really simple, but I can't make it work. Thank you for your time. here's my code: land sprite : import pygame class Object(pygame.sprite.Sprite): def __init__(self,image_file): pygame.sprite.Sprite.__init__(self) self.image = pygame.image.load(image_file) self.rect = self.image.get_rect() player sprite : import pygame class Player(pygame.sprite.Sprite): change_x = 0 change_y = 0 jump_ready = False frame_since_collision = 0 frame_since_jump = 0 frame = 0 def __init__(self): pygame.sprite.Sprite.__init__(self) self.images = [] for i in range(1,9): img = pygame.image.load("pit"+str(i)+".png").convert() img.set_colorkey((0,0,0)) self.images.append(img) self.image = self.images[0] self.rect = self.image.get_rect() def changespeed_x(self,x): self.change_x = x def changespeed_y(self,y): self.change_y = y def update(self,ground,brick,enemy): if self.change_x < 0: self.frame += 1 if self.frame > 3*4: self.frame = 0 self.image = self.images[self.frame//4] if self.change_x > 0: self.frame += 1 if self.frame > 3*4: self.frame = 0 self.image = self.images[self.frame//4+4] old_x = self.rect.x new_x = old_x + self.change_x self.rect.x = new_x player_health = 5 hurt = pygame.sprite.spritecollide(self,enemy,False) if hurt: player_health -= 1 print(player_health) brick_break = pygame.sprite.spritecollide(self,brick,True) collide = pygame.sprite.spritecollide(self,ground,False) if collide: self.rect.x = old_x old_y = self.rect.y new_y = old_y + self.change_y self.rect.y = new_y touch_list = pygame.sprite.spritecollide(self,ground,False) for ground in touch_list: self.rect.y = old_y self.rect.x = old_x self.change_y = 0 self.frame_since_collision = 0 if self.frame_since_collision < 6 and self.frame_since_jump < 6: self.frame_since_jump = 100 self.change_y -= 8 self.frame_since_collision += 1 self.frame_since_jump += 1 def calc_grav(self): self.change_y += .35 if self.rect.y >= 450 and self.change_y >= 0: self.change_y = 0 self.rect.y = 450 self.frame_since_collision = 0 def jump(self,blocks): self.jump_ready = True self.frame_since_jump = 0 this is the enemy sprite that works, it only moves left, every time I tried a variation of the collision code like I have in the player class the sprite would just stop when it collided with the land sprite enemy sprite : import pygame class Enemy(pygame.sprite.Sprite): def __init__(self,image_file): pygame.sprite.Sprite.__init__(self) self.image = pygame.image.load(image_file) self.image = self.image.convert() self.image.set_colorkey((0,0,0)) self.rect = self.image.get_rect() def update(self,ground): change_x = -2 self.rect.x += change_x and my main program code : # first must import import pygame import random import thing import enemy import player # initialize the game engine pygame.init() # define some colors # more color combos at www.colorpicker.com black = ( 0, 0, 0) white = ( 255, 255, 255) green = (0, 255, 0) red = (255, 0, 0) blue = (131,226,252) # open and set window size. screen_width = 700 screen_height = 350 screen = pygame.display.set_mode([screen_width,screen_height]) break_list = pygame.sprite.Group() land_list = pygame.sprite.Group() enemy_list = pygame.sprite.Group() all_sprites_list = pygame.sprite.Group() cloud = pygame.image.load("cumulus-huge.png").convert() for x in range(300,500,60): brick = thing.Object("birck.png") brick.rect.x = x brick.rect.y = 180 break_list.add(brick) all_sprites_list.add(brick) for x in range(0,200,50): wall = thing.Object("Sky3.png") wall.rect.x = -180 wall.rect.y = x land_list.add(wall) all_sprites_list.add(wall) for x in range (-50,1400,70): ground = thing.Object("Ground2.png") ground.rect.x = x ground.rect.y = 305 land_list.add(ground) all_sprites_list.add(ground) monster = enemy.Enemy("monster1.png") monster.rect.x = 650 monster.rect.y = 250 enemy_list.add(monster) all_sprites_list.add(monster) for x in range(760,1070,300): pipe = thing.Object("pipe-top.png") pipe.rect.x = x pipe.rect.y = 225 land_list.add(pipe) all_sprites_list.add(pipe) player = player.Player() player.rect.x = 10 player.rect.y = 230 all_sprites_list.add(player) # set the window title pygame.display.set_caption("Scroller") # the following code sets up the main program loop # Boolean Variable to loop until the user clicks the close button. done = False # loop control # used to manage how fast the screen updates clock = pygame.time.Clock() # controls how fast game runs # Main Program Loop while done == False: # ALL EVENT PROCESSING (input) SHOULD GO BELOW THIS COMMENT for event in pygame.event.get(): # user did something if event.type == pygame.QUIT: #If user clicked close done = True # flag that we are done so we exit this loop if event.type == pygame.KEYDOWN: if event.key == pygame.K_LEFT: player.changespeed_x(-6) if event.key == pygame.K_RIGHT: player.changespeed_x(6) if event.key == pygame.K_UP: player.jump(land_list) if event.key == pygame.K_DOWN: player.changespeed_y(6) if event.type == pygame.KEYUP: if event.key == pygame.K_LEFT: player.changespeed_x(-0) if event.key == pygame.K_RIGHT: player.changespeed_x(0) monster.update() player.update(land_list,break_list,enemy_list) player.calc_grav() # ALL EVENT PROCESSING (input) SHOULD GO ABOVE THIS COMMENT # ALL GAME LOGIC (process) SHOULD GO BELOW THIS COMMENT if player.rect.x >= 500: diff = player.rect.x - 500 player.rect.x=500 for ground in land_list: ground.rect.x -= diff for brick in break_list: brick.rect.x -= diff for monster in enemy_list: monster.rect.x -= diff if player.rect.x <= 15: diff = 15 - player.rect.x player.rect.x = 15 for ground in land_list: ground.rect.x += diff for brick in break_list: brick.rect.x += diff for monster in enemy_list: monster.rect.x += diff # ALL GAME LOGIC (process) SHOULD GO ABOVE THIS COMMENT # ALL CODE TO DRAW (output) SHOULD GO BELOW THIS COMMENT # First, clear the screen. Don't put other drawing commands # above this, or they will be erased with this command. screen.fill(blue) screen.blit(cloud,[200,0]) cloud.set_colorkey(black) all_sprites_list.draw(screen) # ALL CODE TO DRAW (output) SHOULD GO ABOVE THIS COMMENT # This will update the screen with what's been drawn. pygame.display.flip() # limit to 30frames per second clock.tick(30) pygame.quit()
Your enemy class should be like this: class Enemy(pygame.sprite.Sprite): def __init__(self,image_file): pygame.sprite.Sprite.__init__(self) self.image = pygame.image.load(image_file) self.image = self.image.convert() self.image.set_colorkey((0,0,0)) self.rect = self.image.get_rect() self.vel = -2 def update(self,ground): self.rect.x += self.vel Then in your update loop, implement this pseudocode: ... if monster collides with ground: monster.vel *= -1 ...
PyGame get sprite group
hey guys, was trying to build pacman using pygame, have a small problem. When the pacman is moving if i press a key then it changes direction, unfortunately if there is a wall above then the pacman stops at that place and points upwards until i change the direction. I want help with how to find out if the block 3 or 4 units of pacman.rect.y belongs to sprite group level which has all the walls and stuff ..
Here's a longer example of a working game with walls: # Sample Python/Pygame Programs # Simpson College Computer Science # http://cs.simpson.edu/?q=python_pygame_examples import pygame black = (0,0,0) white = (255,255,255) blue = (0,0,255) # This class represents the bar at the bottom that the player controls class Wall(pygame.sprite.Sprite): # Constructor function def __init__(self,x,y,width,height): # Call the parent's constructor pygame.sprite.Sprite.__init__(self) # Make a blue wall, of the size specified in the parameters self.image = pygame.Surface([width, height]) self.image.fill(blue) # Make our top-left corner the passed-in location. self.rect = self.image.get_rect() self.rect.top = y self.rect.left = x # This class represents the bar at the bottom that the player controls class Player(pygame.sprite.Sprite): # Set speed vector change_x=0 change_y=0 # Constructor function def __init__(self,x,y): # Call the parent's constructor pygame.sprite.Sprite.__init__(self) # Set height, width self.image = pygame.Surface([15, 15]) self.image.fill(white) # Make our top-left corner the passed-in location. self.rect = self.image.get_rect() self.rect.top = y self.rect.left = x # Change the speed of the player def changespeed(self,x,y): self.change_x+=x self.change_y+=y # Find a new position for the player def update(self,walls): # Get the old position, in case we need to go back to it old_x=self.rect.left new_x=old_x+self.change_x self.rect.left = new_x # Did this update cause us to hit a wall? collide = pygame.sprite.spritecollide(self, walls, False) if collide: # Whoops, hit a wall. Go back to the old position self.rect.left=old_x old_y=self.rect.top new_y=old_y+self.change_y self.rect.top = new_y # Did this update cause us to hit a wall? collide = pygame.sprite.spritecollide(self, walls, False) if collide: # Whoops, hit a wall. Go back to the old position self.rect.top=old_y score = 0 # Call this function so the Pygame library can initialize itself pygame.init() # Create an 800x600 sized screen screen = pygame.display.set_mode([800, 600]) # Set the title of the window pygame.display.set_caption('Test') # Create a surface we can draw on background = pygame.Surface(screen.get_size()) # Used for converting color maps and such background = background.convert() # Fill the screen with a black background background.fill(black) # Create the player paddle object player = Player( 50,50 ) movingsprites = pygame.sprite.RenderPlain() movingsprites.add(player) # Make the walls. (x_pos, y_pos, width, height) wall_list=pygame.sprite.RenderPlain() wall=Wall(0,0,10,600) wall_list.add(wall) wall=Wall(10,0,790,10) wall_list.add(wall) wall=Wall(10,200,100,10) wall_list.add(wall) clock = pygame.time.Clock() done = False while done == False: for event in pygame.event.get(): if event.type == pygame.QUIT: done=True if event.type == pygame.KEYDOWN: if event.key == pygame.K_LEFT: player.changespeed(-3,0) if event.key == pygame.K_RIGHT: player.changespeed(3,0) if event.key == pygame.K_UP: player.changespeed(0,-3) if event.key == pygame.K_DOWN: player.changespeed(0,3) if event.type == pygame.KEYUP: if event.key == pygame.K_LEFT: player.changespeed(3,0) if event.key == pygame.K_RIGHT: player.changespeed(-3,0) if event.key == pygame.K_UP: player.changespeed(0,3) if event.key == pygame.K_DOWN: player.changespeed(0,-3) player.update(wall_list) screen.fill(black) movingsprites.draw(screen) wall_list.draw(screen) pygame.display.flip() clock.tick(40) pygame.quit()
You could use: http://www.pygame.org/docs/ref/sprite.html#pygame.sprite.spritecollide pacman.rect.y = pacman.rect.y - 3 colliding = pygame.sprite.spritecollide(pacman, level) if colliding: can_move_upwards = False else: can_move_upwards = True pacman.rect.y = pacman.rect.y + 3 And do the same for every direction you want to test.