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
Related
This question already has answers here:
Pygame - Collisions With Floor/Walls
(2 answers)
Closed 2 months ago.
i am coding a little game and so on everything is working but there is a problem.
I have no clue how to code a collision detection between my player and the walls.
There must be a way how to check if the player collides with a wall when he goes the step before he does it.
Here is my code:
import pygame, sys, random
gameover = False
player_in_radius = False
key_picked = False
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
BLUE = (50, 50, 255)
GREY = (238,223,204)
class Player(pygame.sprite.Sprite):
def __init__(self, x, y, image):
super().__init__()
self.image = pygame.image.load(image)
self.rect = self.image.get_rect()
self.rect.y = y
self.rect.x = x
self.walls = None
class Wall(pygame.sprite.Sprite):
def __init__(self, x, y, width, height):
super().__init__()
# Make a blue wall, of the size specified in the parameters
self.image = pygame.Surface([width, height])
self.image.fill(BLACK)
# Make our top-left corner the passed-in location.
self.rect = self.image.get_rect()
self.rect.y = y
self.rect.x = x
pygame.init()
SCREEN_WIDTH = 1200
SCREEN_HEIGHT = 900
clock = pygame.time.Clock()
screen = pygame.display.set_mode([SCREEN_WIDTH, SCREEN_HEIGHT])
pygame.display.set_caption("EscapefromHoney / ETAGE 0")
all_sprite_list = pygame.sprite.Group()
wall_list = pygame.sprite.Group()
wall = Wall(0, 0, 10, 900)
wall_list.add(wall)
all_sprite_list.add(wall)
wall = Wall(1190, 0, 10, 900)
wall_list.add(wall)
all_sprite_list.add(wall)
wall = Wall(0, 890, 1200, 10)
wall_list.add(wall)
all_sprite_list.add(wall)
wall = Wall(10, 0, 1200, 10)
wall_list.add(wall)
all_sprite_list.add(wall)
wall = Wall(10, 200, 120, 10)
wall_list.add(wall)
all_sprite_list.add(wall)
player = Player(50, 50, "pictures\kian60x60.png")
player.walls = wall_list
all_sprite_list.add(player)
while 1:
if key_picked == False:
key = pygame.image.load("pictures\key.png")
keyrect = key.get_rect()
keyrect.top = 600
keyrect.left = 480
screen.blit(key, keyrect)
for event in pygame.event.get():
if event.type == pygame.QUIT: sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
pygame.quit()
sys.exit()
if event.key == pygame.K_DOWN:
player.rect.y = player.rect.y + 60
if event.key == pygame.K_UP:
player.rect.y = player.rect.y - 60
if event.key == pygame.K_RIGHT:
player.rect.x = player.rect.x + 60
if event.key == pygame.K_LEFT:
player.rect.x = player.rect.x - 60
all_sprite_list.update()
screen.fill(GREY)
all_sprite_list.draw(screen)
pygame.display.flip()
clock.tick(60)
pygame.quit()
I tried to use this code
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
but no chance. Still not working. And the other point I dont want the have the whole change thing in it with velocity. I want only steps like i did it in my code.
Your player and your wall are both rects :
Therefore you can simply use the .colliderect() method :
player.rect.colliderect(wall.rect)
or
wall.rect.colliderect(player.rect)
would both return true if the two rects are overlapping.
If you want more control, simply add a hitbox attribue in your classes which will be a rect of the size you want for the collision detection area and then use the hitbox rect
Happy programming
I'm trying to make a simple pygame maze and I have a problem that only 2 sprites are displayed: a player and a single wall, while i see that they are all added to the sprite list correctly
PINK = (221, 160, 221)
WHITE = (255, 255, 255)
BLUE = (29, 32, 76)
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
FPS = 30
class Player(pygame.sprite.Sprite):
def __init__(self, x, y, img='alien.png'):
# Call the parent's constructor
super().__init__()
self.image = pygame.image.load(img).convert_alpha()
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
# Set speed vector
self.change_x = 0
self.change_y = 0
self.walls = None
def update(self):
# Horizontal movement
self.rect.x += self.change_x
# Check if object stumbles upon an obstacle
block_hit_list = pygame.sprite.spritecollide(self, self.walls, False)
for block in block_hit_list:
if self.change_x > 0: # If the object was moving right
self.rect.right = block.rect.left # Align its right border with the left border of an obstacle
else: # If the object was moving left
self.rect.left = block.rect.right # Align its left border with the right border of an obstacle
# Vetical movement
self.rect.y += self.change_y
# Check if object stumbles upon an obstacle
block_hit_list = pygame.sprite.spritecollide(self, self.walls, False)
for block in block_hit_list:
if self.change_y > 0: # If the object was moving up
self.rect.bottom = block.rect.top # Align its upper border with the down border of an obstacle
else: # If the object was moving down
self.rect.top = block.rect.bottom # Align its down border with the up border of an obstacle
class Wall(pygame.sprite.Sprite):
def __init__(self, x, y, width, height):
super().__init__()
self.image = pygame.Surface([width, height])
self.image.fill(BLUE)
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('Maze game')
all_sprite_list = pygame.sprite.Group()
wall_list = pygame.sprite.Group()
for x in range(len(walls)):
for y in range(len(walls)):
if walls[x][y] == 1:
#print(x, y)
wall = Wall(x, y, 20, 20)
wall_list.add(wall)
all_sprite_list.add(wall)
player = Player(maze.start[0], maze.start[1])
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.change_x = -3
elif event.key == pygame.K_RIGHT:
player.change_x = 3
elif event.key == pygame.K_UP:
player.change_y = -3
elif event.key == pygame.K_DOWN:
player.change_y = 3
elif event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
player.change_x = 0
elif event.key == pygame.K_RIGHT:
player.change_x = 0
elif event.key == pygame.K_UP:
player.change_y = 0
elif event.key == pygame.K_DOWN:
player.change_y = 0
screen.fill(PINK)
all_sprite_list.update()
all_sprite_list.draw(screen)
pygame.display.flip()
clock.tick(60)
pygame.quit()
where maze.grid is a 2D np array made from 0's and 1's and maze.start is a tuple like (0, 9).
When I change height and width parameters in line wall = Wall(x, y, 20, 20) to wall = Wall(x, y, 1, 1) i see a tiny maze appearing on the screen, but if i increase the height and width of a wall i just see a single square at the top left corner of the window. I assume that the problem is that i want it to add each wall on 20x20px block but instead it adds on 1x1px block. How can I fix this?
Is there a way to treat coordinates not by just 1x1px block?
Actually, all objects are drawn, but drawn one on top of the other.
In the nested loop x and y are the index in the grid (walls), but not the coordinate of the upper left corner. You need to calculate the coordinate of the corner of each cell by multiplying it by the size of a cell (20):
wall = Wall(x, y, 20, 20)
wall = Wall(x*20, y*20, 20, 20)
I am fairly new at pygame so I need some help with a few problems. I'm doing a snake game but with enemies and a "maze".
My biggest problem is, I think, rather glaring if you run my code. I have coded the 'food' to appear at random but instead of appearing at 1 random place, it is moving around the screen. [SOLVED]
My second problem is that I want to spawn several enemies (around 5) at random locations instead of just one enemy but I don't know how to.
My third problem is bullet to wall collision detection. It works if I shoot the bullets one at a time but if I shoot multiple bullets at once, all the bullets will pass through the wall except the last one which will hit the wall.
These are the enemy codes:
Code is removed for now. Will re-upload in 1 to 2 months.
enemy = Enemy(500, 500, 1, wall_list)
all_sprite_list.add(enemy)
These are the codes for the bullets:
Code is removed for now. Will re-upload in 1 to 2 months.
Code is removed for now. Will re-upload in 1 to 2 months.
and this is my entire code if it helps:
Code is removed for now. Will re-upload in 1 to 2 months.
I appreciate any help I can get, even if its not related to the questions that I asked above. Thank you so much for your help!
You can add an instance to the Enemy class and spawn it to add another enemy, just give it some different coordinates then the first one.:
enemy = Enemy(500, 500, 1, wall_list)
enemy2 = Enemy(400,400,1, wall_list)
all_sprite_list.add(enemy)
all_sprite_list.add(enemy2)
For the food, id add another class like you did before.
class Food(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.Surface([10,10])
self.image.fill(green)
self.rect = self.image.get_rect()
self.rect.x = random.randrange(20,780)
self.rect.y = random.randrange(20,780)
remove the following line:
pygame.draw.rect(win,green,[randfoodx,randfoody,10,10])
add this in the same location as where you spawn the enemies and the player sprites:
food = Food()
all_sprite_list.add(food)
For the bullet problem you mentioned, change the following line:
if pygame.sprite.spritecollideany(bullet, wall_list):
into:
if pygame.sprite.spritecollideany(self, wall_list):
This is important since when you spawn a new bullet, the bullet variable name will be overwritten.
all together:
#Import
import pygame
import math
import time
import random
from pygame.locals import *
#Initialize
pygame.init()
pygame.mixer.init()
clock=pygame.time.Clock()
win = pygame.display.set_mode((800,800))
pygame.display.set_caption("Essential Python CA1")
#Define
black = (0, 0, 0)
white = (255, 250, 250)
green = (0, 255, 0)
red = (255, 0, 0)
blue = (70,130,180)
font = pygame.font.Font(None, 60)
display_instructions = True
instruction_page = 1
#Bullet
class Bullet(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.Surface([5, 5])
self.image.fill(green)
self.rect = self.image.get_rect()
def update(self):
self.rect.move_ip(self.vec.x, self.vec.y)
if pygame.sprite.spritecollideany(self, wall_list):
self.kill()
#Enemy
class Enemy(pygame.sprite.Sprite):
def __init__(self, x, y, speed, walls):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface([20, 20])
self.image.fill(red)
self.rect = self.image.get_rect()
self.rect.y = y
self.rect.x = x
self.speed = speed # speed of the enemy
self.walls = walls # walls for the collision test
def move(self, player):
dx, dy = player.rect.x - self.rect.x, player.rect.y - self.rect.y
dist = math.hypot(dx, dy)
dx, dy = dx / dist, dy / dist
Enemy.move_x = dx * self.speed
Enemy.move_y = dy * self.speed
def update(self):
self.rect.x += round(self.move_x)
block_collide = pygame.sprite.spritecollide(self, self.walls, False)
for block in block_collide:
if self.move_x > 0:
self.rect.right = block.rect.left
else:
self.rect.left = block.rect.right
self.rect.y += round(self.move_y)
block_collide = pygame.sprite.spritecollide(self, self.walls, False)
for block in block_collide:
if self.move_y > 0:
self.rect.bottom = block.rect.top
else:
self.rect.top = block.rect.bottom
#Player
class Player(pygame.sprite.Sprite):
move_x = 0
move_y = 0
walls = None
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface([20, 20])
self.image.fill(white)
self.rect = self.image.get_rect()
self.rect.y = y
self.rect.x = x
def move(self, x, y):
self.move_x += x
self.move_y += y
def update(self):
self.rect.x += self.move_x
block_collide = pygame.sprite.spritecollide(self, self.walls, False)
for block in block_collide:
if self.move_x > 0:
self.rect.right = block.rect.left
else:
self.rect.left = block.rect.right
self.rect.y += self.move_y
block_collide = pygame.sprite.spritecollide(self, self.walls, False)
for block in block_collide:
if self.move_y > 0:
self.rect.bottom = block.rect.top
else:
self.rect.top = block.rect.bottom
#Maze
class Wall(pygame.sprite.Sprite):
def __init__(self, x, y, width, height):
super().__init__()
self.image = pygame.Surface([width, height])
self.image.fill(blue)
self.rect = self.image.get_rect()
self.rect.y = y
self.rect.x = x
class Food(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.width = 10
self.height = 10
self.image = pygame.Surface([10,10])
self.image.fill(green)
self.rect = self.image.get_rect()
self.rect.x = random.randrange(20,780)
self.rect.y = random.randrange(20,780)
all_sprite_list = pygame.sprite.Group()
wall_list = pygame.sprite.Group()
walls = ((0, 0, 10, 800),
(40, 40, 10, 75),
(50, 40, 190, 10),
(790, 10, 10, 800),
(10, 0, 800, 10),
(10, 790, 800, 10),
(50, 750, 170, 10),
(40, 145, 10, 615),
(80, 710, 310, 10),
(250, 750, 110, 10),
(390, 680, 10, 80),
(400, 750, 200, 10),
(430, 710, 10, 50),
(470, 710, 200, 10),
(630, 750, 130, 10),
(750, 40, 10, 720),
(550, 40, 210, 10),
(270, 40, 250, 10),
(410, 80, 310, 10),
(410, 120, 310, 10),
(80, 80, 300, 10),
(370, 40, 10, 90),
(130, 120, 240, 10),
(300, 160, 450, 10),
(50, 160, 220, 10),
(700, 710, 50, 10),
(80, 670, 670, 10),
(80, 160, 10, 510),
(80, 200, 100, 10),
(210, 200, 120, 10),
(270, 200, 10, 90),
(120, 240, 150, 10),
(80, 280, 250, 10),
(360, 200, 100, 10),
(310, 240, 150, 10),
(460, 160, 10, 130),
(360, 280, 100, 10))
for wall_coords in walls:
wall = Wall(*wall_coords)
wall_list.add(wall)
all_sprite_list.add(wall)
player = Player(10, 10)
player.walls = wall_list
enemy = Enemy(500, 500, 1, wall_list)
enemy2 = Enemy(400,400,1, wall_list)
all_sprite_list.add(enemy)
all_sprite_list.add(enemy2)
food = Food()
all_sprite_list.add(food)
all_sprite_list.add(player)
#Start screen Loop
done = False
while not done and display_instructions:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = False
if event.type == pygame.MOUSEBUTTONDOWN:
instruction_page += 1
if instruction_page == 2:
display_instructions = False
# Set the screen background
win.fill(black)
if instruction_page == 1:
text = font.render("Instructions:", True, white)
win.blit(text, [10, 20])
text = font.render("Use WASD, or the Arrow Keys to move", True, white)
win.blit(text, [10, 100])
text = font.render("Left click to shoot", True, white)
win.blit(text, [10, 150])
text = font.render("Can you beat your highscore?", True, red)
win.blit(text, [100, 370])
text = font.render("Click to start", True, white)
win.blit(text, [270, 600])
clock.tick(60)
pygame.display.flip()
# Programme loop
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT or event.key == ord('a'):
player.move(-2, 0)
elif event.key == pygame.K_RIGHT or event.key == ord('d'):
player.move(2, 0)
elif event.key == pygame.K_UP or event.key == ord('w'):
player.move(0, -2)
elif event.key == pygame.K_DOWN or event.key == ord('s'):
player.move(0, 2)
elif event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or event.key == ord('a'):
player.move(2, 0)
elif event.key == pygame.K_RIGHT or event.key == ord('d'):
player.move(-2, 0)
elif event.key == pygame.K_UP or event.key == ord('w'):
player.move(0, 2)
elif event.key == pygame.K_DOWN or event.key == ord('s'):
player.move(0, -2)
elif event.type == pygame.MOUSEBUTTONDOWN:
aim_pos = event.pos
player_position = player.rect.center
bullet_vec = pygame.math.Vector2(aim_pos[0] - player_position[0], aim_pos[1] - player_position[1]).normalize() * 10
bullet = Bullet()
bullet.rect.center = player.rect.center
bullet.vec = bullet_vec
all_sprite_list.add(bullet)
enemy.move(player)
all_sprite_list.update()
win.fill(black)
all_sprite_list.draw(win)
# pygame.draw.rect(win,green,[randfoodx,randfoody,10,10])
pygame.display.flip()
clock.tick(100)
pygame.quit()
For the food issue, you'd need it to only generate a piece of food if there are none on the map. Or if there were less than x. So set a numberOfFood variable, and instead of while run: you could put while numberOfFood < 2:
I've been trying to learn pygame from this site, and it keeps failing.
I'm almost certain it's supposed to be Python 3.
Here's the code that's failing (straight from the site):
import pygame
# COLORS
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
BLUE = (0, 0, 255)
# Screen dimensions
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
# The Player. Without a player, what is a game?
class Player(pygame.sprite.Sprite):
def __init__(self, x, y):
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
# Set speed vector
self.change_x = 0
self.change_y = 0
self.walls = None
def changespeed(self, x, y):
# WHAT DO YOU THINK THIS DOES YOU TWAT?
# keff keff. It changes the player's speed.
self.change_x += x
self.change_y += y
def update(self):
# Update player position.
# Move left/right
self.rect.x += self.change_x
# Did we run into a wall?
block_hit_list = pygame.sprite.spritecollide(self, self.walls, False)
for block in block_hit_list:
# Keep that player OUT!
if self.change_y > 0:
self.rect.bottom = block.rect.top
else:
self.rect.top = block.rect.bottom
# Same thing for up and down, now we only have one variable to mess with
self.rect.y += self.change_y
# NOW did we run into a wall?
block_hit_list = pygame.sprite.spritecollide(self, self.walls, False)
for block in block_hit_list:
# Please leave the premises.
if self.change_y > 0:
self.rect.bottom = block.rect.top
else:
self.rect.top = block.rect.bottom
class Wall(pygame.sprite.Sprite):
# Defines a wall. I mean what else can this do?
def __init__(self, x, y, width, height):
# Construction.
super().__init__()
# Make it blue, and not invisible
self.image = pygame.Surface([width, height])
self.image.fill(BLUE)
# Make the top left corner where we "center" the thing
self.rect = self.image.get_rect()
self.rect.y = y
self.rect.x = x
# That was easy. Most of the work is done by the player and not the walls.
# Initialize pygame
pygame.init()
# Create the pygame window
screen = pygame.display.set_mode([SCREEN_WIDTH, SCREEN_HEIGHT])
# This line is fairly self explanatory...
pygame.display.set_caption('1-2 WALLS')
# Make a list of all the sprites, a census.
all_sprite_list = pygame.sprite.Group()
# Now we build our walls.
wall_list = pygame.sprite.Group()
# Each wall follows a format to be created
# You can copy-paste this over and over till you're happy
# Define a wall # x, y, x2, y2
wall = Wall(0, 0, 10, 600)
# Put it in the appropriate lists
wall_list.add(wall)
all_sprite_list.add(wall)
#blank line here
wall = Wall(10, 0, 790, 10)
wall_list.add(wall)
all_sprite_list.add(wall)
wall = Wall(10, 200, 100, 10)
wall_list.add(wall)
all_sprite_list.add(wall)
# Spawn a player at x 50 y 50.
player = Player(50, 50)
player.walls = wall_list
all_sprite_list.add(player)
# Start the clock
clock = pygame.time.Clock()
done = False
while not done:
# ask pygame what's happening so we can deal with it
for event in pygame.event.get():
# Did they quit the game?
if event.type == pygame.QUIT():
done = True
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_UP:
player.changespeed(0, 3)
elif event.key == pygame.K_DOWN:
player.changespeed(0, -3)
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)
elif event.key == pygame.K_UP:
player.changespeed(0, 3)
elif event.key == pygame.K_DOWN:
player.changespeed(0, -3)
# Update our census
all_sprite_list.update()
screen.fill(BLACK)
all_sprite_list.draw(screen)
pygame.display.flip()
clock.tick(60)
pygame.quit()
When I run it, I get an error saying
Traceback (most recent call last):
line 16, in __init__
super.__init__()
TypeError: descriptor '__init__' of 'super' object needs an argument
You should notice that you are calling super differently in Wall and Player. The way you are doing it in Wall is correct:
super().__init__()
whereas in Player you are missing the parentheses after super.
I'm looking to make some enemies in my game drop "UP Points" (Upgrade Points in the form of small yellow squares) when I shoot them. I've tried a few different things but can't seem to figure out how to spawn these collectable points in place of where an enemy just died. Does anyone have any ideas about how I could implement this?
UP class:
class Up(pygame.sprite.Sprite):
def __init__(self, color):
super().__init__()
self.image = pygame.Surface([5, 5])
self.image.fill(color)
self.rect = self.image.get_rect()
Here's the loop for when an enemy gets shot and dies:
for bullet in bullet_list: #For each bullet:
# Whenever a bullet collides with a zombie,
block_hit_list = pygame.sprite.spritecollide(bullet, zombie_list, True)
for i in block_hit_list:
# Destroy the bullet and zombie and add to the score
bullet_list.remove(bullet)
all_sprites_list.remove(bullet)
score += 100
Sorry for not posting my whole code, the main game loop is at the bottom :)
import pygame
import math
import random
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
BLUE = (0, 0, 255)
ORANGE = (255, 119, 0)
ZOMBIE_GREEN = (122, 172, 34)
YELLOW = (255, 255, 0)
cursor_x = 100
cursor_y = 100
class Player(pygame.sprite.Sprite):
def __init__(self, color):
super().__init__()
# pygame.Surface will create a rectangle with the width and height given
# and the command below it tells it to fill it in with that color
self.image = pygame.Surface([15, 15])
self.image.fill(color)
self.rect = self.image.get_rect()
# This defines the starting position (x, y)
# of whatever sprite is passed through
self.rect.x = 600
self.rect.y = 300
# This is the current speed it will move when drawn
self.change_x = 0
self.change_y = 0
self.walls = None
# Defines how the player will move
def movement(self, x, y):
self.change_x += x
self.change_y += y
# Updates the information so the screen shows the player moving
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:
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
class Enemy(pygame.sprite.Sprite):
def __init__(self, color):
super().__init__()
self.image = pygame.Surface([20, 20])
self.image.fill(color)
self.rect = self.image.get_rect()
self.pos_x = self.rect.x = random.randrange(35, screen_width - 35)
self.pos_y = self.rect.y = random.randrange(35, screen_height - 135)
# How Zombies move towards player
def update(self):
zombie_vec_x = self.rect.x - player.rect.x
zombie_vec_y = self.rect.y - player.rect.y
vec_length = math.sqrt(zombie_vec_x ** 2 + zombie_vec_y ** 2)
if self.rect.x != player.rect.x and self.rect.y != player.rect.y:
zombie_vec_x = (zombie_vec_x / vec_length) * 1 # These numbers determine
zombie_vec_y = (zombie_vec_y / vec_length) * 1 # zombie movement speed
self.pos_x -= zombie_vec_x
self.pos_y -= zombie_vec_y
self.rect.x = self.pos_x
self.rect.y = self.pos_y
block_hit_list = pygame.sprite.spritecollide(self, sprites_list, False)
for block in block_hit_list:
if self.rect.x > 0:
self.rect.right = block.rect.left
elif self.rect.x < 0:
self.rect.left = block.rect.right
elif self.rect.y > 0:
self.rect.bottom = block.rect.top
else:
self.rect.top = block.rect.bottom
class Wall(pygame.sprite.Sprite):
def __init__(self, color, x, y, width, height):
super().__init__()
self.image = pygame.Surface([width, height])
self.image.fill(color)
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
class Cursor(pygame.sprite.Sprite):
def __init__(self, width, height):
self.groups = all_sprites_list
self._layer = 1
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface([width, height])
self.image.fill(RED)
self.rect = self.image.get_rect()
self.walls = None
# This updates the cursor to move along with your
# mouse position (defined in control logic)
def update(self):
self.rect.x = cursor_x
self.rect.y = cursor_y
class Bullet(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.Surface([8, 8])
self.image.fill(ORANGE)
self.rect = self.image.get_rect()
# Instead of using the rect. positions, we'll use pos_ variables
# to calculate position. This is because the rect. uses integers
# while a variable can have exact float numbers. This will keep
# the bullets trajectory exact istead of useing a general
# (rounded) whole number <3
self.pos_x = player.rect.x + 4 # Set up pos_x and pos_y here
self.pos_y = player.rect.y + 4 # rather than rect.x and rect.y
self.walls = None
self.change_x = 0
self.change_y = 0
speed = 6
bullet_vec_x = (cursor.rect.x - 4) - player.rect.x
bullet_vec_y = (cursor.rect.y - 4) - player.rect.y
vec_length = math.sqrt(bullet_vec_x ** 2 + bullet_vec_y ** 2)
bullet_vec_x = (bullet_vec_x / vec_length) * speed
bullet_vec_y = (bullet_vec_y / vec_length) * speed
self.change_x += bullet_vec_x
self.change_y += bullet_vec_y
def update(self):
self.pos_x += self.change_x # Update pos_x and pos_y. They will become floats
self.pos_y += self.change_y # which will let them maintain sub-pixel accuracy.
self.rect.x = self.pos_x # Copy the pos values into the rect, where they will be
self.rect.y = self.pos_y # rounded off. That's OK since we never read them back.
pygame.init()
screen_size = pygame.display.Info()
size = (1300, 720)
screen = pygame.display.set_mode(size)
#size = (screen_size.current_w, screen_size.current_h)
#screen = pygame.display.set_mode(
# ((screen_size.current_w, screen_size.current_h)),pygame.FULLSCREEN
# )
screen_width = screen_size.current_w
screen_height = screen_size.current_h
pygame.display.set_caption("Zombie Shooter")
wall_list = pygame.sprite.Group()
zombie1_list = pygame.sprite.Group()
sprites_list = pygame.sprite.Group()
bullet_list = pygame.sprite.Group()
all_sprites_list = pygame.sprite.Group()
# Walls are made here = (x_coord for where it starts,
# y_coord for where it starts, width of wall, height of wall)
# These walls are made with fullscreen dimentions, not any set dimentions
# Left
wall = Wall(BLUE, 0, 0, 10, screen_height)
wall_list.add(wall)
all_sprites_list.add(wall)
# Top
wall = Wall(BLUE, 0, 0, screen_width, 10)
wall_list.add(wall)
all_sprites_list.add(wall)
# Bottom
wall = Wall(BLUE, 0, screen_height - 10, screen_width, 10)
wall_list.add(wall)
all_sprites_list.add(wall)
# Right
wall = Wall(BLUE, screen_width - 10, 0, 10, screen_width)
wall_list.add(wall)
all_sprites_list.add(wall)
# HUD Border
wall = Wall(BLUE, 0, screen_height - 100, screen_width, 10)
wall_list.add(wall)
all_sprites_list.add(wall)
# This creates the actual player with the parameters set in ( ).
# However, we must add the player to the all_sprites_list
# so that it will actually be drawn to the screen with the draw command
# placed right after the screen.fill(BLACK) command.
player = Player(WHITE)
player.walls = wall_list
all_sprites_list.add(player)
zombie = Enemy(ZOMBIE_GREEN)
zombie.walls = wall_list
for i in range(5):
zombie = Enemy(ZOMBIE_GREEN)
all_sprites_list.add(zombie)
zombie1_list.add(zombie)
sprites_list.add(zombie)
cursor = Cursor(7, 7)
cursor.walls = wall_list
all_sprites_list.add(cursor)
bullet = Bullet()
font = pygame.font.SysFont("crushed", 30)
score = 0
up_score = 0
done = False
clock = pygame.time.Clock()
pygame.mouse.set_visible(0)
# -------- Main Program Loop -----------
while not done:
# --- Main event loop ---
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
# Press 'P' to quit the game_____
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_p:
done = True
#________________________________
# Keyboard controls. The numbers inside change the speed of the player
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_a:
player.movement(-4, 0)
elif event.key == pygame.K_d:
player.movement(4, 0)
elif event.key == pygame.K_w:
player.movement(0, -4)
elif event.key == pygame.K_s:
player.movement(0, 4)
elif event.type == pygame.KEYUP:
if event.key == pygame.K_a:
player.movement(4, 0)
elif event.key == pygame.K_d:
player.movement(-4, 0)
elif event.key == pygame.K_w:
player.movement(0, 4)
elif event.key == pygame.K_s:
player.movement(0, -4)
# ___________________________________________________________________
# Mouse Controls----------------------------
pos = pygame.mouse.get_pos()
cursor_x = pos[0]
cursor_y = pos[1]
if cursor_x <= 10:
cursor_x = 10
if cursor_x >= (screen_width - 17):
cursor_x = (screen_width - 17)
if cursor_y <= 10:
cursor_y = 10
if cursor_y >= (screen_height - 107):
cursor_y = (screen_height - 107)
elif event.type == pygame.MOUSEBUTTONDOWN:
bullet = Bullet()
all_sprites_list.add(bullet)
bullet_list.add(bullet)
#--------------------------------------------
all_sprites_list.update()
# How bullets vanish when they hit a sprite or a wall______________________
for bullet in bullet_list: #For each bullet:
# Whenever a bullet collides with a zombie,
block_hit_list = pygame.sprite.spritecollide(bullet, zombie1_list, True)
for i in block_hit_list:
# Destroy the bullet and zombie and add to the score
bullet_list.remove(bullet)
all_sprites_list.remove(bullet)
score += 100
for bullet in bullet_list:
block_hit_list = pygame.sprite.spritecollide(bullet, wall_list, False)
for i in block_hit_list:
bullet_list.remove(bullet)
all_sprites_list.remove(bullet)
#--------------------------------------------------------------------------
cursor.update()
bullet_list.update()
sprites_list.update()
pygame.mouse.set_visible(0)
screen.fill(BLACK)
all_sprites_list.draw(screen)
text = font.render("Score: " + str(score), True, WHITE)
screen.blit(text, [30, screen_height - 64])
pygame.display.flip()
clock.tick(60)
pygame.quit()
What you will have to do is before you destroy the zombie sprite grab its location and draw the UP coin. Then make sure that whenever the player controlled sprite, in this case the bullet, upon contact "collects" the coin. I haven't worked with python that much but the main code would look something like this:
def drawCoin():
zombieCoords = grabZombieCoords()
drawSprite(zombieCoords())
This would essentially just get the coordinates of the zombie, destroy it, and then place the coin at the last known location of the zombie.
Hope this helps.
Change your Up class to accept an argument pos, and use it to set the starting position:
class Up(pygame.sprite.Sprite):
def __init__(self, color, pos):
super().__init__()
self.image = pygame.Surface([5, 5])
self.image.fill(color)
self.rect = self.image.get_rect(center=pos)
Now, when you hit a zombie, create an Up, using the position of the zombie you just killed.
for bullet in bullet_list:
block_hit_list = pygame.sprite.spritecollide(bullet, zombie_list, True)
for i in block_hit_list:
# just use .kill() to remove a Sprite from all of its Groups
# kill() may get called multiple times, but that does not hurt
bullet.kill()
score += 100
# create an Up for each killed zombie
# takes two arguments: color and pos
# we call .add() to add the Sprite immediately to
# the all_sprites_list and the up_list
Up((255, 0, 0), i.rect.center).add(all_sprites_list, up_list)
You didn't show the rest of your code, but I guess you call .draw and .update on your all_sprites_list and create a Group called up_list.