Pygame animation list index continuously goes out of range - python

I followed a clear code tutorial to make a platformer and ended up finishing it, however one thing always continously messed up. That being the animation, at times the game just would not run and would only run in debug mode due to the animation list being out of index which makes no sense to me since every item in the list is accounted for. Below is my player.py which has all of the functions and such that the video mentions. If more information is needed I will gladly provide it. (the animation part is specifically erroring at self.image = self.animations['idle'][self.frame_index])
import pygame
from support import import_folder
class Player(pygame.sprite.Sprite):
def __init__(self,pos,surface,create_jump_particles):
super().__init__()
self.import_character_assets()
self.frame_index = 0
self.animation_speed = 0.15
self.image = self.animations['idle'][self.frame_index]
self.rect = self.image.get_rect(topleft = pos)
# dust particles
self.import_dust_run_particles()
self.dust_frame_index = 0
self.dust_animation_speed = 0.15
self.display_surface = surface
self.create_jump_particles = create_jump_particles
# player movement
self.direction = pygame.math.Vector2(0,0)
self.speed = 8
self.gravity = 0.8
self.jump_speed = -16
# player status
self.status = 'idle'
self.facing_right = True
self.on_ground = False
self.on_ceiling = False
self.on_left = False
self.on_right = False
def import_character_assets(self):
character_path = '../graphics/character/'
self.animations = {'idle':[],'run':[],'jump':[],'fall':[]}
for animation in self.animations.keys():
full_path = character_path + animation
self.animations[animation] = import_folder(full_path)
def import_dust_run_particles(self):
self.dust_run_particles = import_folder('../graphics/character/dust_particles/run')
def animate(self):
animation = self.animations[self.status]
# loop over frame index
self.frame_index += self.animation_speed
if self.frame_index >= len(animation):
self.frame_index = 0
image = animation[int(self.frame_index)]
if self.facing_right:
self.image = image
else:
flipped_image = pygame.transform.flip(image,True,False)
self.image = flipped_image
# set the rect
if self.on_ground and self.on_right:
self.rect = self.image.get_rect(bottomright = self.rect.bottomright)
elif self.on_ground and self.on_left:
self.rect = self.image.get_rect(bottomleft = self.rect.bottomleft)
elif self.on_ground:
self.rect = self.image.get_rect(midbottom = self.rect.midbottom)
elif self.on_ceiling and self.on_right:
self.rect = self.image.get_rect(topright = self.rect.topright)
elif self.on_ceiling and self.on_left:
self.rect = self.image.get_rect(topleft = self.rect.topleft)
elif self.on_ceiling:
self.rect = self.image.get_rect(midtop = self.rect.midtop)
def run_dust_animation(self):
if self.status == 'run' and self.on_ground:
self.dust_frame_index += self.dust_animation_speed
if self.dust_frame_index >= len(self.dust_run_particles):
self.dust_frame_index = 0
dust_particle = self.dust_run_particles[int(self.dust_frame_index)]
if self.facing_right:
pos = self.rect.bottomleft - pygame.math.Vector2(6,10)
self.display_surface.blit(dust_particle,pos)
else:
pos = self.rect.bottomright - pygame.math.Vector2(6,10)
flipped_dust_particle = pygame.transform.flip(dust_particle,True,False)
self.display_surface.blit(flipped_dust_particle,pos)
def get_input(self):
keys = pygame.key.get_pressed()
if keys[pygame.K_RIGHT]:
self.direction.x = 1
self.facing_right = True
elif keys[pygame.K_LEFT]:
self.direction.x = -1
self.facing_right = False
else:
self.direction.x = 0
if keys[pygame.K_SPACE] and self.on_ground:
self.jump()
self.create_jump_particles(self.rect.midbottom)
def get_status(self):
if self.direction.y < 0:
self.status = 'jump'
elif self.direction.y > 1:
self.status = 'fall'
else:
if self.direction.x != 0:
self.status = 'run'
else:
self.status = 'idle'
def apply_gravity(self):
self.direction.y += self.gravity
self.rect.y += self.direction.y
def jump(self):
self.direction.y = self.jump_speed
def update(self):
self.get_input()
self.get_status()
self.animate()
self.run_dust_animation()
I've tried everything, I've even gone to his website and downloaded his prototype and tried adding my own files to it and it still returns the same error. Whats supposed to be happening is that my character does an animation depending on which state they are in.

So it's likely that the code is not loading any of the animation frames for the 'idle' character animation.
The initialisation code first loads all the assets:
class Player(pygame.sprite.Sprite):
def __init__(self,pos,surface,create_jump_particles):
super().__init__()
self.import_character_assets()
Where self.import_character_assets() is:
def import_character_assets(self):
character_path = '../graphics/character/'
self.animations = {'idle':[],'run':[],'jump':[],'fall':[]}
for animation in self.animations.keys():
full_path = character_path + animation
self.animations[animation] = import_folder(full_path)
Which is iterating through 'idle', 'run', 'jump', 'fall', loading images from '../graphics/character/idle', '../graphics/character/run', etc. into a dictionary-of-lists.
We don't have the code for import_folder(), but it's obviously intended to load some set of images.
After importing, the self.animations dictionary is expected to have at least a single image in self.animations['idle']. This is because the __init__() is defaulting to 'idle', and index 0:
self.frame_index = 0
self.animation_speed = 0.15
self.image = self.animations['idle'][self.frame_index] # <<-- HERE, 0
So we can conclude that because we know, self.animations['idle'] is out of bounds, even on [0], no images were loaded.
Check that there are images available for this. Or maybe the filenames are not what's expected (e.g.: .jpg, not .png), or some other file-system error (e.g.: read only, zero byte files, ... ). Maybe the load-path is incorrect?
It might be a good idea to check the load, and write an error:
def import_character_assets(self):
character_path = '../graphics/character/'
self.animations = {'idle':[],'run':[],'jump':[],'fall':[]}
for animation in self.animations.keys():
full_path = character_path + animation
self.animations[animation] = import_folder(full_path)
# check we loaded something
if ( len( self.animations[animation] ) == 0 ):
print( "Failed to load any animations for \"" + animation + "\" type" )

Related

Animation doubles duration every time it appears in pygame

