Keyboard Unresponsive - python

I can't seem to find out why my keyboard work. I have tried changing the speed, changing the class, and swapped it out for using the mouse but I want more keyboard! No errors appear when I run it but the main player just stays in the top left and doesn't move. I've also duplicated this code with less bonus characters and it worked but once I add bonus and more levels, it fails. Any help would be greatly appreciated.
The link is for all the images and code.
https://drive.google.com/drive/folders/162vsO20kRoNBy6IJa3WgSq4D5ZB5PsI2?usp=sharing
import pygame
import random
BLACK = (0, 0, 0)
pygame.init()
class Block(pygame.sprite.Sprite):
# Constructor. Pass in the color of the block,
# and its x and y position
def __init__(self, color, width, height):
# 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):
# Constructor. Pass in the color of the block,
# and its x and y position
def __init__(self, x, y):
# 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.image.load("aboriginal.png")
# 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()
# Make our top-left corner the passed-in location.
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
class Bonus(pygame.sprite.Sprite):
# Constructor. Pass in the color of the block,
# and its x and y position
def __init__(self, pic):
# 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.image.load(pic)
# 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()
SCREEN_WIDTH = 700
SCREEN_HEIGHT = 400
screen = pygame.display.set_mode([SCREEN_WIDTH, SCREEN_HEIGHT])
pygame.display.set_caption(('Outback Steakhouse'))
background = pygame.image.load('winter.png')
background2 = pygame.image.load('timthumb.jpg')
background3 = pygame.image.load('winter.png')
background4 = pygame.image.load('timthumb.jpg')
background5 = pygame.image.load('rugbyStadium.png')
# sprites
block_list = pygame.sprite.Group()
bonus_list = pygame.sprite.Group()
all_sprites_list = pygame.sprite.Group()
for i in range(10):
# This represents a block
block = Block(BLACK, 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
block_list.add(block)
all_sprites_list.add(block)
# Create a player instance
player = Player(0,0)
all_sprites_list.add(player)
# Bonus instance
kiwi = Bonus('kiwi.png')
kiwi.rect.x = random.randrange(SCREEN_WIDTH - 64)
kiwi.rect.y = random.randrange(SCREEN_HEIGHT - 64)
bonus_list.add(kiwi)
all_sprites_list.add(kiwi)
done = False
clock = pygame.time.Clock()
font = pygame.font.Font(None, 36)
score = 0
level = 1
# -------- Main Program Loop -----------
while not done:
# ALL EVENT PROCESSING SHOULD GO BELOW THIS COMMENT
for event in pygame.event.get(): # User did something
if event.type == pygame.QUIT: # If user clicked close
done = True # Flag that we are done so we exit this loop
# 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)
# See if the player block has collided with anything including bonus
blocks_hit_list = pygame.sprite.spritecollide(player, block_list, True)
bonus_hit_list = pygame.sprite.spritecollide(player, bonus_list, True)
# Check the list of collisions.
for block in blocks_hit_list:
score += 1
print(score)
for bonus in bonus_hit_list:
score += 10
print(score)
# Check to see if all the blocks are gone.
# If they are, level up.
if len(block_list) == 0 and len(bonus_list) == 0:
# Add one to the level
level += 1
# Add more blocks. How many depends on the level.
# Also, an 'if' statement could be used to change what
# happens customized to levels 2, 3, 4, etc.
for i in range(level * 10):
# This represents a block
block = Block(BLACK, 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
block_list.add(block)
all_sprites_list.add(block)
for i in range(level):
if level == 1:
kiwi = Bonus('kiwi.png')
kiwi.rect.x = random.randrange(SCREEN_WIDTH - 64)
kiwi.rect.y = random.randrange(SCREEN_HEIGHT - 64)
bonus_list.add(kiwi)
all_sprites_list.add(kiwi)
if level == 2:
koala = Bonus('koala.png')
koala.rect.x = random.randrange(SCREEN_WIDTH - 64)
koala.rect.y = random.randrange(SCREEN_HEIGHT - 64)
bonus_list.add(koala)
all_sprites_list.add(koala)
if level == 3:
kangaroo = Bonus('kangaroo.png')
kangaroo.rect.x = random.randrange(SCREEN_WIDTH - 64)
kangaroo.rect.y = random.randrange(SCREEN_HEIGHT - 64)
bonus_list.add(kangaroo)
all_sprites_list.add(kangaroo)
if level == 4:
boomerang = Bonus('boomerang.png')
boomerang.rect.x = random.randrange(SCREEN_WIDTH - 64)
boomerang.rect.y = random.randrange(SCREEN_HEIGHT - 64)
bonus_list.add(boomerang)
all_sprites_list.add(boomerang)
if level == 5:
rugby = Bonus('rugby.png')
rugby.rect.x = random.randrange(SCREEN_WIDTH - 64)
rugby.rect.y = random.randrange(SCREEN_HEIGHT - 64)
bonus_list.add(rugby)
all_sprites_list.add(rugby)
# ALL GAME LOGIC SHOULD GO ABOVE THIS COMMENT
# ALL CODE TO DRAW SHOULD GO BELOW THIS COMMENT
# Clear the screen and add new images
if level == 1:
screen.fill(WHITE)
screen.blit(background, (0, 0))
message = font.render("Easy Peasy" , True, RED)
screen.blit(message, [300, 10])
elif level == 2:
screen.fill(WHITE)
screen.blit(background2, (0, 0))
elif level == 3:
screen.fill(WHITE)
screen.blit(background3, (0, 0))
elif level == 4:
screen.fill(WHITE)
screen.blit(background4, (0, 0))
elif level == 5:
screen.fill(WHITE)
screen.blit(background5, (0,0))
else:
pygame.quit()
# Draw all the spites
all_sprites_list.draw(screen)
text = font.render("Score: " + str(score), True, BLACK)
screen.blit(text, [10, 10])
text = font.render("Level: " + str(level), True, BLACK)
screen.blit(text, [10, 40])
# ALL CODE TO DRAW SHOULD GO ABOVE THIS COMMENT
# 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()

The player doesn't move because you don't call the update method in the application loop:
while not done:
# [...]
player.update()

Related

Only 2 sprites added on screen pygame

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)

How do I assign an image to each sprite?

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()

Pygame: bullets sticks to the screen

My problem is very simple. The bullets I fire sticks to the screen if I shoot fast. If I shoot slowly, they don't stick. Anyone have an idea how this phenomenon occurs?
screenshot of the bullets sticking to the screen
Below I have entered the code. I follow this default game flowchart:
I am curious about the origin of the problem. Is it the code or hardware?
import sys
import pygame
from pygame.sprite import Sprite
from pygame.sprite import Group
# pygame initializing
pygame.init()
#create the screen surface
screen = pygame.display.set_mode((800, 700))
class Color():
def __init__(self):
self.black = (0, 0, 0)
self.white = (255, 255, 255)
self.red = (255, 0, 0)
self.green = (0, 255, 0)
self.green_lambda = (10, 255, 150)
self.blue = (0, 0, 255)
# set up the colors
color = Color() # make an instance of this class - this makes some colors available
class Spaceship(Sprite):
"""
This class represents the Spaceship.
It derives from the "Sprite" class in Pygame.
"""
def __init__(self):
""" Constructor"""
# Call the parent class (Sprite) constructor
super().__init__()
width = 22
height = 32
self.screen = screen
self.image = pygame.Surface((width, height))
self.image.fill(color.black)
self.image.set_colorkey(color.black)
pygame.draw.polygon(self.image, color.green_lambda, [[10,0],[15,22],[20,30],[10,27],[0,30],[5,22]],2)
self.rect = self.image.get_rect()
self.screen_rect = self.screen.get_rect()
self.rect.centerx = self.screen_rect.centerx
self.rect.bottom = self.screen_rect.bottom
# As the rect method only take integers we store a
# This value is only used at the beginning, i.e. before the game loop starts
self.center_x = self.rect.centerx
self.center_y = self.rect.centery
class Bullet(Sprite):
"""
This class represents the bullets.
It derives from the "Sprite" class in Pygame.
"""
def __init__(self):
# Call the parent class (Sprite) constructor
super().__init__()
self.image = pygame.Surface((8,10))
self.image.fill(color.red)
self.image.set_colorkey((color.red))
pygame.draw.ellipse(self.image, color.green, [1, 0, 5, 8], 2)
self.rect = self.image.get_rect()
self.rect.centerx = defender.rect.centerx
self.rect.bottom = defender.rect.top
# def function to move the bullets
def update_pos(self):
self.rect.y -= bullet_speed
# create spaceship instance
defender = Spaceship()
# create group to store sprites in
all_sprites_list = Group()
all_sprites_list.add(defender)
ship_speed = 0.5
bullet_speed = 3
def run_game():
m_right = False
m_left = False
m_up = False
m_down = False
new_bullet = False
while True:
"""This is the user interaction section"""
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
sys.exit()
elif event.key == pygame.K_RIGHT:
m_right = True
elif event.key == pygame.K_LEFT:
m_left = True
elif event.key == pygame.K_UP:
m_up = True
elif event.key == pygame.K_DOWN:
m_down = True
elif event.key == pygame.K_SPACE:
new_bullet = Bullet()
#print(dir(new_bullet))
all_sprites_list.add(new_bullet)
if event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT:
m_right = False
elif event.key == pygame.K_LEFT:
m_left = False
elif event.key == pygame.K_UP:
m_up = False
elif event.key == pygame.K_DOWN:
m_down = False
"""Below is the game logic, which gets input from the user interaction
section and more"""
# Movement of spaceship depending on the flag boolean value and on screen width and height
if m_right and defender.rect.right < defender.screen_rect.right:
defender.center_x += ship_speed
if m_left and defender.rect.left > defender.screen_rect.left:
defender.center_x -= ship_speed
if m_up and defender.rect.top > defender.screen_rect.top:
defender.center_y -= ship_speed
if m_down and defender.rect.bottom < defender.screen_rect.bottom:
defender.center_y += ship_speed
# The cumulative value (which is a float number) for the spaceships movement
# is given to the spaceship rect variable (which can only be integer) now.
# This enables fine adjusting of the speed
defender.rect.centerx = defender.center_x
defender.rect.centery = defender.center_y
all_sprites_list.update()
screen.fill(color.black)
if new_bullet:
new_bullet.update_pos()
# Below the bullets which leaves the screen display are deleted
if new_bullet.rect.bottom < defender.screen_rect.top:
all_sprites_list.remove(new_bullet)
all_sprites_list.draw(screen)
print(all_sprites_list)
pygame.display.flip()
run_game()
instead of just updating the position of new_bullet
# if new_bullet:
# new_bullet.update_pos()
# # Below the bullets which leaves the screen display are deleted
# if new_bullet.rect.bottom < defender.screen_rect.top:
# all_sprites_list.remove(new_bullet)
update the position of all bullets
for bullet in all_sprites_list:
if isinstance(bullet,Bullet):
bullet.update_pos()
if bullet.rect.bottom < defender.screen_rect.top:
all_sprites_list.remove(bullet)
del bullet
Joran Beasley's answer is correct. I'd just like to point out that you can also put the behavior of the sprites into their update methods which get called automatically when you call all_sprites_list.update(). You can actually move most of the code in the while loop to the update methods.
I've got an example with these changes and some more tips in the comments (a quick code review):
import pygame
from pygame.sprite import Sprite
from pygame.sprite import Group
# I'd just define some global constants for the colors.
BLACK = (0, 0, 0)
GREEN = (0, 255, 0)
GREEN_LAMBDA = (10, 255, 150)
class Spaceship(Sprite):
"""This class represents the Spaceship."""
def __init__(self, screen):
"""Constructor"""
super().__init__()
self.screen = screen
# pygame.SRCALPHA makes the surface transparent.
self.image = pygame.Surface((22, 32), pygame.SRCALPHA)
pygame.draw.polygon(
self.image, GREEN_LAMBDA,
[[10,0],[15,22],[20,30],[10,27],[0,30],[5,22]], 2
)
self.screen_rect = self.screen.get_rect()
# You can pass the position as the midbottom argument to `get_rect`.
self.rect = self.image.get_rect(midbottom=self.screen_rect.midbottom)
self.center_x = self.rect.centerx
self.center_y = self.rect.centery
# I've removed the `m_right`, etc. variables and just set the speed
# of the sprite in the event loop.
self.max_speed = 3.5
self.speed_x = 0
self.speed_y = 0
def update(self):
# Move the sprite.
self.center_x += self.speed_x
self.center_y += self.speed_y
self.rect.centerx = self.center_x
self.rect.centery = self.center_y
# Keep the sprite on the screen.
if not self.screen_rect.contains(self.rect):
self.rect.clamp_ip(self.screen_rect)
self.center_x, self.center_y = self.rect.center
class Bullet(Sprite):
"""This class represents the bullets."""
def __init__(self, pos):
super().__init__()
self.image = pygame.Surface((8, 10), pygame.SRCALPHA)
pygame.draw.ellipse(self.image, GREEN, [1, 0, 5, 8], 2)
self.rect = self.image.get_rect(midbottom=pos)
self.speed = 3 # The speed is now an attribute.
def update(self):
self.rect.y -= self.speed
if self.rect.top < 0:
self.kill() # Remove the sprite from all groups.
def run_game():
pygame.init()
screen = pygame.display.set_mode((800, 700))
clock = pygame.time.Clock() # Use a clock to limit the frame rate.
defender = Spaceship(screen)
all_sprites = Group() # Changed the name because groups are not lists.
all_sprites.add(defender)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
return
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
return
elif event.key == pygame.K_RIGHT:
defender.speed_x = defender.max_speed
elif event.key == pygame.K_LEFT:
defender.speed_x = -defender.max_speed
elif event.key == pygame.K_UP:
defender.speed_y = -defender.max_speed
elif event.key == pygame.K_DOWN:
defender.speed_y = defender.max_speed
elif event.key == pygame.K_SPACE:
new_bullet = Bullet(defender.rect.midtop) # Pass the pos.
all_sprites.add(new_bullet)
elif event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT and defender.speed_x > 0:
defender.speed_x = 0
elif event.key == pygame.K_LEFT and defender.speed_x < 0:
defender.speed_x = 0
elif event.key == pygame.K_UP and defender.speed_y < 0:
defender.speed_y = 0
elif event.key == pygame.K_DOWN and defender.speed_y > 0:
defender.speed_y = 0
all_sprites.update() # Calls the update methods of all sprites.
screen.fill(BLACK)
all_sprites.draw(screen)
pygame.display.flip()
clock.tick(60) # Limit the frame rate to 60 FPS.
run_game()

Pygame failing. Badly

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.

Collision Detection With 'jump/not smooth'' movement

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.

Categories