Having trouble with my PyGame experimental game - I'm learning how to work with sprites.
I have been trying to code 'collision' detection between sprites (ball and paddle) and have managed to get the collision detection working but my ball sprite seems to reset its position instead of carrying on. Could anyone take a look and see where my error is?
Here is my code:
import pygame
BLACK = ( 0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
#variables, constants, functions
x = 1
y = 1
x_vel = 10
y_vel = 10
bat_x = 1
bat_y = 1
bat_x_vel = 0
bat_y_vel = 0
score = 0
class Ball(pygame.sprite.Sprite):
"""
This class represents the ball.
It derives from the "Sprite" class in Pygame.
"""
def __init__(self, width, height):
""" Constructor. Pass in the color of the block,
and its x and y position. """
# Call the parent class (Sprite) constructor
super().__init__()
# Set the background color and set it to be transparent
self.image = pygame.Surface([width, height])
self.image.fill(WHITE)
self.image.set_colorkey(WHITE)
# Draw the ellipse
pygame.draw.ellipse(self.image, (255,0,0), [0,0,width,height], 10)
# Fetch the rectangle object that has the dimensions of the image
# image.
# Update the position of this object by setting the values
# of rect.x and rect.y
self.rect = self.image.get_rect()
# Instance variables that control the edges of where we bounce
self.left_boundary = 0
self.right_boundary = 0
self.top_boundary = 0
self.bottom_boundary = 0
# Instance variables for our current speed and direction
self.vel_x = 5
self.vel_y = 5
def update(self):
""" Called each frame. """
self.rect.x += self.vel_x
self.rect.y += self.vel_y
if self.rect.right >= self.right_boundary or self.rect.left <= self.left_boundary:
self.vel_x *= -1
if self.rect.bottom >= self.bottom_boundary or self.rect.top <= self.top_boundary:
self.vel_y *= -1
class Paddle(pygame.sprite.Sprite):
"""
This class represents the ball.
It derives from the "Sprite" class in Pygame.
"""
def __init__(self, width, height):
""" Constructor. Pass in the color of the block,
and its x and y position. """
# Call the parent class (Sprite) constructor
super().__init__()
# Set the background color and set it to be transparent
self.image = pygame.Surface([width, height])
self.image.fill(WHITE)
self.image.set_colorkey(WHITE)
# Draw the rectangle
pygame.draw.rect(self.image, (0, 255, 0), [0, 0, width, height], 0)
# Fetch the rectangle object that has the dimensions of the image
# image.
# Update the position of this object by setting the values
# of rect.x and rect.y
self.rect = self.image.get_rect()
# Instance variables for our current speed and direction
self.x_vel = 0
self.y_vel = 0
def update(self):
# Get the current mouse position. This returns the position
# as a list of two numbers.
self.rect.x = self.rect.x + self.x_vel
self.rect.y = self.rect.y + self.y_vel
#initialise ball and paddle
paddle = Paddle(20, 100)
ball = Ball(100,100)
# This is a list of every sprite.
# All blocks and the player block as well.
all_sprites_list = pygame.sprite.Group()
all_sprites_list.add(ball)
all_sprites_list.add(paddle)
ball_sprites_list = pygame.sprite.Group()
ball_sprites_list.add(ball)
# Initialize Pygame
pygame.init()
# Set the height and width of the screen
screen_width = 700
screen_height = 400
screen = pygame.display.set_mode((screen_width, screen_height))
# Used to manage how fast the screen updates
clock = pygame.time.Clock()
# Loop until the user clicks the close button.
done = False
# -------- Main Program Loop -----------
while not done:
# --- Events code goes here (mouse clicks, key hits etc)
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP:
paddle.y_vel = -3
if event.key == pygame.K_DOWN:
paddle.y_vel = 3
if event.type == pygame.KEYUP:
if event.key == pygame.K_UP:
paddle.y_vel = 0
if event.key == pygame.K_DOWN:
paddle.y_vel = 0
# --- Game logic should go here
# Calls update() method on every sprite in the list
all_sprites_list.update()
# collision check
ball_hit_list = pygame.sprite.spritecollide(paddle, ball_sprites_list, False)
# Check the list of collisions.
for ball in ball_hit_list:
score +=1
print(score)
# --- Clear the screen
screen.fill((255,255,255))
# --- Draw all the objects
all_sprites_list.draw(screen)
# render text
myfont = pygame.font.SysFont("monospace", 15)
label = myfont.render(str(score), 1, (0,0,0))
screen.blit(label, (100, 100))
# --- Update the screen with what we've drawn.
pygame.display.flip()
# --- Limit to 60 frames per second
clock.tick(60)
pygame.quit()
Sorry,
Have found the error.
Didn't set the boundaries of the window properly.
# Instance variables that control the edges of where we bounce
self.left_boundary = 0
self.right_boundary = 700
self.top_boundary = 0
self.bottom_boundary = 400
Related
I want an image to be in the place of the rectangle.
The class Block is used to make a 'food' square, enemy square, and player square. I need help reformatting Block to also accept an image in the color attributes place.
import pygame
import random
# Define some colors
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
BLUE = (0,0,255)
GREEN = (0,255,0)
class Block(pygame.sprite.Sprite):
"""
This class represents the ball.
It derives from the "Sprite" class in Pygame.
"""
def __init__(self, color, width, height):
""" Constructor. Pass in the color of the block,
and its size. """
# Call the parent class (Sprite) constructor
super().__init__()
# Create an image of the block, and fill it with a color.
# This could also be an image loaded from the disk.
self.image = pygame.Surface([width, height])
self.image.fill(color)
# Fetch the rectangle object that has the dimensions of the image
# image.
# Update the position of this object by setting the values
# of rect.x and rect.y
self.rect = self.image.get_rect()
class Player(pygame.sprite.Sprite):
""" The class is the player-controlled sprite. """
# -- Methods
def __init__(self, x, y):
"""Constructor function"""
# Call the parent's constructor
super().__init__()
# Set height, width
self.image = pygame.Surface([15, 15])
self.image.fill(BLUE)
# Make our top-left corner the passed-in location.
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
# -- Attributes
# Set speed vector
self.change_x = 0
self.change_y = 0
def changespeed(self, x, y):
""" Change the speed of the player"""
self.change_x += x
self.change_y += y
def update(self):
""" Find a new position for the player"""
if self.rect.x < 0:
self.rect.x += 3
wall.play()
if self.rect.x > 685:
self.rect.x-=3
wall.play()
if self.rect.y < 0:
self.rect.y += 3
wall.play()
if self.rect.y > 384:
self.rect.y -= 3
wall.play()
else:
self.rect.x += self.change_x
self.rect.y += self.change_y
# Initialize Pygame
pygame.init()
# Set the height and width of the screen
screen_width = 700
screen_height = 400
screen = pygame.display.set_mode([screen_width, screen_height])
# This is a list of 'sprites.' Each block in the program is
# added to this list. The list is managed by a class called 'Group.'
good_block_list = pygame.sprite.Group()
bad_block_list = pygame.sprite.Group()
collision_sound_good = pygame.mixer.Sound("good_block.wav")
collision_sound_bad = pygame.mixer.Sound("bad_block.wav")
wall = pygame.mixer.Sound("bump.wav")
# This is a list of every sprite.
# All blocks and the player block as well.
all_sprites_list = pygame.sprite.Group()
for i in range(50):
# This represents a block
block = Block(GREEN, 20, 15)
# Set a random location for the block
block.rect.x = random.randrange(screen_width)
block.rect.y = random.randrange(screen_height)
# Add the block to the list of objects
good_block_list.add(block)
all_sprites_list.add(block)
for i in range(50):
# This represents a block
block = Block(RED, 20, 15)
# Set a random location for the block
block.rect.x = random.randrange(screen_width)
block.rect.y = random.randrange(screen_height)
# Add the block to the list of objects
bad_block_list.add(block)
all_sprites_list.add(block)
# Create a RED player block
player = Player(100,50)
all_sprites_list.add(player)
# Loop until the user clicks the close button.
done = False
# Used to manage how fast the screen updates
clock = pygame.time.Clock()
score = 0
# -------- Main Program Loop -----------
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
# Set the speed based on the key pressed
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)
# Reset speed when key goes up
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)
# Game Logic
# This calls update on all the sprites
all_sprites_list.update()
# Clear the screen
screen.fill(WHITE)
good_blocks_hit_list = pygame.sprite.spritecollide(player, good_block_list, True)
bad_blocks_hit_list = pygame.sprite.spritecollide(player, bad_block_list, True)
# Check the list of collisions.
for block in good_blocks_hit_list:
collision_sound_good.play()
score += 1
print(score)
for block in bad_blocks_hit_list:
collision_sound_bad.play()
score -= 1
print(score)
font = pygame.font.SysFont(None, 45)
text = font.render(str(score), True, BLACK)
screen.blit(text, (54, 350))
# Draw all the spites
all_sprites_list.draw(screen)
# Go ahead and update the screen with what we've drawn.
pygame.display.flip()
# Limit to 60 frames per second
clock.tick(60)
pygame.quit()
There are 3 different kinds of blocks that need a separate image.
The blocks are added to sprite group, so I don't think it is possible to Blit the image in the loop.
Question Answered
I would modify the Block constructor such that the color parameter was just a parameter representing the appearance of the sprite. It might be a string filename, or a colour-tuple. This can be tested at run-time.
def __init__(self, appearance, width, height):
""" Create a new sprite sized <width> by <height>.
The sprite is, either a coloured block where <appearance> is a
RGB colour-tuple, OR an image loaded from a file """
# Call the parent class (Sprite) constructor
super().__init__()
# appearance is either an RGB tuple, or a filename str
if ( type( appearance ) is tuple ):
# Create an image of the block, and fill it with a color
self.image = pygame.Surface([width, height])
self.image.fill( appearance )
else:
# The parameter <appearance> holds an image filename
bitmap = pygame.image.load( appearance ).convert()
self.image = pygame.transform.smoothscale( bitmap, ( width, height ) )
# Fetch the rectangle object that has the dimensions of the image image.
# Update the position of this object by setting the values
# of rect.x and rect.y
self.rect = self.image.get_rect()
I'm not really sure this is the best approach of doing this sort of thing. I guess maybe it could allow for a debug-fallback if the image resources are not found or suchlike.
This allows the code to:
new_sprite = Block( ( 182, 128, 0 ), 64, 64 )
[...]
new_sprite = Block( "sandstone.png", 64, 64 )
Soo I may have an answer for my own question...
class Block(pygame.sprite.Sprite):
"""
This class represents the ball.
It derives from the "Sprite" class in Pygame.
"""
def __init__(self, imageFile, width, height):
""" Constructor. Pass in the color of the block,
and its size. """
# Call the parent class (Sprite) constructor
super().__init__()
# Create an image of the block, and fill it with a color.
# This could also be an image loaded from the disk.
#self.image = pygame.Surface([width, height])
#self.image.fill(color)
self.image = pygame.image.load(imageFile).convert()
# Fetch the rectangle object that has the dimensions of the image
# image.
# Update the position of this object by setting the values
# of rect.x and rect.y
self.rect = self.image.get_rect()
I am teaching a fortnightly coding class to a group of dozen super bright young enthusiasts. We have already covered OOP and created a text based adventure using OOP.
Now I am planning to teach PyGame and continue using objects, and I am wondering if games could be built in such a way where the code for each object is in a separate file?, this would be really neat and easier to build on.
Well For the code below I tried making separate files for each object. This was only partially successful because the draw method never works quite well, I believe the issue that I cannot have separate files referencing the same pygame screen.
import pygame
import random
import time
# Define some colors
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
BLUE = (0,0,255)
SCREEN_WIDTH = 700
SCREEN_HEIGHT = 500
pygame.init()
class Paddle:
'''Class to keep players location'''
def __init__(self,x=350, y=480, width =70,height=20):
self.x = x
self.y = y
self.change_x = 0
self.change_y = 0
self.width = width
self.height = height
self.score = 0
def move(self):
self.x += self.change_x
self.y += self.change_y
def draw(self):
pygame.draw.rect(screen, BLUE, [self.x,self.y, self.width, self.height])
def check_collision(self,ball):
if ball.y>460:
if abs(35+ self.x - ball.x) < 30:
self.score += 1
ball.draw(BLUE)
ball.y = 0
ball.x = random.randint(0,650)
ball.change_y = random.randint(2,3+int(self.score/5))
class Ball:
"""Class to keep track of a ball's location and vector."""
def __init__(self,x=350,y=250,size=25):
self.x = x
self.y = y
self.change_x = 0
self.change_y = 0
self.size = size
def move(self):
self.x += self.change_x
self.y += self.change_y
def draw(self,colour = WHITE):
pygame.draw.circle(screen,WHITE, [self.x, self.y], self.size)
# Set the height and width of the screen
size = [SCREEN_WIDTH, SCREEN_HEIGHT]
screen = pygame.display.set_mode(size)
pygame.display.set_caption("Bouncing Balls")
done = False
clock = pygame.time.Clock()
screen.fill(BLACK)
ball = Ball()
player = Paddle()
ball.change_y = 2
ball.draw()
while not done:
screen.fill(BLACK)
# --- 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_SPACE:
pass
if event.key == pygame.K_LEFT:
player.change_x = -5
if event.key == pygame.K_RIGHT:
player.change_x = 5
else:
ball.change_x = 0
player.change_x = 0
if ball.y > 500:
print('YOUR SCORE: ',player.score)
time.sleep(2)
pygame.quit()
#move ball and player and check if they collide
ball.move()
player.move()
player.check_collision(ball)
#draw ball and player
ball.draw()
player.draw()
#render frame
clock.tick(60)
pygame.display.flip()
# Print score and exit
print('YOUR SCORE: ',player.score)
pygame.quit()
When I had separate files this is the error that I got in relation to screen
line 20, in draw
pygame.draw.circle(screen,WHITE, [self.x, self.y], self.size)
NameError: name 'screen' is not defined
Add a surface argument to the draw() methods of the classes Paddle and Ball and draw the object on the surface which is passed to the method:
class Paddle:
# [...]
def draw(self, surface):
pygame.draw.rect(surface, BLUE, [self.x,self.y, self.width, self.height])
class Ball:
# [...]
def draw(self, surface, colour = WHITE):
pygame.draw.circle(surface, colour, [self.x, self.y], self.size)
Now you can draw the objects on any pygame.Surface you want, e.g. screen:
ball.draw(screen)
player.draw(screen)
I'm making a "duck hunt" game in pygame. I have everything working, my sprites move and respawn when needed, cursor is a crosshair with sound when clicked etc. The issue I'm having is trying to add points when the mouse is click on a duck. Any idea how I would do this? Posted all of the code, its a bit of a mess until I get thank working, check the main loop specifically. Thanks.
import pygame
import random
import duck_code
# Define some colors
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
BLUE = (0, 0, 255)
GREEN = (0, 255, 0)
DUCK_BACK = (59, 202, 255)
class Player(pygame.sprite.Sprite):
""" The class is the player-controlled sprite. """
# -- Methods
def __init__(self, x, y, filename):
"""Constructor function"""
# Call the parent's constructor
super().__init__()
# Set height, width
self.image = pygame.Surface([15, 15])
self.image.fill(BLACK)
self.image = pygame.image.load(filename).convert()
# Make our top-left corner the passed-in location.
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
# -- Attributes
# Set speed vector
self.change_x = 0
self.change_y = 0
def changespeed(self, x, y):
""" Change the speed of the player"""
self.change_x += x
self.change_y += y
def update(self):
""" Find a new position for the player"""
self.rect.x += self.change_x
self.rect.y += self.change_y
# boarders for walls, reset player, play bump sound
if self.rect.x in range(1060, 1085):
self.rect.x -= 25
if self.rect.x in range(-5, 0):
self.rect.x += 25
if self.rect.y in range(-5, 0):
self.rect.y += 25
if self.rect.y in range(480, 505):
self.rect.y -= 25
# Initialize Pygame
# Loading sounds
pygame.init()
game_background = pygame.image.load("game_background.jpg")
duck_hit = pygame.mixer.Sound("duck_hit.wav")
player_click = pygame.mixer.Sound("shot_gun.ogg")
# Set the height and width of the screen
screen_width = 1280
screen_height = 1024
screen = pygame.display.set_mode([screen_width, screen_height])
# Starting score and font settings
font = pygame.font.Font(None, 36)
score = 0
# This is a list of every sprite.
all_sprites_list = pygame.sprite.Group()
duck_list = pygame.sprite.Group()
duck_hit_list = pygame.sprite.Group()
"""DUCKS"""
for i in range(5):
# This represents a block
ducks = duck_code.Duck("duck1.png")
ducks.rect.x = random.randrange(screen_width)
ducks.rect.y = random.randrange(50, 350)
# Add the block to the list of objects
duck_list.add(ducks)
all_sprites_list.add(ducks)
"""PLAYER"""
player_image = pygame.image.load("crosshair.png")
player_image.set_colorkey(WHITE)
# Loop until the user clicks the close button.
done = False
# Used to manage how fast the screen updates
clock = pygame.time.Clock()
score = 0
# Hide the mouse cursor
pygame.mouse.set_visible(0)
# -------- Main Program Loop -----------
while not done:
mouse = pygame.mouse.get_pos()
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
blocks_hit_list = pygame.sprite.spritecollide(mouse, duck_list, True)
score += 100
print(score)
player_click.play()
# --- Game logic should go here
# --- Screen-clearing code goes here
# Here, we clear the screen to white. Don't put other drawing commands
# above this, or they will be erased with this command.
# If you want a background image, replace this clear with blit'ing the
# background image.
screen.blit(game_background, [0, 0])
player_position = pygame.mouse.get_pos()
x = player_position[0]
y = player_position[1]
screen.blit(player_image, [x, y])
pos = pygame.mouse.get_pos()
pressed1, pressed2, pressed3 = pygame.mouse.get_pressed()
# Check if the rect collided with the mouse pos
# and if the left mouse button was pressed.
all_sprites_list.draw(screen)
duck_list.update()
# Showing scoreboard
text = font.render("Score: " + str(score), True, WHITE)
screen.blit(text, [10, 10])
# Go ahead and update the screen with what we've drawn.
pygame.display.flip()
# Limit to 60 frames per second
clock.tick(60)
pygame.quit()
pygame.sprite.spritecollide only works with a sprite as the first argument and a sprite group as the second argument. To check if the mouse collides with a duck, you can iterate over the duck_list with a for loop and call the collidepoint method of the current duck's rect:
if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
for duck in duck_list:
if duck.rect.collidepoint(event.pos): # event.pos is the mouse position.
score += 100
When i try to run the game the code tries to run a method for the wrong sprite. I think the line "player.handle_keys()" is the problem as when i run it, it says that it can't find a "handle_keys()" method for the "meteor" class. I haven't got a line to run a "meteor.handle_keys()" as this class should not have this method.
Here is the code:
import pygame
import random
# Define some colors
BLACK = ( 0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
bg = pygame.image.load("bg1.png")
class space_ship(pygame.sprite.Sprite):
def __init__(self, color, width, height):
super().__init__()
# Create an image of the space_ship1, and fill it with a color.
# This could also be an image loaded from the disk.
self.image = pygame.Surface([width, height])
self.image.fill(WHITE)
self.image.set_colorkey(WHITE)
self.rect = self.image.get_rect()
#draw image
self.image = pygame.image.load("player1.gif").convert()
# Draw the ellipse
#pygame.draw.ellipse(self.image, color, [0, 0, width, height])
# x and y coordinates
self.x = 500
self.y = 450
def handle_keys(self):
""" Handles Keys """
key = pygame.key.get_pressed()
dist = 5 # distance moved in 1 frame
if key[pygame.K_RIGHT]: # right key
self.x += dist # move right
elif key[pygame.K_LEFT]: # left key
self.x -= dist # move left
def draw(self, surface):
""" Draw on surface """
# blit yourself at your current position
surface.blit(self.image, (self.x, self.y))
class asteroid(pygame.sprite.Sprite):
def __init__(self, color, width, height):
super().__init__()
# Create an image of the space_ship1, and fill it with a color.
# This could also be an image loaded from the disk.
self.image = pygame.Surface([width, height])
self.image.fill(WHITE)
self.image.set_colorkey(WHITE)
self.rect = self.image.get_rect()
# Draw the ellipse
#pygame.draw.ellipse(self.image, color, [0, 0, width, height])
self.image = pygame.image.load("ast1.gif").convert()
# x and y coordinates
self.x = random.randint(50,950)
self.y = 10
def draw(self, surface):
""" Draw on surface """
# blit yourself at your current position
surface.blit(self.image, (self.x, self.y))
def fall(self):
dist = 5
self.y +=dist
if self.y > 600:
self.x = random.randint(50,950)
self.y = random.randint(-2000, -10)
def respawn(self):
self.y = -10
# Initialize Pygame
pygame.init()
# Set the height and width of the screen
screen_width = 1000
screen_height = 600
screen = pygame.display.set_mode([screen_width, screen_height])
# This is a list of 'sprites.' Each sprite in the program is
# added to this list.
# The list is managed by a class called 'Group.'
asteroid_list = pygame.sprite.Group()
# This is a list of every sprite.
# All asteroids and the player as well.
all_sprites_list = pygame.sprite.Group()
player = space_ship(RED, 20, 15)
all_sprites_list.add(player)
asteroid_1 = asteroid(BLACK, 40, 40)
asteroid_list.add(asteroid_1)
all_sprites_list.add(asteroid_1)
asteroid_2 = asteroid(BLACK, 40, 40)
asteroid_list.add(asteroid_2)
all_sprites_list.add(asteroid_2)
asteroid_3 = asteroid(BLACK,40, 40)
asteroid_list.add(asteroid_3)
all_sprites_list.add(asteroid_3)
asteroid_4 = asteroid(BLACK,40, 40)
asteroid_list.add(asteroid_4)
all_sprites_list.add(asteroid_4)
asteroid_5 = asteroid(BLACK,40, 40)
asteroid_list.add(asteroid_5)
all_sprites_list.add(asteroid_5)
asteroid_6 = asteroid(BLACK,40, 40)
asteroid_list.add(asteroid_6)
all_sprites_list.add(asteroid_6)
asteroid_7 = asteroid(BLACK,40, 40)
asteroid_list.add(asteroid_7)
all_sprites_list.add(asteroid_7)
asteroid_8 = asteroid(BLACK,40, 40)
asteroid_list.add(asteroid_8)
all_sprites_list.add(asteroid_list)
# Loop until the user clicks the close button.
done = False
# Used to manage how fast the screen updates
clock = pygame.time.Clock()
score = 0
# ----------------- Main Program Loop --------------------
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
#Call upon function
player.handle_keys()
# Clear the screen
screen.fill(WHITE)
#INSIDE OF THE GAME LOOP
screen.blit(bg, (0, 0))
# See if the player space_ship1 has collided with anything.
blocks_hit_list = pygame.sprite.spritecollide(player, asteroid_list, True)
# Check the list of collisions.
for player in blocks_hit_list:
score +=1
print(score)
# Draw all the spites
player.draw(screen)
asteroid_1.draw(screen)
asteroid_1.fall()
asteroid_2.draw(screen)
asteroid_2.fall()
asteroid_3.draw(screen)
asteroid_3.fall()
asteroid_4.draw(screen)
asteroid_4.fall()
asteroid_5.draw(screen)
asteroid_5.fall()
asteroid_6.draw(screen)
asteroid_6.fall()
asteroid_7.draw(screen)
asteroid_7.fall()
asteroid_8.draw(screen)
asteroid_8.fall()
#all_sprites_list.draw(screen)
# Limit to 60 frames per second
clock.tick(60)
# Go ahead and update the screen with what we've drawn.
pygame.display.flip()
pygame.quit()
You are overriding player in your for loop
# Check the list of collisions.
for player in blocks_hit_list:
score +=1
print(score)
change it to something else and all will be good
# Check the list of collisions.
for something_else in blocks_hit_list:
score +=1
print(score)
Enjoy
My problem with the code is that I created a sprite that is able to move a tile each time when an arrow key is pressed, the problem is when the sprite moves onto a tile that has a wall on it, it still goes onto the tile instead of staying on the tile that it is on. I can't seem to get the right collision detection code.
import pygame
import random
# Define some colors
black = ( 0, 0, 0)
white = ( 255, 255, 255)
red = ( 255, 0, 0)
GREEN = ( 0, 255, 0)
wall = ( 66, 66, 66)
# This class represents the ball
# It derives from the "Sprite" class in Pygame
class Main(pygame.sprite.Sprite):
walls = None
def __init__(self, filename):
# Calls the parent class (Sprite) constructor
pygame.sprite.Sprite.__init__(self)
# Creates the 'block' that will contain the image
self.image = pygame.image.load(filename).convert()
# Set background colour so its transparent
self.image.set_colorkey(black)
# Sets parameters so you can adjust the x and y values
self.rect = self.image.get_rect()
def update (self,):
# Moving left or right
self.rect.x += self.change_y
# Did something collide into wall ?
wall_hit_list = pygame.sprite.spritecollide(self, self.walls, False)
for wall in wall_hit_list:
# If we are moving right, set our right side to the left side of the item we hit
if self.change_y > 0:
self.rect.right = wall.rect.left
else:
# Otherwise if we are moving left, do the opposite
self.rect.left = wall.rect.right
# Move up/down
self.rect.y += self.change_x
# Check and see if we hit anything
wall_hit_list = pygame.sprite.spritecollide(self, self.walls, False)
for wall in wall_hit_list:
# Reset our position based on the top/bottom of the object.
if self.change_x > 0:
self.rect.bottom = wall.rect.top
else:
self.rect.top = wall.rect.bottom
class Wall(pygame.sprite.Sprite):
# Wall that the player can run into.
def __init__(self, filename):
# Constructor
pygame.sprite.Sprite.__init__(self)
# Make a wall
self.image = pygame.image.load(filename).convert()
# Sets parameters so you adjust the x and y values
self.rect = self.image.get_rect()
# Initialize Pygame
pygame.init()
# Set the height and width of the screen
screen_width = 700
screen_height = 400
screen = pygame.display.set_mode([screen_width, screen_height])
# List of all the sprites
all_sprites_list = pygame.sprite.Group ()
# List of the main sprite ( squirtle )
main_sprite = pygame.sprite.Group ()
# List of Walls
wall_list = pygame.sprite.Group ()
wall = Wall("wall2.png",)
wall.rect.x = 100
wall.rect.y = 150
wall_list.add(wall)
all_sprites_list.add(wall)
# Sets player to the class 'Main' which thanks to the parameter, is squirtle
Hero = Main ("Character.png")
player = Main ("Character.png")
# Spawns squirtle in a random position
Hero.rect.x = 4
Hero.rect.y = 1
# Adds squirtle to the lists that we made
main_sprite.add(Hero)
all_sprites_list.add(Hero)
#Loop until the user clicks the close button.
done = False
# Used to manage how fast the screen updates
clock = pygame.time.Clock()
# -------- Main Program Loop -----------
while done == False:
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
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
Hero.rect.x -= 50
elif event.key == pygame.K_RIGHT:
Hero.rect.x += 50
elif event.key == pygame.K_UP:
Hero.rect.y -= 50
elif event.key == pygame.K_DOWN:
Hero.rect.y += 50
# Clear the screen
screen.fill(white)
# Drawing Code
y_offset = 0
x_offset = 0
while x_offset < 750:
pygame.draw.line(screen,GREEN, [0+x_offset,0], [0+x_offset,500],1)
x_offset = x_offset + 50
while y_offset < 550:
pygame.draw.line(screen, GREEN, [0,0+y_offset], [700,0+y_offset],1)
y_offset = y_offset + 50
# Draw all the sprites
all_sprites_list.draw(screen)
pygame.display.flip ()
clock.tick (60)
pygame.quit ()`
First of all, you never call the update method of your sprites, so your collision check is never performed.
If you would call it, it would fail, because you try to read self.change_y, which you never set.
If you would, it would still fail, because you try to check the collision against the sprites in self.walls, but you never set it thus self.walls is always None.