I'm fairly new to coding and I am working on a little game with pygame. I have a Sprite for an explosion animation, the first times it appears it works great for the whole game, but once you are playing a second or third game the explosions lasts more every time even though I empty the sprite group every time the game restarts, I think the problem might be that the explosion update function doesn't works well for more than one game, but I don't really know how to fix it. Thanks in advance for the help!
class Explosion(pygame.sprite.Sprite):
expl_img = []
def __init__(self, center):
pygame.sprite.Sprite.__init__(self)
self.image = self.cargaImagenes()
self.rect = self.image.get_rect()
self.rect.center = center
self.frame = 0
self.last_update = pygame.time.get_ticks()
self.frame_rate = 50
def update(self):
now = pygame.time.get_ticks()
if now -self.last_update > self.frame_rate:
self.last_update = now
self.frame +=1
if self.frame == len(self.expl_img):
self.kill()
else:
center = self.rect.center
self.image = self.expl_img[self.frame]
self.rect = self.image.get_rect()
self.rect.center = center
def cargaImagenes(self):
for i in range(9):
filename = 'regularExplosion0{}.png'.format(i)
img = pygame.image.load(path.join(img_dir, filename)).convert()
img.set_colorkey(BLACK)
img_def = pygame.transform.scale(img, (75, 75))
self.expl_img.append(img_def)
return self.expl_img[0]
Here is where the explosion appears:
if self.player.estado == self.player.Estado.volando:
anticolision = False
colisiones = pygame.sprite.spritecollide(self.player, self.asteroides, True, pygame.sprite.collide_circle)
for colision in colisiones:
start_ticks = pygame.time.get_ticks()
if colision and not anticolision:
anticolision = True
print("anticolision true")
expl = Explosion(colision.rect.center)
self.explosionSound.play()
self.all_sprites.add(expl)
self.vidas -= 1
segundos = (pygame.time.get_ticks()-start_ticks)/1000
if segundos > 3:
anticolision = False
print("anticolision false")
elif colision and anticolision:
pass
if self.vidas == 0:
self.gameOver()
running= False
self.cargaImagenes() is called every time when you create a new instance of Explosion. Therefore the number of elements in the class variable expl_img grows continuously. Only add new items to the list when the list is empty:
class Explosion(pygame.sprite.Sprite):
expl_img = []
# [...]
def cargaImagenes(self):
if not expl_img: # <---
for i in range(9):
filename = 'regularExplosion0{}.png'.format(i)
img = pygame.image.load(path.join(img_dir, filename)).convert()
img.set_colorkey(BLACK)
img_def = pygame.transform.scale(img, (75, 75))
self.expl_img.append(img_def)
return self.expl_img[0]

Trying to delete sprite with kill(), but sprite isn't disappearing

