I'm very new to python and pygame and I was trying to make a top-down shooter style game. I managed to get many components working but I cant get the blocks that I shoot at to show up in the rooms I created in the game. I moved the code for it to the game function and it shows up on screen but when you move between rooms they stay the same, for the time being I commented that part out. I want each room to have their own blocks that I can shoot, but when I try putting the code into each room class it does not show up on the screen. I'm pretty sure nothing is drawn over it. I want to know why the walls are being drawn but not the blocks. Any help is appreciated.
import pygame, sys, math, random
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
BLUE = (0, 0, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
PURPLE = (255, 0, 255)
click = False
# Call this function so the Pygame library can initialize itself
pygame.init()
# Create an 800x600 sized screen
WIDTH = 800
HEIGHT = 600
screen = pygame.display.set_mode([WIDTH, HEIGHT])
# Set the title of the window
pygame.display.set_caption('Maze Runner')
class Wall(pygame.sprite.Sprite):
def __init__(self, x, y, width, height, color):
# 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(color)
# Make our top-left corner the passed-in location.
self.rect = self.image.get_rect()
self.rect.y = y
self.rect.x = x
class Block(pygame.sprite.Sprite):
def __init__(self, color):
# Call the parent class (Sprite) constructor
super().__init__()
self.image = pygame.Surface([20, 20])
self.image.fill(color)
self.rect = self.image.get_rect()
class Player(pygame.sprite.Sprite):
# Set speed vector
change_x = 0
change_y = 0
def __init__(self, x, y):
# Call the parent's constructor
super().__init__()
# 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.y = y
self.rect.x = x
def changespeed(self, x, y):
self.change_x += x
self.change_y += y
def move(self, walls):
# 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, 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, 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 Bullet(pygame.sprite.Sprite):
def __init__(self, start_x, start_y, dest_x, dest_y):
# Call the parent class (Sprite) constructor
super().__init__()
# Set up the image for the bullet
self.image = pygame.Surface([5, 5])
self.image.fill(BLUE)
self.rect = self.image.get_rect()
# Move the bullet to our starting location
self.rect.x = start_x
self.rect.y = start_y
# Because rect.x and rect.y are automatically converted
# to integers, we need to create different variables that
# store the location as floating point numbers. Integers
# are not accurate enough for aiming.
self.floating_point_x = start_x
self.floating_point_y = start_y
# Calculation the angle in radians between the start points
# and end points. This is the angle the bullet will travel.
x_diff = dest_x - start_x
y_diff = dest_y - start_y
angle = math.atan2(y_diff, x_diff);
# Taking into account the angle, calculate our change_x
# and change_y. Velocity is how fast the bullet travels.
velocity = 5
self.change_x = math.cos(angle) * velocity
self.change_y = math.sin(angle) * velocity
def update(self):
""" Move the bullet. """
# The floating point x and y hold our more accurate location.
self.floating_point_y += self.change_y
self.floating_point_x += self.change_x
# The rect.x and rect.y are converted to integers.
self.rect.y = int(self.floating_point_y)
self.rect.x = int(self.floating_point_x)
# If the bullet flies of the screen, get rid of it.
if self.rect.x < 0 or self.rect.x > WIDTH or self.rect.y < 0 or self.rect.y > HEIGHT:
self.kill()
class Room(object):
# Each room has a list of walls, and of enemy sprites.
wall_list = None
enemy_sprites = None
block_list = None
def __init__(self):
""" Constructor, create our lists. """
self.wall_list = pygame.sprite.Group()
self.enemy_sprites = pygame.sprite.Group()
self.block_list = pygame.sprite.Group()
self.movingsprites = pygame.sprite.Group()
class Room1(Room):
def __init__(self):
super().__init__()
# Make the walls. (x_pos, y_pos, width, height)
# This is a list of walls. Each is in the form [x, y, width, height]
walls = [[0, 0, 20, 250, WHITE],
[0, 350, 20, 250, WHITE],
[780, 0, 20, 250, WHITE],
[780, 350, 20, 250, WHITE],
[20, 0, 760, 20, WHITE],
[20, 580, 760, 20, WHITE],
[390, 50, 20, 500, BLUE]
]
# Loop through the list. Create the wall, add it to the list
for item in walls:
wall = Wall(item[0], item[1], item[2], item[3], item[4])
self.wall_list.add(wall)
for i in range(10):
# This represents a block
block = Block(GREEN)
# Set a random location for the block
block.rect.x = random.randrange(WIDTH - 50)
block.rect.y = random.randrange(HEIGHT - 50)
# Add the block to the list of objects
self.block_list.add(block)
self.movingsprites.add(block)
class Room2(Room):
def __init__(self):
super().__init__()
walls = [[0, 0, 20, 250, RED],
[0, 350, 20, 250, RED],
[780, 0, 20, 250, RED],
[780, 350, 20, 250, RED],
[20, 0, 760, 20, RED],
[20, 580, 760, 20, RED],
[190, 50, 20, 500, GREEN],
[590, 50, 20, 500, GREEN]
]
for item in walls:
wall = Wall(item[0], item[1], item[2], item[3], item[4])
self.wall_list.add(wall)
block = Block(RED)
block.rect.x = 200
block.rect.y = 200
self.block_list.add(block)
self.movingsprites.add(block)
class Room3(Room):
def __init__(self):
super().__init__()
walls = [[0, 0, 20, 250, PURPLE],
[0, 350, 20, 250, PURPLE],
[780, 0, 20, 250, PURPLE],
[780, 350, 20, 250, PURPLE],
[20, 0, 760, 20, PURPLE],
[20, 580, 760, 20, PURPLE]
]
for item in walls:
wall = Wall(item[0], item[1], item[2], item[3], item[4])
self.wall_list.add(wall)
for x in range(100, 800, 100):
for y in range(50, 451, 300):
wall = Wall(x, y, 20, 200, RED)
self.wall_list.add(wall)
for x in range(150, 700, 100):
wall = Wall(x, 200, 20, 200, WHITE)
self.wall_list.add(wall)
def draw_text(text, font, color, surface, x, y):
textobj = font.render(text, 1, color)
textrect = textobj.get_rect()
textrect.topleft = (x, y)
surface.blit(textobj, textrect)
def main_menu():
done = False
while not done:
font = pygame.font.SysFont('Calibri', 20, True, False)
clock = pygame.time.Clock()
screen.fill(BLACK)
draw_text('main menu', font, WHITE, screen, 20, 20)
mx, my = pygame.mouse.get_pos()
button_1 = pygame.Rect(50, 100, 200, 50)
if button_1.collidepoint((mx, my)):
if click:
game()
pygame.draw.rect(screen, RED, button_1)
draw_text('Play', font, WHITE, screen, 60, 110)
click = False
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
pygame.quit()
sys.exit()
done = True
if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
click = True
pygame.display.flip()
clock.tick(60)
pygame.quit()
def game():
# Create the player paddle object
player = Player(50, 50)
movingsprites = pygame.sprite.Group()
movingsprites.add(player)
bullet_list = pygame.sprite.Group()
walls = pygame.sprite.Group()
wall_list = pygame.sprite.Group()
block_list = pygame.sprite.Group()
#for i in range(10):
## This represents a block
#block = Block(GREEN)
## Set a random location for the block
#block.rect.x = random.randrange(WIDTH - 50)
#block.rect.y = random.randrange(HEIGHT - 50)
## Add the block to the list of objects
#block_list.add(block)
#movingsprites.add(block)
rooms = []
room = Room1()
rooms.append(room)
room = Room2()
rooms.append(room)
room = Room3()
rooms.append(room)
current_room_no = 0
current_room = rooms[current_room_no]
clock = pygame.time.Clock()
done = False
while not done:
# --- Event Processing ---
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(-5, 0)
if event.key == pygame.K_RIGHT:
player.changespeed(5, 0)
if event.key == pygame.K_UP:
player.changespeed(0, -5)
if event.key == pygame.K_DOWN:
player.changespeed(0, 5)
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
pygame.quit()
sys.exit()
done = True
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
player.changespeed(5, 0)
if event.key == pygame.K_RIGHT:
player.changespeed(-5, 0)
if event.key == pygame.K_UP:
player.changespeed(0, 5)
if event.key == pygame.K_DOWN:
player.changespeed(0, -5)
if event.type == pygame.MOUSEBUTTONDOWN:
# Fire a bullet if the user clicks the mouse button
# Get the mouse position
pos = pygame.mouse.get_pos()
mouse_x = pos[0]
mouse_y = pos[1]
# Create the bullet based on where we are, and where we want to go.
bullet = Bullet(player.rect.x, player.rect.y, mouse_x, mouse_y)
# Add the bullet to the lists
movingsprites.add(bullet)
bullet_list.add(bullet)
# --- Game Logic ---
player.move(current_room.wall_list)
movingsprites.update()
if player.rect.x < -15:
if current_room_no == 0:
current_room_no = 2
current_room = rooms[current_room_no]
player.rect.x = 790
elif current_room_no == 2:
current_room_no = 1
current_room = rooms[current_room_no]
player.rect.x = 790
else:
current_room_no = 0
current_room = rooms[current_room_no]
player.rect.x = 790
if player.rect.x > WIDTH + 1:
if current_room_no == 0:
current_room_no = 1
current_room = rooms[current_room_no]
player.rect.x = 0
elif current_room_no == 1:
current_room_no = 2
current_room = rooms[current_room_no]
player.rect.x = 0
else:
current_room_no = 0
current_room = rooms[current_room_no]
player.rect.x = 0
for bullet in bullet_list:
# See if it hit a block
block_hit_list = pygame.sprite.spritecollide(bullet, block_list, True)
# For each block hit, remove the bullet and add to the score
for block in block_hit_list:
bullet_list.remove(bullet)
movingsprites.remove(bullet)
# Remove the bullet if it flies up off the screen
if bullet.rect.y < -10:
bullet_list.remove(bullet)
movingsprites.remove(bullet)
# --- Drawing ---
screen.fill(BLACK)
block_list.draw(screen)
movingsprites.draw(screen)
current_room.wall_list.draw(screen)
pygame.display.flip()
clock.tick(60)
pygame.quit()
if __name__ == "__main__":
main_menu()
Sorry about the long code, this is my first time asking a question here. Once again any help is appreciated.
You need to make the blocks list a property of the room class, and then draw them in draw. Notice how in draw, I call
current_room.block_list.draw(screen)
So is this what you mean:
import pygame, sys, math, random
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
BLUE = (0, 0, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
PURPLE = (255, 0, 255)
click = False
# Call this function so the Pygame library can initialize itself
pygame.init()
# Create an 800x600 sized screen
WIDTH = 800
HEIGHT = 600
screen = pygame.display.set_mode([WIDTH, HEIGHT])
# Set the title of the window
pygame.display.set_caption('Maze Runner')
class Wall(pygame.sprite.Sprite):
def __init__(self, x, y, width, height, color):
# 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(color)
# Make our top-left corner the passed-in location.
self.rect = self.image.get_rect()
self.rect.y = y
self.rect.x = x
class Block(pygame.sprite.Sprite):
def __init__(self, color):
# Call the parent class (Sprite) constructor
super().__init__()
self.image = pygame.Surface([20, 20])
self.image.fill(color)
self.rect = self.image.get_rect()
class Player(pygame.sprite.Sprite):
# Set speed vector
change_x = 0
change_y = 0
def __init__(self, x, y):
# Call the parent's constructor
super().__init__()
# 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.y = y
self.rect.x = x
def changespeed(self, x, y):
self.change_x += x
self.change_y += y
def move(self, walls):
# 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, 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, 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 Bullet(pygame.sprite.Sprite):
def __init__(self, start_x, start_y, dest_x, dest_y):
# Call the parent class (Sprite) constructor
super().__init__()
# Set up the image for the bullet
self.image = pygame.Surface([5, 5])
self.image.fill(BLUE)
self.rect = self.image.get_rect()
# Move the bullet to our starting location
self.rect.x = start_x
self.rect.y = start_y
# Because rect.x and rect.y are automatically converted
# to integers, we need to create different variables that
# store the location as floating point numbers. Integers
# are not accurate enough for aiming.
self.floating_point_x = start_x
self.floating_point_y = start_y
# Calculation the angle in radians between the start points
# and end points. This is the angle the bullet will travel.
x_diff = dest_x - start_x
y_diff = dest_y - start_y
angle = math.atan2(y_diff, x_diff);
# Taking into account the angle, calculate our change_x
# and change_y. Velocity is how fast the bullet travels.
velocity = 5
self.change_x = math.cos(angle) * velocity
self.change_y = math.sin(angle) * velocity
def update(self):
""" Move the bullet. """
# The floating point x and y hold our more accurate location.
self.floating_point_y += self.change_y
self.floating_point_x += self.change_x
# The rect.x and rect.y are converted to integers.
self.rect.y = int(self.floating_point_y)
self.rect.x = int(self.floating_point_x)
# If the bullet flies of the screen, get rid of it.
if self.rect.x < 0 or self.rect.x > WIDTH or self.rect.y < 0 or self.rect.y > HEIGHT:
self.kill()
class Room(object):
# Each room has a list of walls, and of enemy sprites.
wall_list = None
enemy_sprites = None
block_list = None
def __init__(self):
""" Constructor, create our lists. """
self.wall_list = pygame.sprite.Group()
self.enemy_sprites = pygame.sprite.Group()
self.block_list = pygame.sprite.Group()
self.movingsprites = pygame.sprite.Group()
for i in range(10):
# This represents a block
block = Block(GREEN)
# Set a random location for the block
block.rect.x = random.randrange(WIDTH - 50)
block.rect.y = random.randrange(HEIGHT - 50)
# Add the block to the list of objects
self.block_list.add(block)
self.movingsprites.add(block)
class Room1(Room):
def __init__(self):
super().__init__()
# Make the walls. (x_pos, y_pos, width, height)
# This is a list of walls. Each is in the form [x, y, width, height]
walls = [[0, 0, 20, 250, WHITE],
[0, 350, 20, 250, WHITE],
[780, 0, 20, 250, WHITE],
[780, 350, 20, 250, WHITE],
[20, 0, 760, 20, WHITE],
[20, 580, 760, 20, WHITE],
[390, 50, 20, 500, BLUE]
]
# Loop through the list. Create the wall, add it to the list
for item in walls:
wall = Wall(item[0], item[1], item[2], item[3], item[4])
self.wall_list.add(wall)
for i in range(10):
# This represents a block
block = Block(GREEN)
# Set a random location for the block
block.rect.x = random.randrange(WIDTH - 50)
block.rect.y = random.randrange(HEIGHT - 50)
# Add the block to the list of objects
self.block_list.add(block)
self.movingsprites.add(block)
class Room2(Room):
def __init__(self):
super().__init__()
walls = [[0, 0, 20, 250, RED],
[0, 350, 20, 250, RED],
[780, 0, 20, 250, RED],
[780, 350, 20, 250, RED],
[20, 0, 760, 20, RED],
[20, 580, 760, 20, RED],
[190, 50, 20, 500, GREEN],
[590, 50, 20, 500, GREEN]
]
for item in walls:
wall = Wall(item[0], item[1], item[2], item[3], item[4])
self.wall_list.add(wall)
block = Block(RED)
block.rect.x = 200
block.rect.y = 200
self.block_list.add(block)
self.movingsprites.add(block)
class Room3(Room):
def __init__(self):
super().__init__()
walls = [[0, 0, 20, 250, PURPLE],
[0, 350, 20, 250, PURPLE],
[780, 0, 20, 250, PURPLE],
[780, 350, 20, 250, PURPLE],
[20, 0, 760, 20, PURPLE],
[20, 580, 760, 20, PURPLE]
]
for item in walls:
wall = Wall(item[0], item[1], item[2], item[3], item[4])
self.wall_list.add(wall)
for x in range(100, 800, 100):
for y in range(50, 451, 300):
wall = Wall(x, y, 20, 200, RED)
self.wall_list.add(wall)
for x in range(150, 700, 100):
wall = Wall(x, 200, 20, 200, WHITE)
self.wall_list.add(wall)
def draw_text(text, font, color, surface, x, y):
textobj = font.render(text, 1, color)
textrect = textobj.get_rect()
textrect.topleft = (x, y)
surface.blit(textobj, textrect)
def main_menu():
done = False
while not done:
font = pygame.font.SysFont('Calibri', 20, True, False)
clock = pygame.time.Clock()
screen.fill(BLACK)
draw_text('main menu', font, WHITE, screen, 20, 20)
mx, my = pygame.mouse.get_pos()
button_1 = pygame.Rect(50, 100, 200, 50)
if button_1.collidepoint((mx, my)):
if click:
game()
pygame.draw.rect(screen, RED, button_1)
draw_text('Play', font, WHITE, screen, 60, 110)
click = False
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
pygame.quit()
sys.exit()
done = True
if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
click = True
pygame.display.flip()
clock.tick(60)
pygame.quit()
def game():
# Create the player paddle object
player = Player(50, 50)
movingsprites = pygame.sprite.Group()
movingsprites.add(player)
bullet_list = pygame.sprite.Group()
walls = pygame.sprite.Group()
wall_list = pygame.sprite.Group()
block_list = pygame.sprite.Group()
rooms = []
room = Room1()
rooms.append(room)
room = Room2()
rooms.append(room)
room = Room3()
rooms.append(room)
current_room_no = 0
current_room = rooms[current_room_no]
clock = pygame.time.Clock()
done = False
while not done:
# --- Event Processing ---
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(-5, 0)
if event.key == pygame.K_RIGHT:
player.changespeed(5, 0)
if event.key == pygame.K_UP:
player.changespeed(0, -5)
if event.key == pygame.K_DOWN:
player.changespeed(0, 5)
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
pygame.quit()
sys.exit()
done = True
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
player.changespeed(5, 0)
if event.key == pygame.K_RIGHT:
player.changespeed(-5, 0)
if event.key == pygame.K_UP:
player.changespeed(0, 5)
if event.key == pygame.K_DOWN:
player.changespeed(0, -5)
if event.type == pygame.MOUSEBUTTONDOWN:
# Fire a bullet if the user clicks the mouse button
# Get the mouse position
pos = pygame.mouse.get_pos()
mouse_x = pos[0]
mouse_y = pos[1]
# Create the bullet based on where we are, and where we want to go.
bullet = Bullet(player.rect.x, player.rect.y, mouse_x, mouse_y)
# Add the bullet to the lists
movingsprites.add(bullet)
bullet_list.add(bullet)
# --- Game Logic ---
player.move(current_room.wall_list)
movingsprites.update()
if player.rect.x < -15:
if current_room_no == 0:
current_room_no = 2
current_room = rooms[current_room_no]
player.rect.x = 790
elif current_room_no == 2:
current_room_no = 1
current_room = rooms[current_room_no]
player.rect.x = 790
else:
current_room_no = 0
current_room = rooms[current_room_no]
player.rect.x = 790
if player.rect.x > WIDTH + 1:
if current_room_no == 0:
current_room_no = 1
current_room = rooms[current_room_no]
player.rect.x = 0
elif current_room_no == 1:
current_room_no = 2
current_room = rooms[current_room_no]
player.rect.x = 0
else:
current_room_no = 0
current_room = rooms[current_room_no]
player.rect.x = 0
for bullet in bullet_list:
# See if it hit a block
block_hit_list = pygame.sprite.spritecollide(bullet, block_list, True)
# For each block hit, remove the bullet and add to the score
for block in block_hit_list:
bullet_list.remove(bullet)
movingsprites.remove(bullet)
# Remove the bullet if it flies up off the screen
if bullet.rect.y < -10:
bullet_list.remove(bullet)
movingsprites.remove(bullet)
# --- Drawing ---
screen.fill(BLACK)
current_room.block_list.draw(screen)
movingsprites.draw(screen)
current_room.wall_list.draw(screen)
pygame.display.flip()
clock.tick(60)
pygame.quit()
if __name__ == "__main__":
main_menu()
Also, if you change the collision detection to this:
for bullet in bullet_list:
# See if it hit a block
block_hit_list = pygame.sprite.spritecollide(bullet, current_room.block_list, True)
It will detect bullet hits against the rooms blocks
For some reason the Colliderect won't work and the rain passes through pavement. This is really annoying because all of those unused sprites create tons of lag.
import pygame
import random
class Square(pygame.sprite.Sprite):
def __init__(self, x, y, size1, size2, speedx, speedy, colour):
super().__init__()
self.image = pygame.Surface([size1, size2])
self.image.fill(colour)
self.speedx = speedx
self.speedy = speedy
self.rect=self.image.get_rect()
self.rect.x=x
self.rect.y=y
def update(self):
square_colour = (random.randint(0,255), random.randint(0,255), random.randint(0,255))
self.rect.x = self.rect.x + self.speedx
self.rect.y = self.rect.y + self.speedy
my_square = Square(0, 705, 20, 30, 1, 0, (0, 0, 0))
pavement = Square(0, 735, 750, 15, 0 , 0, (100, 100, 100))
allspriteslist = pygame.sprite.Group()
allspriteslist.add(my_square)
allspriteslist.add(pavement)
pygame.init()
screen = pygame.display.set_mode([750,750])
pygame.display.set_caption('Snake Example')
clock = pygame.time.Clock()
background_colour = (150, 150, 150)
done = False
while not done:
r = Square(random.randint(0, 747), 0, 3, 7, 0, 5, (137, 200, 230))
allspriteslist.add(r)
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_q:
done = True
if my_square.rect.x > 750:
my_square.rect.x = - 10
if my_square.rect.x < - 50:
my_square.rect.x = 800
if r.rect.colliderect(pavement.rect):
allspriteslist.remove(r)
screen.fill(background_colour)
allspriteslist.draw(screen)
allspriteslist.update()
pygame.display.flip()
You have to detect the collision of all the raindrops with the pavement.
Add a group for the raindrops:
rain = pygame.sprite.Group()
Add each rain drop to the group:
done = False
while not done:
r = Square(random.randint(0, 747), 0, 3, 7, 0, 5, (137, 200, 230))
allspriteslist.add(r)
rain.add(r)
And remove a drop if it hits the ground, by pygame.sprite.Sprite.kill():
done = False
while not done:
# [...]
for r in rain:
if r.rect.colliderect(pavement.rect):
r.kill()
Removing the rain drops can be simplified by using pygame.sprite.spritecollide() and passing True to the argument dokill:
done = False
while not done:
# [...]
pygame.sprite.spritecollide(pavement, rain, True)
Complete example code:
import pygame
import random
class Square(pygame.sprite.Sprite):
def __init__(self, x, y, size1, size2, speedx, speedy, colour):
super().__init__()
self.image = pygame.Surface([size1, size2])
self.image.fill(colour)
self.speedx = speedx
self.speedy = speedy
self.rect=self.image.get_rect()
self.rect.x=x
self.rect.y=y
def update(self):
square_colour = (random.randint(0,255), random.randint(0,255), random.randint(0,255))
self.rect.x = self.rect.x + self.speedx
self.rect.y = self.rect.y + self.speedy
my_square = Square(0, 705, 20, 30, 1, 0, (0, 0, 0))
pavement = Square(0, 735, 750, 15, 0 , 0, (100, 100, 100))
allspriteslist = pygame.sprite.Group()
allspriteslist.add(my_square)
allspriteslist.add(pavement)
rain = pygame.sprite.Group()
pygame.init()
screen = pygame.display.set_mode([750,750])
pygame.display.set_caption('Snake Example')
clock = pygame.time.Clock()
background_colour = (150, 150, 150)
done = False
while not done:
r = Square(random.randint(0, 747), 0, 3, 7, 0, 5, (137, 200, 230))
allspriteslist.add(r)
rain.add(r)
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_q:
done = True
if my_square.rect.x > 750:
my_square.rect.x = - 10
if my_square.rect.x < - 50:
my_square.rect.x = 800
pygame.sprite.spritecollide(pavement, rain, True)
screen.fill(background_colour)
allspriteslist.draw(screen)
allspriteslist.update()
pygame.display.flip()
For some reason the Colliderect won't work and the rain passes through pavement. This is really annoying because all of those unused sprites create tons of lag.
import pygame
import random
class Square(pygame.sprite.Sprite):
def __init__(self, x, y, size1, size2, speedx, speedy, colour):
super().__init__()
self.image = pygame.Surface([size1, size2])
self.image.fill(colour)
self.speedx = speedx
self.speedy = speedy
self.rect=self.image.get_rect()
self.rect.x=x
self.rect.y=y
def update(self):
square_colour = (random.randint(0,255), random.randint(0,255), random.randint(0,255))
self.rect.x = self.rect.x + self.speedx
self.rect.y = self.rect.y + self.speedy
my_square = Square(0, 705, 20, 30, 1, 0, (0, 0, 0))
pavement = Square(0, 735, 750, 15, 0 , 0, (100, 100, 100))
allspriteslist = pygame.sprite.Group()
allspriteslist.add(my_square)
allspriteslist.add(pavement)
pygame.init()
screen = pygame.display.set_mode([750,750])
pygame.display.set_caption('Snake Example')
clock = pygame.time.Clock()
background_colour = (150, 150, 150)
done = False
while not done:
r = Square(random.randint(0, 747), 0, 3, 7, 0, 5, (137, 200, 230))
allspriteslist.add(r)
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_q:
done = True
if my_square.rect.x > 750:
my_square.rect.x = - 10
if my_square.rect.x < - 50:
my_square.rect.x = 800
if r.rect.colliderect(pavement.rect):
allspriteslist.remove(r)
screen.fill(background_colour)
allspriteslist.draw(screen)
allspriteslist.update()
pygame.display.flip()
You have to detect the collision of all the raindrops with the pavement.
Add a group for the raindrops:
rain = pygame.sprite.Group()
Add each rain drop to the group:
done = False
while not done:
r = Square(random.randint(0, 747), 0, 3, 7, 0, 5, (137, 200, 230))
allspriteslist.add(r)
rain.add(r)
And remove a drop if it hits the ground, by pygame.sprite.Sprite.kill():
done = False
while not done:
# [...]
for r in rain:
if r.rect.colliderect(pavement.rect):
r.kill()
Removing the rain drops can be simplified by using pygame.sprite.spritecollide() and passing True to the argument dokill:
done = False
while not done:
# [...]
pygame.sprite.spritecollide(pavement, rain, True)
Complete example code:
import pygame
import random
class Square(pygame.sprite.Sprite):
def __init__(self, x, y, size1, size2, speedx, speedy, colour):
super().__init__()
self.image = pygame.Surface([size1, size2])
self.image.fill(colour)
self.speedx = speedx
self.speedy = speedy
self.rect=self.image.get_rect()
self.rect.x=x
self.rect.y=y
def update(self):
square_colour = (random.randint(0,255), random.randint(0,255), random.randint(0,255))
self.rect.x = self.rect.x + self.speedx
self.rect.y = self.rect.y + self.speedy
my_square = Square(0, 705, 20, 30, 1, 0, (0, 0, 0))
pavement = Square(0, 735, 750, 15, 0 , 0, (100, 100, 100))
allspriteslist = pygame.sprite.Group()
allspriteslist.add(my_square)
allspriteslist.add(pavement)
rain = pygame.sprite.Group()
pygame.init()
screen = pygame.display.set_mode([750,750])
pygame.display.set_caption('Snake Example')
clock = pygame.time.Clock()
background_colour = (150, 150, 150)
done = False
while not done:
r = Square(random.randint(0, 747), 0, 3, 7, 0, 5, (137, 200, 230))
allspriteslist.add(r)
rain.add(r)
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_q:
done = True
if my_square.rect.x > 750:
my_square.rect.x = - 10
if my_square.rect.x < - 50:
my_square.rect.x = 800
pygame.sprite.spritecollide(pavement, rain, True)
screen.fill(background_colour)
allspriteslist.draw(screen)
allspriteslist.update()
pygame.display.flip()
I have recently learned python and have a school project involving pygame, but we weren't taught much, anyways I have been trying to make a maze in which the player (the white square), collides with the red block (the endpoint) something happens (a task takes place as a result of the collision), but I have tried various things but nothing seems to be working (I am still VERY new to pygame). Well, thanks for any help, but bear in mind that i am a beginner an that there are probably many mistakes in my code
import pygame
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
BLUE = (50, 50, 255)
GREEN = (33,206,14)
RED = (255,0,0)
GREY = (43,44,61)
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
class Player(pygame.sprite.Sprite):
def __init__(self, x, y):
# Call the parent's constructor
super().__init__()
#self.image = pygame.image.load("basketballsprite.png").convert()
#self.image.set_colorkey(WHITE)
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.y = y
self.rect.x = x
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):
self.rect.x += self.change_x
block_hit_list = pygame.sprite.spritecollide(self, self.walls, False)
for block in block_hit_list:
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
self.rect.y += self.change_y
block_hit_list = pygame.sprite.spritecollide(self, self.walls, False)
for block in block_hit_list:
if self.change_y > 0:
self.rect.bottom = block.rect.top
else:
self.rect.top = block.rect.bottom
#if pygame.sprite.spritecollide(Endpoint, self.image,True):
class Wall(pygame.sprite.Sprite):
def __init__(self, x, y, width, height):
super().__init__()
self.image = pygame.Surface([width, height])
self.image.fill(GREY)
self.rect = self.image.get_rect()
self.rect.y = y
self.rect.x = x
class Endpoint(pygame.sprite.Sprite):
def __init__(self, x, y, width, height):
super().__init__()
self.image = pygame.Surface([width, height])
self.image.fill(RED)
self.rect = self.image.get_rect()
self.rect.y = y
self.rect.x = x
pygame.init()
screen = pygame.display.set_mode([SCREEN_WIDTH, SCREEN_HEIGHT])
pygame.display.set_caption('A "Little" Maze Game...')
all_sprite_list = pygame.sprite.Group()
wall_list = pygame.sprite.Group()
Endpoint_list = pygame.sprite.Group()
wall = Wall(0, 0, 10, 600)
wall_list.add(wall)
all_sprite_list.add(wall)
wall = Wall(0, 590, 400, 10)
wall_list.add(wall)
all_sprite_list.add(wall)
wall = Wall(450, 590, 390, 10)
wall_list.add(wall)
all_sprite_list.add(wall)
wall = Wall(10, 0, 790, 10)
wall_list.add(wall)
all_sprite_list.add(wall)
wall = Wall(30, 200, 85, 10)
wall_list.add(wall)
all_sprite_list.add(wall)
wall = Wall(790, 0, 10, 800)
wall_list.add(wall)
all_sprite_list.add(wall)
wall = Wall(70, 0, 10, 80)
wall_list.add(wall)
all_sprite_list.add(wall)
wall = Wall(390, 500, 10, 150)
wall_list.add(wall)
all_sprite_list.add(wall)
wall = Wall(450, 500, 10, 150)
wall_list.add(wall)
all_sprite_list.add(wall)
wall = Wall(790, 0, 10, 800)
wall_list.add(wall)
all_sprite_list.add(wall)
wall = Wall(400, 600, 2000, 15)
wall_list.add(wall)
all_sprite_list.add(wall)
Endpoint = Endpoint(400, 590, 50, 15)
wall_list.add(wall)
all_sprite_list.add(Endpoint)
wall = Wall(35, 100, 50, 10)
wall_list.add(wall)
all_sprite_list.add(wall)
wall = Wall(100, 95, 10, 80)
wall_list.add(wall)
all_sprite_list.add(wall)
wall = Wall(100, 10, 10, 65)
wall_list.add(wall)
all_sprite_list.add(wall)
wall = Wall(130, 200, 10, 90)
wall_list.add(wall)
all_sprite_list.add(wall)
wall = Wall(130, 225, 90, 10)
wall_list.add(wall)
all_sprite_list.add(wall)
wall = Wall(50, 100, 10, 45)
wall_list.add(wall)
all_sprite_list.add(wall)
wall = Wall(10, 160, 40, 10)
wall_list.add(wall)
all_sprite_list.add(wall)
wall = Wall(300, 200, 10, 250)
wall_list.add(wall)
all_sprite_list.add(wall)
wall = Wall(240, 260, 60, 10)
wall_list.add(wall)
all_sprite_list.add(wall)
'''
wall = Wall(x, y, width, height)
wall_list.add(wall)
all_sprite_list.add(wall)
wall = Wall(x, y, width, height)
wall_list.add(wall)
all_sprite_list.add(wall)
wall = Wall(x, y, width, height)
wall_list.add(wall)
all_sprite_list.add(wall)
wall = Wall(x, y, width, height)
wall_list.add(wall)
all_sprite_list.add(wall)
wall = Wall(x, y, width, height)
wall_list.add(wall)
all_sprite_list.add(wall)
'''
player = Player(34, 34)
player.walls = wall_list
all_sprite_list.add(player)
clock = pygame.time.Clock()
done = False
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:
player.changespeed(-2, 0)
elif event.key == pygame.K_RIGHT:
player.changespeed(2, 0)
elif event.key == pygame.K_UP:
player.changespeed(0, -2)
elif event.key == pygame.K_DOWN:
player.changespeed(0, 2)
elif event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
player.changespeed(2, 0)
elif event.key == pygame.K_RIGHT:
player.changespeed(-2, 0)
elif event.key == pygame.K_UP:
player.changespeed(0, 2)
elif event.key == pygame.K_DOWN:
player.changespeed(0, -2)
screen.fill(BLACK)
if pygame.sprite.spritecollideany(player,Endpoint_list):
exit()
all_sprite_list.update()
pygame.draw.circle(screen, BLUE, [40, 40], 30)
all_sprite_list.draw(screen)
pygame.display.flip()
clock.tick(60)
pygame.quit()
You just need to add the Endpoint instance to the Endpoint_list which you use for the collision detection. Also, don't use the same name for the instance and the class, otherwise you're overriding the class and can't create new instances anymore.
endpoint = Endpoint(400, 590, 50, 15) # Just use a lowercase name for the instance.
all_sprite_list.add(endpoint)
Endpoint_list.add(endpoint)
Alternatively, you could use the pygame.sprite.collide_rect() function.
if pygame.sprite.collide_rect(player, endpoint):
print('exit reached')
Or just the colliderect method of the rects:
if player.rect.colliderect(endpoint):
This is the error:
Traceback (most recent call last):
File "C:/Users/Lucas/PycharmProjects/FirstPyGame/Main.py", line 117, in <module>
player.changespeed(3, 0)
File "C:/Users/Lucas/PycharmProjects/FirstPyGame/Main.py", line 42, in changespeed
self.change_x += x
AttributeError: 'Ship' object has no attribute 'change_x'
Here is my code:
import pygame
import random
pygame.init()
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 255, 255)
size = [800, 600]
x_coord = 400
y_coord = 600
x_speed = 0
y_speed = 0
font = pygame.font.SysFont("Calibri", 25, True, False)
snow_list = []
for i in range(50):
x = random.randrange(0, 800)
y = random.randrange(0, 600)
snow_list.append([x, y])
pygame.display.set_caption("Star Fighter")
screen = pygame.display.set_mode(size)
clock = pygame.time.Clock()
class Ship(pygame.sprite.Sprite):
def ___init__(self, x, y):
super().__init__()
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.change_x = 0
self.change_y = 0
def changespeed(self, x, y):
self.change_x += x
self.change_y += y
def update(self):
self.rect.x += self.change_x
self.rect.y += self.change_y
def DrawShip(screen, x, y):
a = pygame.draw.rect(screen, WHITE, ((x_coord - 5), (y_coord - 60), 10, 10))
b = pygame.draw.rect(screen, WHITE, ((x_coord - 15), (y_coord - 50), 10, 10))
c = pygame.draw.rect(screen, RED, ((x_coord - 5), (y_coord - 50), 10, 10))
d = pygame.draw.rect(screen, WHITE, ((x_coord + 5), (y_coord - 50), 10, 10))
class Block(pygame.sprite.Sprite):
def __init__(self, color):
super().__init__()
self.image = pygame.Surface([20, 15])
self.image.fill(color)
self.rect = self.image.get_rect()
def ScrollStars():
for i in range(len(snow_list)):
pygame.draw.circle(screen, WHITE, snow_list[i], 3)
snow_list[i][1] += 1
if snow_list[i][1] > 600:
y = random.randrange(-50, -10)
snow_list[i][1] = y
x = random.randrange(0, 800)
snow_list[i][0] = x
class Bullet(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.Surface([4, 10])
self.image.fill(WHITE)
self.rect = self.image.get_rect()
def update(self):
self.rect.y -= 3
all_sprites_list = pygame.sprite.Group()
block_list = pygame.sprite.Group()
bullet_list = pygame.sprite.Group()
for i in range(50):
# This represents a block
block = Block(BLUE)
# Set a random location for the block
block.rect.x = random.randrange(800)
block.rect.y = random.randrange(300)
# Add the block to the list of objects
block_list.add(block)
all_sprites_list.add(block)
score = 0
player = Ship()
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
player.changespeed(-3, 0)
elif event.key == pygame.K_RIGHT:
player.changespeed(3, 0)
elif event.key == pygame.K_SPACE:
bullet = Bullet()
bullet.rect.x = x_coord
bullet.rect.y = 550
all_sprites_list.add(bullet)
bullet_list.add(bullet)
elif event.key == pygame.K_q:
running = False
elif event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
player.changespeed(3, 0)
elif event.key == pygame.K_RIGHT:
player.changespeed(-3, 0)
if event.key == pygame.K_LEFT or pygame.K_RIGHT:
x_speed = 0
if event.type == pygame.K_UP or pygame.K_DOWN:
y_speed = 0
for bullet in bullet_list:
block_hit_list = pygame.sprite.spritecollide(bullet, block_list, True)
for block in block_hit_list:
bullet_list.remove(bullet)
all_sprites_list.remove(bullet)
score += 1
if bullet.rect.y < -10:
bullet_list.remove(bullet)
all_sprites_list.remove(bullet)
x_coord = x_coord + x_speed
y_coord = y_coord + y_speed
all_sprites_list.update()
screen.fill(BLACK)
all_sprites_list.draw(screen)
Ship.DrawShip(screen, x_coord, y_coord)
pygame.display.update()
clock.tick(70)
pygame.quit()
Could someone explain the error that I am having? I am a beginner and I do not understand it very well. It says that the Ship class has no attribute 'change_x' but it does, right? Sorry if this doesn't make any sense, but someone please help me with this. I would really appreciate it.
The issue is caused by a typo. The name of the constructor is __init__ rather than ___init__:
def ___init__(self, x, y):
def __init__(self, x, y):