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.

Categories

Resources