This is my first time asking here, so sorry if I don't ask very well.
Lately I've been trying to make a Terraria-type game where you can break/place blocks in a randomly generated landscape. While trying to implement the breaking-block mechanic (which is triggered by clicking on a block), I ran into an issue. The block no longer became solid (that's a good thing), but the block's image is still there, and I can walk right through it.
A visual example:
Before breaking block vs.
After breaking block
Here's the code
Main file (hopefully only the relevant bits):
# Imports
import pygame as pg
import json
import sys
import random
import os
from settings import *
from world_handler import *
# Initialize pygame
pg.mixer.pre_init()
pg.init()
# Fonts
# NOTE: put fonts in here
# Helper functions
def load_image(file_path):
# Loads an image
img = pg.image.load(file_path)
return img
def play_sound(sound, loops=0, maxtime=0, fade_ms=0):
# Plays some audio
if sound_on:
sound.play(loops, maxtime, fade_ms)
def play_music():
# Plays background music
if sound_on:
pg.mixer.music.play(-1)
# File paths
current_path = os.path.dirname(__file__)
assets_path = os.path.join(current_path, "assets")
image_path = os.path.join(assets_path, "img")
# Images
player_standing = load_image((os.path.join(image_path, "player", "standing", "player-standing.png")))
player_walking1 = load_image((os.path.join(image_path, "player", "walking", "player-walking1.png")))
player_walking2 = load_image((os.path.join(image_path, "player", "walking", "player-walking2.png")))
player_walking3 = load_image((os.path.join(image_path, "player", "walking", "player-walking3.png")))
player_walking4 = load_image((os.path.join(image_path, "player", "walking", "player-walking4.png")))
player_jumping = load_image((os.path.join(image_path, "player", "jumping", "player-jumping.png")))
player_images = {"walking": [player_walking1, player_walking2, player_walking3, player_walking4],
"jumping": player_jumping,
"standing": player_standing}
block_images = {"Grass": load_image((os.path.join(image_path, "blocks", "grass.png"))),
"Dirt": load_image((os.path.join(image_path, "blocks", "dirt.png"))),
"Stone": load_image((os.path.join(image_path, "blocks", "stone.png")))}
cursor_tracker = load_image((os.path.join(image_path, "misc", "clear-single-pixel.png")))
class Entity(pg.sprite.Sprite):
def __init__(self, x, y, image):
# Initialize an entity
super().__init__()
self.image = image
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.vx = 0
self.vy = 0
def apply_gravity(self, world):
# Let the enemy be affected by gravity
self.vy += world.gravity
self.vy = min(self.vy, world.terminal_velocity)
class Block(Entity):
def __init__(self, x, y, image):
# Initialize the block
super().__init__(x, y, image)
class Cursor(Entity):
def __init__(self, x, y, image):
# Initialize the invisible mouse cursor object
# This will be used to track where the mouse goes and if the mouse is on a block
super().__init__(x, y, image)
self.on_block = False
def follow_mouse(self):
# Make object follow the mouse
self.mouse_x, self.mouse_y = pg.mouse.get_pos()
self.rect.x = self.mouse_x
self.rect.y = self.mouse_y
def detect_block_collision(self, world):
# Detects collsion between cursor tracker and a block
hit_list = pg.sprite.spritecollide(self, world.blocks, True)
if len(hit_list) > 0:
pass
def update(self, world):
# Update the cursor object
self.follow_mouse()
world.active_sprites.add(self)
class Player(Entity):
def __init__(self, images):
# Initialize the player
super().__init__(0, 0, images["standing"])
# Images in each direction
self.image_standing_right = images["standing"]
self.image_standing_left = pg.transform.flip(self.image_standing_right, 1, 0)
self.images_walking_right = images["walking"]
self.images_walking_left = [pg.transform.flip(img, 1, 0) for img in self.images_walking_right]
self.image_jumping_right = images["jumping"]
self.image_jumping_left = pg.transform.flip(self.image_jumping_right, 1, 0)
# Player variables
self.running_images = self.images_walking_right
self.image_index = 0
self.steps = 0
self.speed = 3.5
self.jump_power = 12
self.vx = 0
self.vy = 0
self.direction = "right"
self.on_ground = True
self.score = 0
self.health = 100
self.max_health = 100
self.invincibility = 0
def move_left(self):
# Move to the left
self.vx = -self.speed + 0.9
self.direction = "left"
def move_right(self):
# Move to the rightS
self.vx = self.speed
self.direction = "right"
def stop(self):
# Stop it right there
self.vx = 0
def jump(self, blocks):
# Jump up, jump up, and get down
self.rect.y += 1
hit_list = pg.sprite.spritecollide(self, blocks, False)
if len(hit_list) > 0:
self.vy = -1 * self.jump_power
self.rect.y -= 1
def check_world_boundaries(self, world):
# Make sure the player doesn"t walk off the world
if self.rect.left < 0:
self.rect.left = 0
elif self.rect.right > world.width:
self.rect.right = world.width
def move_and_process_blocks(self, blocks):
# Detect block collisions
# Block side collisions
self.rect.x += self.vx
hit_list = pg.sprite.spritecollide(self, blocks, False)
for block in hit_list:
if self.vx > 0:
self.rect.right = block.rect.left
self.vx = 0
elif self.vx < 0:
self.rect.left = block.rect.right
self.vx = 0
self.on_ground = False
# Block top and bottom collisions
self.rect.y += self.vy + 1 # The +1 isn"t necessary, but it helps
hit_list = pg.sprite.spritecollide(self, blocks, False)
for block in hit_list:
if self.vy > 0:
self.rect.bottom = block.rect.top
self.on_ground = True
self.vy = 0
elif self.vy < 0:
self.rect.top = block.rect.bottom
self.on_ground = True
self.vy = 0
def set_image(self):
# Set images and animate
if self.on_ground:
if self.vx != 0:
if self.direction == "right":
self.walking_images = self.images_walking_right
elif self.direction == "left":
self.walking_images = self.images_walking_left
self.steps = (self.steps + 1) % self.speed
if self.steps == 0:
self.image_index = (self.image_index + 1) % len(self.walking_images)
self.image = self.walking_images[self.image_index]
else:
if self.direction == "right":
self.image = self.image_standing_right
elif self.direction == "left":
self.image = self.image_standing_left
else:
if self.direction == "right":
self.image = self.image_jumping_right
elif self.direction == "left":
self.image = self.image_jumping_left
def die(self):
# D E D
pass
def check_block_breaks(self, blocks):
# Break a block
# mouse_pos = pg.mouse.get_pos()
# for block in blocks:
# if block.rect.collidepoint(mouse_pos):
# print("hi")
pass
def respawn(self, world):
# Hey, you"re back!
self.rect.x = world.start_x
self.rect.y = world.start_y
self.health = self.max_health
self.invincibility = 0
self.direction = "right"
def update(self, world):
# Constantly update the player
self.apply_gravity(world)
self.move_and_process_blocks(world.blocks)
self.check_world_boundaries(world)
self.set_image()
self.check_block_breaks(world.blocks)
if self.health > 0:
if self.invincibility > 0:
self.invincibility -= 1
else:
self.die()
class Game():
def __init__(self):
# Initialize the game itself
self.window = pg.display.set_mode([WINDOWWIDTH, WINDOWHEIGHT])
pg.display.set_caption(TITLE)
self.clock = pg.time.Clock()
self.done = False
self.reset()
def start(self):
# Start the whole thing up
self.world = World(worlds[self.current_world])
self.cursor = Cursor(0, 0, cursor_tracker)
self.world.reset()
self.player.respawn(self.world)
def reset(self):
# Reset the game
self.player = Player(player_images)
self.current_world = 0
self.start()
def update(self):
# Update things in the game
self.player.update(self.world)
self.cursor.update(self.world)
if self.player.health <= 0:
self.player.respawn(self.world)
def calculate_offset(self):
# Calculate x/y coordinates after screen scrolls
x = -1 * self.player.rect.centerx + WINDOWWIDTH / 2
if self.player.rect.centerx < WINDOWWIDTH / 2:
x = 0
elif self.player.rect.centerx > self.world.width - WINDOWWIDTH / 2:
x = -1 * self.world.width + WINDOWWIDTH
y = -1 * self.player.rect.centery + WINDOWHEIGHT / 2
if self.player.rect.centery < WINDOWHEIGHT / 2:
y = 0
elif self.player.rect.centery > self.world.height - WINDOWHEIGHT / 2:
y = -1 * self.world.height + WINDOWHEIGHT
return x, y
def draw(self):
# Draw sprites to the screen
self.offset_x, self.offset_y = self.calculate_offset()
self.world.active_layer.fill(TRANSPARENT)
self.world.active_sprites.draw(self.world.active_layer)
if self.player.invincibility % 3 < 2:
self.world.active_layer.blit(self.player.image, [self.player.rect.x, self.player.rect.y])
self.window.blit(self.world.background_layer, [self.offset_x / 3, self.offset_y])
self.window.blit(self.world.inactive_layer, [self.offset_x, self.offset_y])
self.window.blit(self.world.active_layer, [self.offset_x, self.offset_y])
self.offset_cursor_x = self.cursor.rect.x - self.offset_x
self.offset_cursor_y = self.cursor.rect.y - self.offset_y
self.cursor.rect.x = self.offset_cursor_x
self.cursor.rect.y = self.offset_cursor_y
pg.display.update(0, 0, WINDOWWIDTH, WINDOWHEIGHT)
def process_events(self):
# Handle events (key presses, mouse clicks, etc)
for event in pg.event.get():
if event.type == pg.QUIT:
self.done = True
elif event.type == pg.KEYDOWN:
# Jump
if event.key == JUMP:
self.player.jump(self.world.blocks)
# Debug reset
elif event.key == pg.K_r:
self.reset()
# Debug close
elif event.key == pg.K_q:
self.done = True
# Break a block if you click on it
if event.type == pg.MOUSEBUTTONDOWN:
# for block in self.world.blocks:
# if block.rect.collidepoint(self.offset_cursor_x, self.offset_cursor_y):
# block.kill()
self.cursor.detect_block_collision(self.world)
pressed = pg.key.get_pressed()
if pressed[LEFT]:
self.player.move_left()
elif pressed[RIGHT]:
self.player.move_right()
else:
self.player.stop()
def loop(self):
# Loop through essential functions
while not self.done:
self.process_events()
self.update()
self.draw()
self.clock.tick(FPS)
if __name__ == "__main__":
# Begin the loop and pre-initialize the game
game = Game()
game.start()
game.loop()
pg.quit()
sys.exit()
World Handler (generated blocks and adds them to groups):
Some parts are commented out because they serve no purpose yet, but will soon.
# Imports
import pygame as pg
import json
import random
import os
from settings import *
from main import *
# Initialize pygame
pg.init()
class World():
def __init__(self, file_path):
# Initialize the world
# Starting entities
self.starting_blocks = []
# Entity groups
self.blocks = pg.sprite.Group()
# Sprite groups (active/inactive)
self.active_sprites = pg.sprite.Group()
self.inactive_sprites = pg.sprite.Group()
# Read the world json file
with open(file_path, "r") as f:
data = f.read()
map_data = json.loads(data)
# World width and height
self.width = map_data["width"] * GRID_SIZE
self.height = map_data["height"] * GRID_SIZE
# Player start position
self.start_x = map_data["start"][0] * GRID_SIZE
self.start_y = map_data["start"][1] * GRID_SIZE
# Load blocks
for item in map_data["blocks"]:
x, y = item[0] * GRID_SIZE, item[1] * GRID_SIZE
img = block_images[item[2]]
self.starting_blocks.append(Block(x, y, img))
# Layers
self.background_layer = pg.Surface([self.width, self.height], pg.SRCALPHA, 32)
self.inactive_layer = pg.Surface([self.width, self.height], pg.SRCALPHA, 32)
self.active_layer = pg.Surface([self.width, self.height], pg.SRCALPHA, 32)
# Load background color
if map_data["bg-color"] != "":
self.background_layer.fill(map_data["bg-color"])
# Load background image
# if map_data["bg-image"] != "":
# bg_image = pg.image.load(map_data["bg-image"]).convert_alpha()
#
# if map_data["bg-fill-y"]:
# h = bg_image.get_height()
# w = int(bg_image.get_width() * WINDOWHEIGHT / h)
# bg_image = pg.transform.scale(bg_image, (w, WINDOWHEIGHT))
#
# if "top" in map_data["bg-position"]:
# start_y = 0
# elif "bottom" in map_data["bg-postion"]:
# start_y = self.height = bg_image.get_height()
#
# if map_data["bg-repeat-x"]:
# for x in range(0, self.width, bg_image.get_width()):
# self.background_layer.blit(bg_image, [x, start_y])
# else:
# self.background_layer.blit(bg_image, [0, start_y])
# Load background music
# pg.mixer.music.load(map_data["music"])
# Set the world's gravity strength and terminal velocity
self.gravity = map_data["gravity"]
self.terminal_velocity = map_data["terminal-velocity"]
# Grass generator
if map_data["gen-type"] == "earth":
gen_loop = map_data["width"]
x = 0
y = 56 * GRID_SIZE # The general y coordinate for block placing
y_gen = 56 * GRID_SIZE # Stored to be referenced in order to make a smoother landscape
for i in range (0, map_data["width"]):
# Generate grass
img = block_images["Grass"]
self.starting_blocks.append(Block(x, y, img))
y += GRID_SIZE
# Generate dirt
for i in range(0, 6):
img = block_images["Dirt"]
self.starting_blocks.append(Block(x, y, img))
y += GRID_SIZE
# Generate stone
for i in range(1, int((self.height / GRID_SIZE))):
img = block_images["Stone"]
self.starting_blocks.append(Block(x, y, img))
y += GRID_SIZE
y = y_gen
x += GRID_SIZE
gen_loop -= 1
# Randomly decide what the next grass' y will be in relation to the previous one
random_grass = random.randint(0, 5)
# The lowest point you'll find a block of grass
lowest_grass_y = 53 * GRID_SIZE
# How extreme the changes in block heights will be
# 0 is flat, 1 will have pretty smooth terrain, while something like 10 would be super steep
gen_extremity = 1
# Keep the grass at the same y
if random_grass == 0 or random_grass == 1 or random_grass == 2 or random_grass == 3:
gen_loop -= 1
if y <= lowest_grass_y:
y += GRID_SIZE
# Increase y
elif random_grass == 4:
y_gen += GRID_SIZE * gen_extremity
if y <= lowest_grass_y:
y += GRID_SIZE
# Decrease y
elif random_grass == 5:
y_gen -= GRID_SIZE * gen_extremity
if y <= lowest_grass_y:
y += GRID_SIZE
else:
raise ValueError("How did we get here? Grass generator somehow generated an invalid number.")
# Add starting entities to their groups
self.blocks.add(self.starting_blocks)
# Add sprites to inactive/active sprite groups
self.inactive_sprites.add(self.blocks)
# Does... something?
for s in self.active_sprites:
s.image.convert()
for s in self.inactive_sprites:
s.image.convert()
# Draw inactive sprites to the inactive layer
self.inactive_sprites.draw(self.inactive_layer)
# Convert layers
self.background_layer.convert()
self.inactive_layer.convert()
self.active_layer.convert()
Setting file (to help you recreate the issue and find out what's going on
# Imports
import pygame as pg
import os
# File paths
current_path = os.path.dirname(__file__)
assets_path = os.path.join(current_path, 'assets')
image_path = os.path.join(assets_path, 'img')
# Window settings
TITLE = "Mooncraft"
WINDOWWIDTH = 960
WINDOWHEIGHT = 640
FPS = 60
GRID_SIZE = 32
# Options
sound_on = True
# Controls
LEFT = pg.K_a
RIGHT = pg.K_d
JUMP = pg.K_SPACE
# Colors
TRANSPARENT = (0, 0, 0, 0)
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
# World files
worlds = [(os.path.join(assets_path, 'worlds', 'earth.json'))]
If someone could explain what I'm doing wrong, it would be much appreciated.
Update 2: Added player class and settings file to help anyone willing to assist me find the issue.
From just a glance, it looks like you might not be clearing the screen at any point in the update loop, but rather drawing over what was already there. This would result in the block still being visible, but not actually there. Try adding screen.fill(#Color here) before flipping the display. Also try using pygame.display.update() instead of pygame.display.flip()
You can do this:
all_sprites = pg.sprite.Group()
all_sprites.add(your_sprite)
#your event:
all_sprites.remove(your_sprite)

Why isn't my pygame display displaying anything?

I am working on a program that evolves creatures over time using a genetic algorithm. However, for some reason, my pygame display stopped working and I have absolutely no idea why. When I run the program, the window opens but then it just sits on a black screen. I have tested to see where the program gets to and about 38 creatures die then nothing happens. However, these creatures should be displaying before their deaths also, but they aren't.Any help would be wonderful! Thank you for all your time!
Here's my code:
import numpy as np
import pygame
import random
#Initializes Pygame & Creates Window
pygame.init()
backgroundColor = (255, 255, 255)
screenSize = (800, 600)
screen = pygame.display.set_mode(screenSize)
pygame.display.set_caption("Genetic Algorithm")
screen.fill(backgroundColor)
clock = pygame.time.Clock()
#Loads Images & Rectangles
creaturePNG = pygame.image.load("Creature.png").convert_alpha()
foodPNG = pygame.image.load("Food.png").convert_alpha()
#Establishes Size Of Population
creatureCount = 40
deadCreatures = []
numGenerations = 10
#Generates Random 12 Digit DNA For First Generation
def initialDNA():
while True:
randomDNA = ""
total = 0
for i in range(12):
digit = random.randint(1, 9)
total += digit
digit = str(digit)
randomDNA = randomDNA + digit
if total <= 60:
break
return randomDNA
def reproduce(deadCreatureList, creatureCount):
reproducingCreatures = deadCreatureList[0.5*creatureCount:creatureCount]
for i in range(0.25*creatureCount):
creature1 = reproducingCreatures[0]
del reproducingCreatures[0]
creature2 = reproducingCreatures[0]
del reproducingCreatures[0]
DNA1 = str(creature1.DNA)
DNA2 = str(creature2.DNA)
crosspoint = random.randint(0, 12)
newDNA1 = int(DNA1[0:crosspoint] + DNA2[crosspoint:])
newDNA2 = int(DNA2[0:crosspoint] + DNA1[crosspoint:])
return newDNA1, newDNA2
#Creates Creatures From DNA
class Creature:
def __init__(self, DNA, image):
self.DNA = DNA
self.speed = (int(self.DNA[0:2])/100) + 1
self.strength = int(DNA[2:4])/10
self.foodCap = int(DNA[4:6])
self.maxHealth = int(DNA[6:8])
self.health = self.maxHealth
self.regeneration = int(DNA[8:10])/10
self.turnProbability = int(DNA[10:12])
self.currentFood = self.foodCap
self.image = image
self.rect = self.image.get_rect()
self.directions = [-1, 1]
self.directionX = random.choice(self.directions)
self.directionY = random.choice(self.directions)
self.isAlive = True
def spawn(self):
self.x = random.randint(25, 775)
self.y = random.randint(25, 575)
self.loc = (self.x, self.y)
self.rect = pygame.Rect(0, 0, 25, 25)
self.rect.center = self.loc
def move(self):
changeDirection = random.randint(0, 100)
if changeDirection < self.turnProbability:
self.directionX = random.choice(self.directions)
self.directionY = random.choice(self.directions)
self.x += self.directionX * self.speed
self.y += self.directionY * self.speed
if self.x > 775:
self.x = 775
elif self.x < 25:
self.x = 25
elif self.y > 575:
self.y = 575
elif self.y < 25:
self.y = 25
self.loc = (self.x, self.y)
self.rect.center = self.loc
def foodCollision(self, foodList):
foodRects = []
for i in range(25):
food = foodList[i]
foodRect = food.rect
foodRects.append(foodRect)
collision = self.rect.collidelist(foodRects)
if collision > 0:
self.currentFood += 20
if self.currentFood > self.foodCap:
self.currentFood = self.foodCap
def creatureCollision(self, creatureList, creatureCount, creatureNumber):
creatureRects = []
for i in range(creatureCount):
creature = creatures[i]
creatureRect = creature.rect
creatureRects.append(creatureRect)
collision = self.rect.collidelist(creatureRects)
creature = creatures[collision]
if collision >= 0:
if collision != creatureNumber:
if creature.health > 0:
self.health -= creature.strength
if self.health < 0:
self.health = 0
def starve(self):
if self.currentFood == 0:
self.health -= 1
def display(self):
screen.blit(self.image, self.loc)
#Creates Food Objects For Creatures To Eat
class Food:
def __init__(self, image):
self.image = image
self.rect = self.image.get_rect()
def spawn(self):
self.x = random.randint(25, 775)
self.y = random.randint(25, 575)
self.loc = (self.x, self.y)
self.rect = pygame.Rect(0, 0, 25, 25)
self.rect.center = self.loc
def creatureCollision(self, creatureList, creatureCount):
creatureRects = []
for i in range(creatureCount):
creature = creatures[i]
creatureRects.append(creature.rect)
collision = self.rect.collidelist(creatureRects)
creature = creatures[collision]
if collision >= 0:
if creature.health > 0:
self.spawn()
def display(self):
screen.blit(self.image, self.loc)
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
screen.fill(backgroundColor)
for i in range(numGenerations):
if i == 0:
#Spawns Creatures Into World
creatures = []
for i in range(creatureCount):
DNA = initialDNA()
print (DNA)
creature = Creature(DNA, creaturePNG)
creature.spawn()
creatures.append(creature)
elif i > 0:
creatures = []
for i in range(0.5*creatureCount):
DNA1, DNA2 = reproduce(deadCreatures, creatureCount)
print (DNA1, DNA2)
creature1, creature2 = Creature(DNA1, creaturePNG), Creature(DNA2, creaturePNG)
creature.spawn()
creatures.append(creature)
#Spawns Food Into World
foodList = []
for i in range(25):
food = Food(foodPNG)
food.spawn()
foodList.append(food)
livingCreatures = True
while livingCreatures:
for i in range(25):
food = foodList[i]
food.creatureCollision(creatures, creatureCount)
food.display()
for i in range(creatureCount):
creature = creatures[i]
if creature.health > 0:
creature.move()
creature.foodCollision(foodList)
creature.creatureCollision(creatures, creatureCount, i)
creature.currentFood -= 0.5
if creature.currentFood < 0:
creature.currentFood = 0
if creature.currentFood > 0:
creature.health += creature.regeneration
if creature.health > creature.maxHealth:
creature.health = creature.maxHealth
creature.starve()
creature.display()
if creature.isAlive == True:
if creature.health == 0:
print ("DEATH")
deadCreatures.append(i)
creature.isAlive = False
if len(deadCreatures) == creatureCount:
livingCreatures = False
pygame.display.flip()
clock.tick(10)
I suspect the livingCreatures variable is never set to False, so the pygame.display.flip() never gets called--and you won't see anything on the screen at all until you flip the buffers. The fact that you're filling the screen with a color, but then still seeing black, is a dead giveaway for this sort of problem.
In the future, you should also try to reproduce the problem in a simpler example without domain-specific, irrelevant code.

calling attributes from other classes error

I am working on a project for my CS class, I am near where I fell comfortable to call it complete, but I am getting this error:
exceptions.AttributeError: type object 'protaganist' has no attribute 'hearts'
also i am trying to make my protaganist class move up.... i have tried
if keys[pygame.K_SPACE]:
self.y += self.dy # (where dy was defined as 10 in init)
i dont know what else to try
lastly how i might set somthing with a random position of x with a set y position
it highlights here: ( it is calling another classe's attribute, but i dnt know why its causing error:
class coinandheartscore(gameEngine.SuperSprite):
def __init__(self, scene):
gameEngine.SuperSprite.__init__(self, scene)
self.font = pygame.font.SysFont("None", 50)
def update(self):
self.text = "hearts X: %d, Coins X: %d" % (protaganist.hearts, protaganist.coins)
self.image = self.font.render(self.text, 1, (255, 255, 0))
self.rect = self.image.get_rect()
here is my overall code:
import gameEngine
import pygame
import math
pygame.init()
screen = pygame.display.set_mode((640, 480))
pygame.mixer.init()
sndAtk = pygame.mixer.Sound("OOT_AdultLink_Attack1.wav")
sndWalk = pygame.mixer.Sound("OOT_Steps_Dirt1.wav")
sndPoof = pygame.mixer.Sound("OOT_Enemy_Poof1.wav")
sndWalk.set_volume(.1)
sndAtk.set_volume(.5)
sndPoof.set_volume(.9)
#sndRun = pygame.mixer.Sound("")
#goal is to create a game
#must have menu to start game
#menu should have a start and quit button.. start runs gaming operations and quit exits program
#sprites for character and enemies and bullets maybe, use one large image and simply move visibiliy
#this saves memory as 1 image is loaded instead of many
"""
protaganist is our hero sprite
should run left and right, jump left and right
and attack left and right...
I might add in the bow and jump attack
"""
class scrollinggrass(gameEngine.SuperSprite):
def __init__(self, scene):
gameEngine.SuperSprite.__init__(self, scene)
self.setImage("gamebackground.jpg")
self.rect = self.imageMaster.get_rect()
self.setPosition((400,247))
self.checkKeys()
self.dy = 3
def checkKeys(self):
keys = pygame.key.get_pressed()
if keys[pygame.K_d]:
self.forward(-6)
sndWalk.play()
if keys[pygame.K_a]:
self.forward(6)
sndWalk.play()
class coins(gameEngine.SuperSprite):
def __init__(self, scene):
gameEngine.SuperSprite.__init__(self, scene)
self.loadImages()
self.image = self.imageMaster
self.frame = -1
self.pause = 0
self.delay = 3
def loadImages(self):
self.coinImgList = []
for i in range(3):
nameImage = "linkimages/coins/greenrupee%d.png" % i
self.setImage(nameImage)
tempImage = self.imageMaster
transparentColor = tempImage.get_at((1,1))
tempImage.set_colorkey(transparentColor)
self.coinImgList.append(tempImage)
def update(self):
self.pause += .25
if self.pause >= self.delay:
self.pause = 0
self.frame += 1
if self.frame >= len(self.coinImgList):
self.frame = 0
self.image = self.coinImgList[self.frame]
class hearts(gameEngine.SuperSprite):
def __init__(self, scene):
gameEngine.SuperSprite.__init__(self, scene)
self.setImage("heart.png")
self.setTransparentColor = self.imageMaster.get_at((1,1))
self.imageMaster.set_colorkey(self.setTransparentColor)
self.setPosition((550 , 30))
class badguy(gameEngine.SuperSprite):
def __init__(self, scene):
gameEngine.SuperSprite.__init__(self, scene)
self.setImage("badguy1.png")
self.setTransparentColor = self.imageMaster.get_at((1,1))
self.imageMaster.set_colorkey(self.setTransparentColor)
self.rect = self.imageMaster.get_rect()
# self.CONTINUE = 4
self.boundAction = self.CONTINUE
self.health = 2
self.DEAD = 1
self.state = 0
self.setPosition((200,375))
self.checkKeys()
def checkKeys(self):
keys = pygame.key.get_pressed()
if keys[pygame.K_d]:
self.forward(-3)
if keys[pygame.K_a]:
self.forward(3)
def reset(self):
self.setPosition((1000, 375))
self.health = 2
# def update(self):
class protaganist(gameEngine.SuperSprite):
def __init__(self, scene):
gameEngine.SuperSprite.__init__(self, scene)
self.imageList = []
self.pause = 0
self.delay = 3
self.rect = self.imageMaster.get_rect()
self.STANDING = 0
self.RIGHT = 0
self.LEFT = 1
self.direction = self.RIGHT
self.RUNNING = 1
self.ATTACKING = 2
self.JUMPING = 3
self.DEAD = 10
self.frame = -1
self.state = self.STANDING
self.coins = 0
self.hearts = 1
self.heartPts = self.hearts * 3
self.stats()
self.dy = 20
self.loadImages()
self.image = self.imageMaster
self.checkKeys()
def stats(self):
#sets it up so each heart is essentially 3 hit points
if self.heartPts >= 3:
self.hearts = 1
elif self.heartPts >= 6:
self.hearts = 2
elif self.heartPts == 9:
self.hearts = 3
elif self.heartPts > 9:
self.heartPts = 9
# changes state to dead if hp == 0
if self.heartPts == 0:
self.state = DEAD
def loadImages(self):
self.setImage("heroSTANDINGLeft.gif")
self.setTransparentColor = self.imageMaster.get_at((1,1))
self.imageMaster.set_colorkey(self.setTransparentColor)
self.imageSTANDINGLeft = self.imageMaster
self.setImage("heroSTANDING.gif")
self.setTransparentColor = self.imageMaster.get_at((1,1))
self.imageMaster.set_colorkey(self.setTransparentColor)
self.imageSTANDING = self.imageMaster
self.heroATKList = []
self.heroATKleft = []
self.heroDEAD = []
self.heroRUNList = []
self.heroRUNLeftList = []
for i in range(4):
nameImage = "linkimages/DEAD/heroDEAD%d.gif" % i
self.setImage(nameImage)
tempImage = self.imageMaster
transparentColor = tempImage.get_at((1,1))
tempImage.set_colorkey(transparentColor)
self.heroDEAD.append(tempImage)
for i in range(5):
nameImage = "linkimages/runningRIGHT/heroRUN%d.gif" % i
self.setImage(nameImage)
tempImage = self.imageMaster
transparentColor = tempImage.get_at((1,1))
tempImage.set_colorkey(transparentColor)
self.heroRUNList.append(tempImage)
for i in range(5):
nameImage = "linkimages/runningLEFT/heroRUN%d.gif" % i
self.setImage(nameImage)
tempImage = self.imageMaster
transparentColor = tempImage.get_at((1,1))
tempImage.set_colorkey(transparentColor)
self.heroRUNLeftList.append(tempImage)
for i in range(4):
nameImage = "linkimages/ATTACKING/heroATTACKING%d.gif" % i
self.setImage(nameImage)
tempImage = self.imageMaster
transparentColor = tempImage.get_at((1,1))
tempImage.set_colorkey(transparentColor)
self.heroATKList.append(tempImage)
for i in range(4):
nameImage = "linkimages/ATTACKING/heroATTACKINGLeft%d.gif" % i
self.setImage(nameImage)
tempImage = self.imageMaster
transparentColor = tempImage.get_at((1,1))
tempImage.set_colorkey(transparentColor)
self.heroATKleft.append(tempImage)
def update(self):
self.rect = self.imageMaster.get_rect()
self.rect.x = 275
self.rect.y = 350
if self.state == self.STANDING:
if self.direction == self.RIGHT:
self.image = self.imageSTANDING
self.setPosition((200,200))
elif self.direction == self.LEFT:
self.image = self.imageSTANDINGLeft
if self.state == self.RUNNING:
if self.direction == self.RIGHT:
self.frame += 1
if self.frame >= len(self.heroRUNList):
self.frame = 0
self.image = self.heroRUNList[self.frame]
elif self.direction == self.LEFT:
self.frame += 1
if self.frame >= len(self.heroRUNLeftList):
self.frame = 0
self.image = self.heroRUNLeftList[self.frame]
if self.state == self.DEAD:
self.frame += 1
if self.frame >= len(self.heroDEAD):
self.frame = 0
self.image = self.heroDEAD[self.frame]
self.pause += .5
if self.pause >= self.delay:
self.pause = 0
if self.state == self.ATTACKING:
if self.direction == self.RIGHT:
self.frame += 1
sndAtk.play()
if self.frame >= len(self.heroATKList):
self.frame = 0
self.image = self.heroATKList[self.frame]
elif self.direction == self.LEFT:
self.frame += 1
sndAtk.play()
if self.frame >= len(self.heroATKleft):
self.frame = 0
self.image = self.heroATKleft[self.frame]
def checkKeys(self):
keys = pygame.key.get_pressed()
if keys[pygame.K_d]:
self.direction = self.RIGHT
self.state = self.RUNNING
self.x += self.dx
else:
self.state = self.STANDING
if keys[pygame.K_a]:
self.state = self.RUNNING
self.direction = self.LEFT
if keys[pygame.K_g]:
self.state = self.ATTACKING
#sndAtk.play()
if keys[pygame.K_SPACE]:
self.addDY(3)
if self.state == self.DEAD:
self.image = self.deadImgList[0]
self.frame += 1
self.image = self.deadImgList[self.frame]
#self.image = self.image.get_rect()
#self.rect.center = (320, 240)
class coinandheartscore(gameEngine.SuperSprite):
def __init__(self, scene):
gameEngine.SuperSprite.__init__(self, scene)
self.font = pygame.font.SysFont("None", 50)
def update(self):
self.text = "hearts X: %d, Coins X: %d" % (protaganist.hearts, protaganist.coins)
self.image = self.font.render(self.text, 1, (255, 255, 0))
self.rect = self.image.get_rect()
class game(gameEngine.Scene):
def __init__ (self):
gameEngine.Scene.__init__(self)
pygame.display.set_caption("Link's Mediocre Adventure")
background = pygame.Surface(screen.get_size())
background.fill((0, 0, 0))
screen.blit(background, (0, 0))
coin = coins(self)
pro = protaganist(self)
baddy = badguy(self)
baddy1 = badguy(self)
heart = hearts(self)
grass = scrollinggrass(self)
score = coinandheartscore(self)
goodlySprites = self.makeSpriteGroup((grass, coin, pro, heart))
baddySprites = self.makeSpriteGroup((baddy, baddy1))
cnhrtSprites = self.makeSpriteGroup((score))
self.addGroup((cnhrtSprites))
self.addGroup((goodlySprites))
self.addGroup((baddySprites))
clock = pygame.time.Clock()
keepGoing = True
while keepGoing:
clock.tick(30)
for event in pygame.event.get():
if event.type == pygame.QUIT:
keepGoing = False
if pro.state == pro.ATTACKING:
if pro.collidesGroup(baddySprites):
baddy.health -= 1
baddy1.health -= 1
if baddy.health == 0:
sndPoof.play()
baddy.reset()
elif baddy1.health == 0:
sndPoof.play()
baddy1.reset()
elif pro.state != pro.ATTACKING:
if pro.collidesGroup(baddySprites):
pro.heartPts -= 1
baddy.checkKeys()
grass.checkKeys()
pro.checkKeys()
pro.loadImages()
goodlySprites.clear(screen, background)
baddySprites.clear(screen, background)
cnhrtSprites.clear(screen, background)
goodlySprites.update()
baddySprites.update()
cnhrtSprites.update()
goodlySprites.draw(screen)
baddySprites.draw(screen)
cnhrtSprites.draw(screen)
pygame.display.flip()
def main():
game.start()
if __name__ == "__main__":
game()
At least one of the problems is in your naming of your classes: the PEP8 convention calls for capitalized class names (Protagonist) and lower-case instances of them (pro). You've called your class protagonist and instantiated as pro. It looks like you're referring to protagonist.hearts (no such class attribute exists) when you mean pro.hearts (attribute of an instance of the protagonist class.
As a general rule, if you have two questions (even about the same piece of code), you should post two separate questions on Stack Overflow. That said...
1: Moving Up
The code you quoted in your question looks OK. Unfortunately, it's nothing like the code you're actually running in protaganist.checkKeys:
if keys[pygame.K_SPACE]:
self.addDY(3)
There is no protaganist.addDY method, so trying to call it should raise an exception. The hard-wired argument to the non-existent method is 3, not 10. Finally (to correct your comment), protaganist.__init__ sets protaganist.dy to 20, not 10.
2: AttributeError
Your protaganist class has no hearts attribute, which is almost exactly what the error message said. (Note that it's typically spelled with an "o": protagonist.)
Instances of your protaganist class do have a hearts attribute, but you can't access that by going through the class name. (How would the Python interpreter know which of possibly-many protaganist instances you meant?)
To get a particular protaganist object's hearts value, you'll need a reference to that specific instance:
class coinandheartscore(gameEngine.SuperSprite):
# New protagonist parameter is required.
def __init__(self, scene, protagonist):
gameEngine.SuperSprite.__init__(self, scene)
self.font = pygame.font.SysFont("None", 50)
# Save it for later use.
self.protagonist = protagonist
def update(self):
# self.protagonist refers to _one_ specific
# protaganist instance, which _does_ have
# hearts and coins attributes.
self.text = "hearts X: %d, Coins X: %d" % (
self.protagonist.hearts,
self.protagonist.coins,
)
# Remainder unchanged...
Later, in the game.__init__ method, you'll have to provide the new argument when you instantiate coinandheartscore:
# New self.pro argument.
score = coinandheartscore(self, self.pro)
3: PEP-8
Finally, I second xnx's comments about naming conventions... The strange names made this much harder to read than it had to be.
Although xnx didn't link to PEP-8 in his answer, it is literally the first Google result. He or she was specifically talking about the section on Naming Conventions.
4: Freebies
protaganist.checkKeys: d and a are not the inverses you would expect. d adds self.dx ( which does not exist) to self.x, while a adds nothing.
protaganist.stats sets self.state to DEAD, which does not exist. You probably meant self.DEAD.
In general, test more and code less. The more you write between tests, the more bugs you will have to track down, and the more places they can be hiding.

Trouble using the same image for multiple objects

I'm making a game with Pygame and I'm trying to animate asteroids that get hit with a bullet. The animation works fine if there's just one asteroid type on the screen. I run into trouble when there's two identical asteroids on the screen. It seems that the first one on is the only one that uses my animation.
For example, say the game spawns two small asteroids, these are the exact same and I'm using glob.glob to get the 4 animation images, then I'll just use those images to create a little animation by looping over them. This works with one of the asteroids, the other will not play the animation. I'm thinking it must be because only one object can use specific images at any one time?
I'm sorry for the terrible explaination.
Here's the asteroid class I have and the call to create the animation:
class Asteroid(pygame.sprite.Sprite):
def __init__(self, screen, size):
pygame.sprite.Sprite.__init__(self)
self.screen = screen
self.size = size
self.pos_x = random.randint(100,900)
pos_y= random.randint(100, 700)
self.pos_y = -pos_y
self.vel_y = 3
self.update_main = True
self.animation_path = ""
#load the image then put it above the screen, ready to drop
if self.size == "small":
self.asteroid_image = pygame.image.load("asteroid_small.tga")
self.animation_path = "C:/Programming/Stupid Games/Alien Invasion/animations/asteroid_small/*.tga"
elif self.size == "medium":
self.asteroid_image = pygame.image.load("asteroid_medium.tga")
self.animation_path = "C:/Programming/Stupid Games/Alien Invasion/animations/asteroid_medium/*.tga"
elif self.size == "med_large":
self.asteroid_image = pygame.image.load("asteroid_med_large.tga")
self.animation_path = "C:/Programming/Stupid Games/Alien Invasion/animations/asteroid_med_large/*.tga"
elif self.size == "small_med":
self.asteroid_image = pygame.image.load("asteroid_small_med.png")
elif self.size == "small_1":
self.asteroid_image = pygame.image.load("small1.tga")
self.animation_path = "C:/Programming/Stupid Games/Alien Invasion/animations/small/*.tga"
else:
self.asteroid_image = pygame.image.load("asteroid_large.tga")
self.animation_path = "C:/Programming/Stupid Games/Alien Invasion/animations/asteroid_large/*.tga"
#make the asteroid transparent
corner = self.asteroid_image.get_at((0,0))
self.asteroid_image.set_colorkey(corner, RLEACCEL)
#randomly rotate the image
self.new_asteroid_image = pygame.transform.rotate(self.asteroid_image, random.randint(0,340))
self.rect = self.new_asteroid_image.get_rect()
self.rect.x, self.rect.y = ((self.pos_x, self.pos_y))
self.start_animate = False
self.times = 0
#load the asteroid animation
self.animation = glob.glob(self.animation_path)
self.animation.sort()
self.animation_pos = 0
self.animation_max = len(self.animation)-1
self.animation_speed_init = 50
self.animation_speed = self.animation_speed_init
def update(self):
#if asteroid has left the screen, place it back to the top
if self.rect.y > 900:
pos_y = random.randint(100,500)
self.rect.y = -pos_y
self.rect.x = random.randint(100,900)
self.rect.y += self.vel_y
self.position = self.rect.x, self.rect.y
self.screen.blit(self.new_asteroid_image.convert(), self.position)
if self.start_animate == True:
self.animation_speed += 25
if self.animation_speed > 60:
self.update_main = False
self.new_asteroid = pygame.image.load(self.animation[self.times])
corner = self.new_asteroid.get_at((0,0))
self.new_asteroid.set_colorkey(corner, RLEACCEL)
self.new_asteroid_image = self.new_asteroid
self.animation_speed = 0
self.animation_pos += 1
self.times += 1
if self.times > self.animation_max:
self.kill()
def start_animation(self):
self.start_animate = True
#create asteroids at the start of the game
if keys[K_SPACE]:
game_over = False
player = Space_Ship("space_ship.tga", screen)
asteroid_small = Asteroid(screen, "small")
asteroid_large = Asteroid(screen, "large")
asteroid_medium = Asteroid(screen, "medium")
asteroid_med_large = Asteroid(screen, "med_large")
asteroid_group.add(asteroid_small, asteroid_large, asteroid_medium, asteroid_med_large)
player_group.add(player)
score = 0
#add asteroids after the game has started
if len(asteroid_group) < difficulty:
random_asteroid_number = random.randint(0,5)
if random_asteroid_number == 0:
#large asteroid
asteroid_large = Asteroid(screen, "large")
asteroid_group.add(asteroid_large)
elif random_asteroid_number == 1:
#medium asteroid
asteroid_medium = Asteroid(screen, "medium")
asteroid_group.add(asteroid_medium)
elif random_asteroid_number == 2:
#medium large asteroid
asteroid_med_large = Asteroid(screen, "med_large")
asteroid_group.add(asteroid_med_large)
elif random_asteroid_number == 3:
#small medium asteroid
asteroid_small_med = Asteroid(screen, "small_med")
asteroid_group.add(asteroid_small_med)
elif random_asteroid_number == 4:
#small_1 asteroid
asteroid_small_1 = Asteroid(screen, "small_1")
asteroid_group.add(asteroid_small_1)
else:
#small asteroid
asteroid_small = Asteroid(screen, "small")
asteroid_group.add(asteroid_small)
#bullet - asteroid collision
collisions = pygame.sprite.groupcollide(bullet_group, asteroid_group, True, False)
if collisions != None:
for i in collisions.values():
for sprite in i:
channel2.play(asteroid_audio)
if sprite == asteroid_large:
score += 3
sprite.start_animation()
elif sprite == asteroid_small_1 or sprite == asteroid_med_large or sprite == asteroid_medium or sprite == asteroid_small:
score += 1
sprite.start_animation()
else:
score += 1
sprite.kill()
Although I can't be sure because the bit where you call update is not shown, I have a few ideas of why it is doing what it is. It seems that the second asteroid's update is not being called. This could be for several reasons. The first reason is if you do not implement groups to update you asteroid. Basically, if you only call your single instance of the asteroid, the second one will not do anything, even show up on the screen. If this is the case, you will need to make a group, perhaps a render updates group but even a list would be fine. This would mean you could do something like:
asteroids.update()
or
for asteroid in asteroids:
asteroid.update()
the above two codes assume that you have some kind of grouping of asteroids, called asteroids.
Another possible problem, if you are implementing groups, is if the second asteroid is not getting added to this group. If you tell it to add itself to the group in the init function, this problem will not be there, however, if you call it outside of this function, you may not be doing so when you make your second asteroid. To address this problem just move the part where you add the asteroid into a group that will be updated to the init function of asteroids.

Categories