Bullet not colliding with enemy Pygame (Python 3) - python
I want to make a mega man similar game where you jump around and shooting stuff. But I've noticed there's something wrong with the collision, I have a video below:
https://youtu.be/p2VCtbBkefo
I'm planning to make this project open source, so anybody can customize it. Please don't steal this code, but you may use chunks of it to help you with something. because I haven't put it on GitHub publicly yet.
main.py:
import pygame as pg
from player import *
from settings import *
from levels import *
from block import *
from enemy import *
class Game:
def __init__(self):
pg.init()
pg.mixer.init()
self.screen = pg.display.set_mode((width, height))
pg.display.set_caption("wait until realesed.")
self.clock = pg.time.Clock()
self.enemiesList = []
self.running = True
self.shootRight = True
def loadLevel(self, level, enemies, group, group2, group3):
for y in range(0, len(level)):
for x in range(0, len(level[y])):
if (level[y][x] == 1):
blockList.append(Block(x*32, y*32))
group.add(Block(x*32, y*32))
group2.add(Block(x*32, y*32))
for amount in range(0, enemies):
group2.add(FlyingEnemy(self))
group3.add(FlyingEnemy(self))
self.enemies.add(FlyingEnemy(self))
self.enemiesList.append(FlyingEnemy(self))
def new(self):
self.platforms = pg.sprite.Group()
self.all_sprites = pg.sprite.Group()
self.enemies = pg.sprite.Group()
self.bullets = pg.sprite.Group()
self.player = Player()
self.loadLevel(level1["platform"], level1["enemies"], self.platforms, self.all_sprites, self.enemies)
self.all_sprites.add(self.player)
self.run()
def shoot(self):
if self.shootRight:
self.bullet = Bullet(self.player.rect.centerx, self.player.rect.centery)
self.bullet.speed = 10
self.all_sprites.add(self.bullet)
self.bullets.add(self.bullet)
print(self.bullet)
elif self.shootRight == False:
self.bullet = Bullet(self.player.rect.centerx, self.player.rect.centery)
self.bullet.speed = -10
self.all_sprites.add(self.bullet)
self.bullets.add(self.bullet)
print(self.bullet)
def run(self):
self.playing = True
while self.playing:
self.clock.tick(FPS)
self.events()
self.update()
self.draw()
def update(self):
self.all_sprites.update()
self.enemy_hits = pg.sprite.spritecollide(self.player, self.enemies, False)
#print(enemy_hits)
if self.enemy_hits:
pass
#print("hit")
self.bullet_hits = pg.sprite.groupcollide(self.enemies, self.bullets, True, True)
if self.bullet_hits:
print(self.bullet_hits)
pygame.quit()
hits = pg.sprite.spritecollide(self.player, self.platforms, False)
if hits:
self.player.pos.y = hits[0].rect.top + 1
self.player.vel.y = 0
def events(self):
for event in pg.event.get():
if event.type == pg.QUIT:
if self.playing:
self.playing = False
self.running = false
if event.type == pg.KEYDOWN:
if event.key == pg.K_UP:
self.player.jump()
if event.key == pg.K_SPACE:
self.shoot()
if event.key == pg.K_RIGHT:
self.shootRight = True
if event.key == pg.K_LEFT:
self.shootRight = False
def draw(self):
self.screen.fill((255, 255, 255))
self.all_sprites.draw(self.screen)
pg.display.flip()
def show_start_screen(self):
pass
def show_go_screen(self):
pass
g = Game()
g.show_start_screen()
while g.running:
g.new()
g.show_go_screen()
pg.quit()
"""width = 800
height = 600
FPS = 60
pg.init()
pg.mixer.init()
screen = pg.display.set_mode((width, height))
pg.display.set_caption("doom room")
clock = pg.time.Clock()
running = True
while running:
for event in pg.event.get():
clock.tick(FPS)
if event.type == pg.QUIT:
running = false
screen.fill((255, 255, 255))
pg.display.flip()
pg.quit()"""
import pygame
class Bullet(pygame.sprite.Sprite):
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((20, 10))
self.image.fill((240, 43, 12))
self.rect = self.image.get_rect()
self.rect.bottom = y
self.rect.centerx = x
self.speed = -10
def update(self):
self.rect.x += self.speed
if self.rect.bottom < 0:
self.kill()
player.py
import pygame as pg
from settings import *
from laser import *
vec = pg.math.Vector2
class Player(pg.sprite.Sprite):
def __init__(self):
pg.sprite.Sprite.__init__(self)
self.image = pg.Surface((40, 40))
self.image.fill((80, 123, 255))
self.rect = self.image.get_rect()
self.rect.center = (width / 2, height / 2)
self.pos = vec(width / 2, height / 2)
self.vel = vec(0, 0)
self.acc = vec(0, 0)
#self.vx = 0
#self.vy = 0
def jump(self):
self.vel.y = -15
def update(self):
self.acc = vec(0, player_gravity)
keys = pg.key.get_pressed()
if keys[pg.K_LEFT]:
self.acc.x = -player_acc
if keys[pg.K_RIGHT]:
self.acc.x = player_acc
self.acc.x += self.vel.x * player_friction
self.vel += self.acc
self.pos += self.vel + 0.5 * self.acc
if self.pos.x > width:
self.pos.x = 0
if self.pos.x < 0:
self.pos.x = width
if self.pos.y <= 0:
self.pos.y += 15
self.rect.midbottom = self.pos
enemy.py
import pygame as pg
from random import *
from settings import *
class FlyingEnemy(pg.sprite.Sprite):
def __init__(self, game):
pg.sprite.Sprite.__init__(self)
self.game = game
self.image = pg.Surface((45, 45))
self.image.fill((20, 203, 50))
self.rect = self.image.get_rect()
self.rect.centerx = choice([-100, width + 100])
self.vx = randrange(4, 7)
if self.rect.centerx > width:
self.vx *= -1
self.rect.y = height / 4
self.rect.x = 0
self.vy = 0
self.dy = 0.5
def update(self):
if self.rect.x > width:
self.rect.x = 0
if self.rect.x < 0:
self.rect.x = width
self.rect.x += self.vx
self.vy += self.dy
if self.vy > 3 or self.vy < -3:
self.dy *= -1
center = self.rect.center
if self.dy < 0:
pass
#print("bobbed up")
else:
pass
#print("bobbed down")
settings.py
import pygame
blockList = []
player_acc = 1.0
player_friction = -0.12
player_gravity = 0.5
bullets = pygame.sprite.Group()
true = True
false = False
width = 800
height = 600
FPS = 60
levels.py
level1 = {
"platform": [
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1],
[1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0],
[0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0],
[0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0],
[0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0],
[0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
],
"enemies": 5
}
block.py
import pygame as pg
class Block(pg.sprite.Sprite):
def __init__(self, x, y):
pg.sprite.Sprite.__init__(self)
self.image = pg.Surface((32, 32))
self.image.fill((0, 0, 0))
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
Thanks all help is appreciated.
This part of the loadLevel method causes the problem:
for amount in range(0, enemies):
group2.add(FlyingEnemy(self))
group3.add(FlyingEnemy(self))
self.enemies.add(FlyingEnemy(self))
self.enemiesList.append(FlyingEnemy(self))
You're adding 4 different FlyingEnemy objects to these groups and the list (btw, the list is useless), so the sprites in the self.all_sprites group and in the self.enemies group are not the same.
Since you're only updating the all_sprites and not the enemies, the sprites in the enemies group, which are used for the collision detection, stay at the left screen edge all the time and are also invisible, because you don't draw this group.
To solve the problem, create one instance and add this instance to the two groups:
for amount in range(0, enemies):
enemy = FlyingEnemy(self)
self.enemies.add(enemy)
self.all_sprites.add(enemy)
I found the bug by printing the rect of one enemy sprite in the self.enemies group. Then I checked the update method of this sprite, but it looked correct, so I went to the instantiation part in loadLevel and noticed the mistake.
Related
Im stuck on doing an explosion animation for my cement block sprites [duplicate]
This question already exists: I want to do an explosion animation. I have 4 png files number 0 - 3. In my debris class I loaded them into an image list using a for loop [duplicate] Closed 1 year ago. I want to do an explosion animation. I have 4 png files number 0 - 3. In my debris class I loaded them into an image list using a for loop. Then I made an explosion function but when I load my pygame windows and start shooting my cement block sprites, my cement block sprites disappear which is fine but they don't do the exploding animation I want. How can I fix this problem. Would appreciate the help. My code: import random import pygame import pygame.freetype pygame.init() #screen settings WIDTH = 1000 HEIGHT = 400 screen = pygame.display.set_mode((WIDTH, HEIGHT)) pygame.display.set_caption("AutoPilot") screen.fill((255, 255, 255)) #fps FPS = 120 clock = pygame.time.Clock() #load images bg = pygame.image.load('background/street.png').convert_alpha() # background bullets = pygame.image.load('car/bullet.png').convert_alpha() debris_img = pygame.image.load('debris/cement.png') #define game variables shoot = False #player class class Player(pygame.sprite.Sprite): def __init__(self, scale, speed): pygame.sprite.Sprite.__init__(self) self.bullet = pygame.image.load('car/bullet.png').convert_alpha() self.bullet_list = [] self.speed = speed #self.x = x #self.y = y self.moving = True self.frame = 0 self.flip = False self.direction = 0 self.score = 0 #load car self.images = [] img = pygame.image.load('car/car.png').convert_alpha() img = pygame.transform.scale(img, (int(img.get_width()) * scale, (int(img.get_height()) * scale))) self.images.append(img) self.image = self.images[0] self.rect = self.image.get_rect() self.update_time = pygame.time.get_ticks() self.movingLeft = False self.movingRight = False self.rect.x = 465 self.rect.y = 325 #draw car to screen def draw(self): screen.blit(self.image, (self.rect.centerx, self.rect.centery)) #move car def move(self): #reset the movement variables dx = 0 dy = 0 #moving variables if self.movingLeft and self.rect.x > 33: dx -= self.speed self.flip = True self.direction = -1 if self.movingRight and self.rect.x < 900: dx += self.speed self.flip = False self.direction = 1 #update rectangle position self.rect.x += dx self.rect.y += dy #shoot def shoot(self): bullet = Bullet(self.rect.centerx + 18, self.rect.y + 30, self.direction) bullet_group.add(bullet) #check collision def collision(self, debris_group): for debris in debris_group: if pygame.sprite.spritecollide(debris, bullet_group, True): debris.health -= 1 if debris.health <= 0: self.score += 1 debris.kill() #player stats def stats(self): myfont = pygame.font.SysFont('comicsans', 30) scoretext = myfont.render("Score: " + str(self.score), 1, (0,0,0)) screen.blit(scoretext, (100,10)) #bullet class class Bullet(pygame.sprite.Sprite): def __init__(self, x, y, direction): pygame.sprite.Sprite.__init__(self) self.speed = 5 self.image = bullets self.rect = self.image.get_rect() self.rect.center = (x,y) self.direction = direction def update(self): self.rect.centery -= self.speed #check if bullet has gone off screen if self.rect.centery < 1: self.kill() #debris class class Debris(pygame.sprite.Sprite): def __init__(self,scale,speed): pygame.sprite.Sprite.__init__(self) self.scale = scale self.x = random.randrange(100,800) self.speed_y = 10 self.y = 15 self.speed = speed self.vy = 0 self.on_ground = True self.move = True self.health = 4 self.max_health = self.health self.alive = True self.velocity = random.randrange(1,2) self.speed_x = random.randrange(-3,3) self.moving_down = True #load debris self.image = debris_img self.rect = self.image.get_rect() self.rect.x = random.randrange(100, 800) self.rect.y = random.randrange(-150, -100) self.rect.center = (self.x,self.y) #load explosion self.images = [] for i in range(4): self.images.append(pygame.image.load(f'explosion/{i}.png')) self.index = 0 self.img = self.images[self.index] #spawn new debris def spawn_new_debris(self): self.rect.x = random.randrange(100, 800) self.rect.y = random.randrange(-150, -100) self.velocity = random.randrange(1, 2) self.speed_x = random.randrange(-3, 3) #respawn debris when they go of the screen def boundaries(self): if self.rect.left > WIDTH + 10 or self.rect.right < -10 or self.rect.top > HEIGHT + 10: self.spawn_new_debris() #update image def update(self): self.rect.y += self.velocity self.rect.x += self.speed_x self.boundaries() #make debris fall down def falldown(self): self.rect.centery += self.velocity if self.moving_down and self.rect.y > 350: self.kill() #explosion def explode(self): if self.max_health <= 0: self.index += 1 if self.index >= len(self.images): self.index = 0 self.img = self.images[self.index] ######################CAR/DEBRIS########################## player = Player(1,5) ########################################################## #groups bullet_group = pygame.sprite.Group() debris_group = pygame.sprite.Group() all_sprites = pygame.sprite.Group() for i in range(50): d = Debris(1,5) debris_group.add(d) all_sprites.add(d) #game runs here run = True while run: #draw street screen.blit(bg, [0, 0]) #update groups bullet_group.update() bullet_group.draw(screen) debris_group.update() debris_group.draw(screen) #draw car player.draw() player.move() player.collision(debris_group) player.stats() #update all sprites all_sprites.update() all_sprites.draw(screen) for event in pygame.event.get(): if event.type == pygame.QUIT: run = False #check if key is down if event.type == pygame.KEYDOWN: if event.key == pygame.K_ESCAPE: run = False if event.key == pygame.K_a: player.movingLeft = True if event.key == pygame.K_d: player.movingRight = True if event.key == pygame.K_SPACE: player.shoot() shoot = True #check if key is up if event.type == pygame.KEYUP: if event.key == pygame.K_a: player.movingLeft = False if event.key == pygame.K_d: player.movingRight = False #update the display pygame.display.update() pygame.display.flip() clock.tick(FPS) pygame.quit()
Pygame: player sprite colliding incorrectly and clipping into wall
I am creating a 4-way movement, tile based rpg. The code I have written for collision detection is relatively simple but I have a minor graphical error. The player moves directly between evenly spaced tiles. To control the speed the player moves at there is a walk buffer of 200 seconds. When the player collides with a wall, they should be pushed back in the same direction they hit the wall. This works, however, very briefly the player sprite will flicker in the wall. I suspect it's to do with the player update function and how that's ordered but I've messed around with it to no avail. import sys vec = pg.math.Vector2 WHITE = ( 255, 255, 255) BLACK = ( 0, 0, 0) RED = ( 255, 0, 0) YELLOW = ( 255, 255, 0) BLUE = ( 0, 0, 255) WIDTH = 512 # 32 by 24 tiles HEIGHT = 384 FPS = 60 TILESIZE = 32 PLAYER_SPEED = 3 * TILESIZE MAP = ["1111111111111111", "1P.............1", "1..............1", "1..1111........1", "1..1..1........1", "1..1111.111111.1", "1............1.1", "1........111.1.1", "1........1...1.1", "1........11111.1", "1..............1", "1111111111111111"] def collide_hit_rect(one, two): return one.hit_rect.colliderect(two.rect) def player_collisions(sprite, group): hits_walls = pg.sprite.spritecollide(sprite, group, False, collide_hit_rect) if hits_walls: sprite.pos -= sprite.vel * TILESIZE class Player(pg.sprite.Sprite): def __init__(self, game, x, y): self.groups = game.all_sprites pg.sprite.Sprite.__init__(self, self.groups) self.game = game self.walk_buffer = 200 self.vel = vec(0, 0) self.pos = vec(x, y) *TILESIZE self.current_frame = 0 self.last_update = 0 self.walking = False self.walking_sprite = pg.Surface((TILESIZE, TILESIZE)) self.walking_sprite.fill(YELLOW) self.image = self.walking_sprite self.rect = self.image.get_rect() self.hit_rect = self.rect self.hit_rect.bottom = self.rect.bottom def update(self): self.get_keys() self.rect = self.image.get_rect() self.rect.topleft = self.pos self.pos += self.vel * TILESIZE self.hit_rect.topleft = self.pos player_collisions(self, self.game.walls) self.rect.midbottom = self.hit_rect.midbottom def get_keys(self): self.vel = vec(0,0) now = pg.time.get_ticks() keys = pg.key.get_pressed() if now - self.last_update > self.walk_buffer: self.vel = vec(0,0) self.last_update = now if keys[pg.K_LEFT] or keys[pg.K_a]: self.vel.x = -1 elif keys[pg.K_RIGHT] or keys[pg.K_d]: self.vel.x = 1 elif keys[pg.K_UP] or keys[pg.K_w]: self.vel.y = -1 elif keys[pg.K_DOWN] or keys[pg.K_s]: self.vel.y = 1 class Obstacle(pg.sprite.Sprite): def __init__(self, game, x, y): self.groups = game.walls pg.sprite.Sprite.__init__(self, self.groups) self.x = x * TILESIZE self.y = y * TILESIZE self.w = TILESIZE self.h = TILESIZE self.game = game self.image = pg.Surface((self.w,self.h)) self.image.fill(BLACK) self.rect = self.image.get_rect() self.hit_rect = self.rect self.rect.x = self.x self.rect.y = self.y class Game: def __init__(self): pg.init() self.screen = pg.display.set_mode((WIDTH, HEIGHT)) pg.display.set_caption("Hello Stack Overflow") self.clock = pg.time.Clock() pg.key.set_repeat(500, 100) def new(self): self.all_sprites = pg.sprite.Group() self.walls = pg.sprite.Group() for row, tiles in enumerate(MAP): for col, tile in enumerate(tiles): if tile == "1": Obstacle(self, col, row) elif tile == "P": print("banana!") self.player = Player(self, col, row) def quit(self): pg.quit() sys.exit() def run(self): # game loop - set self.playing = False to end the game self.playing = True while self.playing: self.dt = self.clock.tick(FPS) / 1000 self.events() self.update() self.draw() def events(self): # catch all events here for event in pg.event.get(): if event.type == pg.QUIT: self.quit() def update(self): self.player.update() def draw(self): self.screen.fill(WHITE) for wall in self.walls: self.screen.blit(wall.image, wall.rect) for sprite in self.all_sprites: self.screen.blit(sprite.image, sprite.rect) pg.display.flip() # create the game object g = Game() while True: g.new() g.run() pg.quit()```
You're setting the rect before checking for collision but not resetting it after the collision check. Here is the updated code (in Player class, update method): self.hit_rect.topleft = self.pos player_collisions(self, self.game.walls) # may change postion self.hit_rect.topleft = self.pos # reset rectangle
How to jump only when standing on the ground? (Python)
As of now, I jump whenever I press space. How can I make it so I only jump when standing on something? Would I create some variables such as STANDING and JUMPING? And if I do, how to I reference to them in my class Player? Here is my code, all help is appreciated. Thanks everyone. import pygame as pg import os # create a variable for pg.math.Vector2 vec = pg.math.Vector2 TITLE = "Jumping 1" WIDTH = 800 HEIGHT = 600 clock = pg.time.Clock() FPS = 60 GREEN = (0, 255, 0) LIGHTBLUE = (50, 200, 250) RED = (255, 0, 0) # Player properties PLAYER_ACC = 0.5 PLAYER_FRICTION = -0.12 PLAYER_GRAVITY = 0.8 game_folder = os.path.dirname(__file__) img_folder = os.path.join(game_folder, "img") class Player(pg.sprite.Sprite): def __init__(self): pg.sprite.Sprite.__init__(self) self.image = pg.Surface((50, 50)) self.image.fill(GREEN) self.rect = self.image.get_rect() self.rect.center = ((WIDTH / 2, HEIGHT / 2)) # position, velocity, acceleration self.pos = vec(WIDTH / 2, HEIGHT / 2) self.vel = vec(0, 0) self.acc = vec(0, 0) def update(self): self.acc = vec(0, PLAYER_GRAVITY) keystate = pg.key.get_pressed() if keystate[pg.K_LEFT]: self.acc.x = -PLAYER_ACC if keystate[pg.K_RIGHT]: self.acc.x = PLAYER_ACC # apply friction self.acc.x += self.vel.x * PLAYER_FRICTION # equations of motion self.vel += self.acc self.pos += self.vel + 0.5 * self.acc # wrap around the sides of the screen if self.pos.x > WIDTH: self.pos.x = 0 if self.pos.x < 0: self.pos.x = WIDTH self.rect.midbottom = self.pos def jump(self): self.vel.y = -20 player = Player() class Platform(pg.sprite.Sprite): def __init__(self): pg.sprite.Sprite.__init__(self) self.image = pg.Surface((WIDTH, 50)) self.image.fill(RED) self.rect = self.image.get_rect() self.rect.center = ((WIDTH / 2, HEIGHT - 25)) platform = Platform() def game_loop(): pg.init() screen = pg.display.set_mode((WIDTH, HEIGHT)) pg.display.set_caption(TITLE) all_sprites = pg.sprite.Group() all_sprites.add(player, platform) ground_sprite = pg.sprite.Group() ground_sprite.add(platform) running = True while running: for event in pg.event.get(): if event.type == pg.QUIT: running = False if event.type == pg.KEYDOWN: if event.key == pg.K_SPACE: player.jump() all_sprites.update() hits = pg.sprite.spritecollide(player, ground_sprite, False) if hits: player.pos.y = hits[0].rect.top or platform.rect.top player.vel.y = 0 screen.fill(LIGHTBLUE) all_sprites.draw(screen) pg.display.flip() clock.tick(FPS) pg.quit() game_loop()
In your Player class add a standing flag. Then when space is pressed before performing the jump check if standing is true. If standing is false then do not allow the jump to happen, essentially: onSpaceBar() { if(standing) { \\ perform jump standing = false; } } Then also make sure after the jump is completed (i.e. you land on something) set the standing flag back to true.
TypeError: argument 1 must be pygame.Surface, not list [closed]
Closed. This question needs debugging details. It is not currently accepting answers. Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question. Closed 6 years ago. Improve this question I was working on a movement animations since I saw a youtuber explaining how to do it, but I'm getting this error: TypeError: argument 1 must be pygame.Surface, not list My code is about 500 lines. # Pygame Template - skeleton for a new pygame project import pygame import random import os from os import path vec = pygame.math.Vector2 width = 800 height = 600 FPS = 60 POWERUP_TIME = 5000 title = 'Parkourse' # Player properties player_acceleration = 0.5 player_friction = -0.12 player_gravity = 0.8 player_jump = 10 # Starting platforms platforms_list = [(0,height-40,width,50), # Ground (0,0,800,10), # Top (0,0,10,600), # Left Border (790,height-400,10,600),# Right Border (250,height - 160,width-200,10), # Floor 1 (0,height - 280,width-200,10), # Floor 2 (250,height - 400,width-100,10)] # Floor 3 # Define Colors white = (255,255,255) black = (0,0,0) red = (255,0,0) green = (0,255,0) blue = (0,0,255) # set up assets folders game_folder = os.path.dirname(__file__) image_folder = os.path.join(game_folder, "Image") sound_folder = os.path.join(game_folder, "Sound") # Initialize pygame and create window pygame.init() pygame.mixer.init() screen = pygame.display.set_mode((width,height)) pygame.display.set_caption(title) clock = pygame.time.Clock() # Load all game graphics background = pygame.image.load(path.join(image_folder, "background.png")).convert() background_rect = background.get_rect() no_mvmt_0 = pygame.image.load(path.join(image_folder,"no_mvmt_0.png")).convert() no_mvmt_1 = pygame.image.load(path.join(image_folder,"no_mvmt_1.png")).convert() running_0 = pygame.image.load(path.join(image_folder,"running_0.png")).convert() running_1 = pygame.image.load(path.join(image_folder,"running_1.png")).convert() jumping_0 = pygame.image.load(path.join(image_folder,"jumping_0.png")).convert() mini_no_mvmt = pygame.transform.scale(no_mvmt_0, (25,48)) mini_no_mvmt.set_colorkey(white) scissors = pygame.image.load(path.join(image_folder,"scissors.png")).convert() mob_left = pygame.image.load(path.join(image_folder,"mob_left.png")).convert() power_upper_image = {} power_upper_image['shield_0'] = pygame.image.load(path.join(image_folder,"shield_upper_0.png")).convert() power_upper_image['shield_1'] = pygame.image.load(path.join(image_folder,"shield_upper_1.png")).convert() power_upper_image['shield_2'] = pygame.image.load(path.join(image_folder,"shield_upper_2.png")).convert() power_upper_image['life'] = pygame.image.load(path.join(image_folder,"life_upper.png")).convert() power_upper_image['power'] = pygame.image.load(path.join(image_folder,"power.png")).convert() explosion_animation = {} explosion_animation['normal']=[] explosion_animation['small']=[] explosion_animation['player']=[] for explosion in range(5): explose = 'explosion_{}.png'.format(explosion) image = pygame.image.load(path.join(image_folder, explose)).convert() image.set_colorkey(white) image.set_colorkey(black) image_normal = pygame.transform.scale(image, (80,80)) explosion_animation['normal'].append(image_normal) image_small = pygame.transform.scale(image, (30, 30)) explosion_animation['small'].append(image_small) death = 'dying_{}.png'.format(explosion) image = pygame.image.load(path.join(image_folder, death)).convert() image.set_colorkey(white) explosion_animation['player'].append(image) #Load all game sounds scream_sound = [] for scream in ["slightscream_0.wav", "slightscream_1.wav", "slightscream_2.wav", "slightscream_3.wav", "slightscream_4.wav", "slightscream_5.wav", "slightscream_6.wav", "slightscream_7.wav", "slightscream_8.wav", "slightscream_9.wav", "slightscream_10.wav", "slightscream_11.wav", "slightscream_12.wav", "slightscream_13.wav", "slightscream_14.wav"]: scream_sound.append(pygame.mixer.Sound(path.join(sound_folder,scream))) shoot_sound = pygame.mixer.Sound(path.join(sound_folder,"shoot.wav")) shield = pygame.mixer.Sound(path.join(sound_folder,"shield.wav")) life = pygame.mixer.Sound(path.join(sound_folder,"life.wav")) special_power = pygame.mixer.Sound(path.join(sound_folder,"special_power.wav")) death_sound = pygame.mixer.Sound(path.join(sound_folder,"death.ogg")) explosion_sound = [] for sound in ["explosion.wav", "explosion_2.wav"]: explosion_sound.append(pygame.mixer.Sound(path.join(sound_folder, sound))) pygame.mixer.music.load(path.join(sound_folder,"gameplay.ogg")) pygame.mixer.music.set_volume(0.6) font_name = pygame.font.match_font('arial') def draw_text (surf, text,color,size, x, y): font = pygame.font.Font(font_name, size) text_surface = font.render(text, True, color) text_rect = text_surface.get_rect() text_rect.midtop = (x, y) surf.blit(text_surface, text_rect) def newmob(): m = Mobs() all_sprites.add(m) mobs.add(m) def draw_shield_bar(screen, x,y,percentage): if percentage < 0: percentage = 0 bar_lenght = 100 bar_height = 10 fill = (percentage / 100) * bar_lenght outline_rect = pygame.Rect(x,y,bar_lenght,bar_height) fill_rect = pygame.Rect(x,y,fill, bar_height) pygame.draw.rect(screen, green, fill_rect) pygame.draw.rect(screen, black, outline_rect, 2) # 2 is the the number of pixels # of how wide you want the outline # of the rectangle to be def draw_lives (surface, x, y, lives, image): for i in range(lives): image_rect = image.get_rect() image_rect.x = x + 30 * i image_rect.y = y surface.blit(image, image_rect) score = 0 def show_game_over_screen(): screen.blit(background, background_rect) draw_text(screen, "Dang..!",red,100, width/2, 200) draw_text(screen, "Score: " + str(score),blue,30, width/2, 330) draw_text(screen, "Press any key to retry",blue,30, width/2, 390) pygame.display.flip() waiting = True while waiting: clock.tick(FPS) for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() if event.type == pygame.KEYUP: waiting = False def show_start_screen(): screen.blit(background, background_rect) draw_text(screen,"Parkourse!", green, 100, width/2, 200) draw_text(screen, "Use the arrow keys to move, S to fire, and space to Jump",blue,30, width/2, 330) draw_text(screen, "Press any key to begin",blue,30, width/2, 390) pygame.display.flip() waiting = True while waiting: clock.tick(FPS) for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() if event.type == pygame.KEYUP: waiting = False class Player (pygame.sprite.Sprite): # Sprite for the player def __init__(self): pygame.sprite.Sprite.__init__(self) self.load_movement_images() self.image = self.standing_frame[0] self.rect = self.image.get_rect() self.pos = vec(50,500) self.vel = vec(0,0) self.acc = vec(0,0) self.shield = 100 self.lives = 3 self.hidden = False self.hide_timer = pygame.time.get_ticks() self.power = 1 self.power_timer = pygame.time.get_ticks() self.running = False self.jumping = False self.current_frame = 0 self.last_update = 0 def load_movement_images(self): self.standing_frame = [no_mvmt_0, no_mvmt_1] self.running_frame_right = [running_0,running_1] self.running_frame_left = [] for frame in self.standing_frame: frame.set_colorkey(white) for frame in self.running_frame_right: self.running_frame_left.append(pygame.transform.flip(frame,True,False)) # True is horizontaly, False is vertically frame.set_colorkey(white) self.jumping_frame = jumping_0 self.jumping_frame.set_colorkey(white) def animate(self): now = pygame.time.get_ticks() if not self.jumping and not self.running: if now - self.last_update > 350: self.last_update = now self.current_frame = (self.current_frame + 1) % len(self.standing_frame) self.image = self.standing_frame def jump(self): # Jump only if standing on a Platform self.rect.x +=1 hits = pygame.sprite.spritecollide(player,platforms, False) self.rect.x -= 1 if hits: self.vel.y = - player_jump def update(self): self.animate() # timeout for powerups if self.power >=2 and pygame.time.get_ticks() - self.power_time > POWERUP_TIME: self.power -= 1 self.power_time = pygame.time.get_ticks() # unhide if hidden if self.hidden and pygame.time.get_ticks() - self.hide_timer > 1000: self.hidden = False self.pos = vec(30, 400) self.acc = vec(0,player_gravity) keystate = pygame.key.get_pressed() if keystate[pygame.K_LEFT] or keystate[pygame.K_a]: self.acc.x = -player_acceleration if keystate[pygame.K_RIGHT] or keystate[pygame.K_d]: self.acc.x = player_acceleration if keystate[pygame.K_SPACE]: player.jump() # apply friction self.acc.x += self.vel.x * player_friction # equations of motions self.vel += self.acc self.pos += self.vel + 0.5 * self.acc # wrap around the sides of the screen if self.pos.x > 750: self.pos.x = 750 if self.pos.x <= 0: self.pos.x = 25 self.rect.midbottom = self.pos def powerup(self): self.power += 1 self.power_time = pygame.time.get_ticks() def shoot(self): if self.power == 1: bullet = Bullet(self.pos.x + 5, self.pos.y - 20) all_sprites.add(bullet) bullets.add(bullet) shoot_sound.play() if self.power >= 2: bullet1 = Bullet(self.pos.x + 5, self.pos.y - 20) bullet2 = Bullet(self.pos.x + 35, self.pos.y -20) all_sprites.add(bullet1) all_sprites.add(bullet2) bullets.add(bullet1) bullets.add(bullet2) shoot_sound.play() def hide(self): # hide the player temporarily self.hidden = True self.hide_timer = pygame.time.get_ticks() self.pos = vec(0, 6000) class Bullet(pygame.sprite.Sprite): def __init__(self, x, y): pygame.sprite.Sprite.__init__(self) self.image = scissors self.rect = self.image.get_rect() self.image.set_colorkey(white) self.image = pygame.transform.scale(scissors, (30,15)) self.rect.bottom = y self.rect.centerx = x self.speedx = 10 def update(self): self.rect.x += self.speedx # kill if it moves off the top of the screen if self.rect.bottom < 0: self.kill() class Mobs(pygame.sprite.Sprite): def __init__(self): pygame.sprite.Sprite.__init__(self) self.image = mob_left self.rect = self.image.get_rect() self.image.set_colorkey(white) self.rect.x = random.randrange(0,800) self.rect.y = 530 self.speedx = 2 def update(self): self.rect.x -= self.speedx if self.rect.right < 0: self.rect.x = 800 class Explosion(pygame.sprite.Sprite): def __init__(self, center, size, frame): pygame.sprite.Sprite.__init__(self) self.size = size self.image = explosion_animation[self.size][0] self.rect = self.image.get_rect() self.rect.center = center self.frame = 0 self.last_update = pygame.time.get_ticks() self.frame_rate = frame 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(explosion_animation[self.size]): self.kill() else: center = self.rect.center self.image = explosion_animation[self.size][self.frame] self.rect = self.image.get_rect() self.rect.center = center class Normal_Power(pygame.sprite.Sprite): def __init__(self, center): pygame.sprite.Sprite.__init__(self) self.type = random.choice(['shield_0','shield_1','shield_2']) self.image = power_upper_image[self.type] self.rect = self.image.get_rect() self.image.set_colorkey(white) self.rect.center = center class Special_Power(pygame.sprite.Sprite): def __init__(self, center): pygame.sprite.Sprite.__init__(self) self.type = random.choice(['life','power']) self.image = power_upper_image[self.type] self.rect = self.image.get_rect() self.image.set_colorkey(white) self.rect.center = center class Platform(pygame.sprite.Sprite): def __init__(self, x, y, w, h): pygame.sprite.Sprite.__init__(self) self.image = pygame.Surface((w, h)) self.image.fill(black) self.rect = self.image.get_rect() self.rect.x = x self.rect.y = y pygame.mixer.music.play(loops=-1) # loops = -1 means that pygame will restart the song when it's finished # Game loop running = True new_game = True game_over = False while running: if new_game: show_start_screen() new_game = False all_sprites = pygame.sprite.Group() platforms = pygame.sprite.Group() for plat in platforms_list: p = Platform (*plat) all_sprites.add(p) platforms.add(p) mobs = pygame.sprite.Group() player = Player() all_sprites.add(player) bullets = pygame.sprite.Group() powerups = pygame.sprite.Group() for i in range(1): newmob() score = 0 if game_over: show_game_over_screen() game_over = False all_sprites = pygame.sprite.Group() platforms = pygame.sprite.Group() for plat in platforms_list: p = Platform (*plat) all_sprites.add(p) platforms.add(p) mobs = pygame.sprite.Group() player = Player() all_sprites.add(player) bullets = pygame.sprite.Group() powerups = pygame.sprite.Group() for i in range(1): newmob() score = 0 # Keep loop running at the right speed clock.tick(FPS) # Process input (events) for event in pygame.event.get(): if event.type == pygame.QUIT: running = False if event.type == pygame.KEYDOWN: if event.key == pygame.K_s: player.shoot() # Updates all_sprites.update() # check if player hits a platform - only if falling if player.vel.y > 0: hits = pygame.sprite.spritecollide(player,platforms,False) if hits: player.pos.y = hits[0].rect.top player.vel.y = 0 # check to see if a bullet hit a mob hits = pygame.sprite.groupcollide(mobs,bullets,True,True) for hit in hits: score += 1 random.choice(explosion_sound).play() expl = Explosion(hit.rect.center, 'normal', 50) all_sprites.add(expl) if random.random() > 0.75: power = Normal_Power(hit.rect.center) all_sprites.add(power) powerups.add(power) if random.random() > 0.90: lives = Special_Power(hit.rect.center) all_sprites.add(lives) powerups.add(lives) newmob() # check to see if the mob hit the player hits = pygame.sprite.spritecollide(player, mobs,True) for hit in hits: random.choice(explosion_sound).play() player.shield -= 25 newmob() expl = Explosion(hit.rect.center, 'small', 50) all_sprites.add(expl) if player.shield <= 0: death_sound.play() death_animation = Explosion(player.rect.center, 'player', 100) all_sprites.add(death_animation) player.hide() player.lives -= 1 player.shield = 100 else: random.choice(scream_sound).play() # check if the player hit a powerup hits = pygame.sprite.spritecollide(player, powerups, True) for hit in hits: if hit.type == 'shield_0': player.shield += 5 if player.shield >= 100: player.shield = 100 shield.play() if hit.type == 'shield_1': player.shield += 20 if player.shield >= 100: player.shield = 100 shield.play() if hit.type == 'shield_2': player.shield += 20 if player.shield >= 100: player.shield = 100 shield.play() if hit.type == 'life': player.lives += 1 if player.lives >= 3: player.lives = 3 life.play() if hit.type == 'power': special_power.play() player.powerup() # if the player died and the explosion finished playing if player.lives == 0 and not death_animation.alive(): game_over = True # Draw / Render screen.fill(white) screen.blit(background, background_rect) all_sprites.draw(screen) draw_text(screen,str(score),red,30, width/ 2, 30) draw_text(screen,"Score:",red,30, width / 2, 3) draw_shield_bar(screen,90,20, player.shield) draw_lives(screen,95,40,player.lives, mini_no_mvmt) # *after* drawing everything, flip the display pygame.display.flip() pygame.quit() quit()
The error is caused by a sprite in your all_sprites group that has a list as its self.image attribute. I've just printed the sprites before the all_sprites.draw(screen) line for sprite in all_sprites: print(sprite, sprite.image) and it was the player sprite which had a list as its image. <Player sprite(in 1 groups)> [<Surface(40x25x32 SW)>, <Surface(40x25x32 SW)>] In the load_movement_images method you define self.standing_frame as a list of two images/pygame.Surfaces and in __init__ you set self.image to the first item of that list. But in the animate method you set self.image to the whole list instead of the active image self.image = self.standing_frame and that leads to the error. class Player (pygame.sprite.Sprite): # Sprite for the player def __init__(self): pygame.sprite.Sprite.__init__(self) self.load_movement_images() # self.image is the first image in the # self.standing_frame list. self.image = self.standing_frame[0] # ... def load_movement_images(self): self.standing_frame = [no_mvmt_0, no_mvmt_1] # ... def animate(self): now = pygame.time.get_ticks() if not self.jumping and not self.running: if now - self.last_update > 350: self.last_update = now self.current_frame = (self.current_frame + 1) % len(self.standing_frame) # Here you set the self.image to the self.standing_fram list instead one image. self.image = self.standing_frame # It should be: # self.image = self.standing_frame[self.current_frame]
Pygame: Accessing colliding sprite's properties using spritecollide()
I am building a top down shooter in the style of Raiden 2. I need to know how to get access to the enemy object when I detect collision using 'spritecollide'. The reason I need the enemy object is so that I can lower their energy level for every bullet that hits them. This is the dictionary that I have to work with: enemyCollisions = pygame.sprite.groupcollide(shipBulletGroup, enemyGroup, True, False) Here's my Bullet class: class Bullet(Entity): def __init__(self, ship, angle): Entity.__init__(self) self.speed = 8 self.level = 0 self.image = pygame.Surface((BULLET_DIMENSIONS, BULLET_DIMENSIONS)).convert() self.rect = self.image.get_rect() self.rect.x = ship.rect.centerx self.rect.y = ship.rect.top self.angle = angle def update(self, enemyGroup): if self.rect.bottom < 0: self.kill() else: self.rect.y -= self.speed Here's my unfinished Enemy class: class Enemy_1(Entity): def __init__(self): Entity.__init__(self) self.speed = (1, 1) self.energy = 10 self.begin = False self.run = False self.image = pygame.Surface((WIN_W/5, WIN_H/15)).convert() self.image.fill((70, 70, 70)) self.rect = self.image.get_rect() self.rect.centerx = WIN_W/1.333 self.rect.y = -WIN_H/15 def shoot(self): bullet_1 = Bullet(self, 270) bullet_2 = Bullet(self, 225) bullet_3 = Bullet(self, 315) def update(self, enemyGroup, timer): if timer == 300: self.begin = True elif timer == 900: self.run = True elif timer > 900 and self.rect.x > WIN_W: self.remove(enemyGroup) if self.run: self.rect.x += self.speed[0] self.rect.y += self.speed[1] elif self.begin: self.rect.y += self.speed[1] if self.rect.y > WIN_H/4: self.rect.y = WIN_H/4 if self.energy == 0: self.kill() Here's the complete program: import sys, pygame, os, random, math from ast import literal_eval # Force static position of screen os.environ['SDL_VIDEO_CENTERED'] = '1' # Constants LEFT = 'left' RIGHT = 'right' BLACK = (0, 0, 0) WHITE = (255, 255, 255) PILL_WIDTH = 5 PILL_HEIGHT = 20 WIN_W = 500 WIN_H = 800 SHIP_WIDTH = WIN_W/15 SHIP_HEIGHT = WIN_H/15 BULLET_DIMENSIONS = 5 TIMER = 0 class Entity(pygame.sprite.Sprite): def __init__(self): pygame.sprite.Sprite.__init__(self) class Text(Entity): def __init__(self, text, size, color, position, font=None): Entity.__init__(self) self.color = color self.font = pygame.font.Font(font, size) self.text = text self.set(text, position) def set(self, text, position): self.image = self.font.render(str(text), 1, self.color) self.rect = self.image.get_rect() self.rect.move_ip(position[0]-self.rect.width/2, (position[1]-self.rect.height)/2) class Ship(Entity): def __init__(self, container): Entity.__init__(self) self.speed = 5 self.score = 0 self.image = pygame.Surface((SHIP_WIDTH, SHIP_HEIGHT)).convert() self.rect = self.image.get_rect() self.rect.centerx = container.centerx self.rect.y = container.centery def update(self, bulletGroup): key = pygame.key.get_pressed() if key[pygame.K_w]: self.rect.centery -= self.speed if key[pygame.K_s]: self.rect.centery += self.speed if key[pygame.K_d]: self.rect.centerx += self.speed if key[pygame.K_a]: self.rect.centerx -= self.speed if key[pygame.K_SPACE]: if TIMER % 7 == 0: bullet = Bullet(self, 90, 'friend') bulletGroup.add(bullet) # Ship Movement Boundaries if self.rect.y < WIN_H/25: self.rect.y = WIN_H/25 if self.rect.y > WIN_H - SHIP_HEIGHT: self.rect.y = WIN_H - SHIP_HEIGHT if self.rect.x < 0: self.rect.x = 0 if self.rect.x > WIN_W - SHIP_WIDTH: self.rect.x = WIN_W - SHIP_WIDTH class Bullet(Entity): def __init__(self, ship, angle, type): Entity.__init__(self) self.speed = 8 self.level = 0 self.image = pygame.Surface((BULLET_DIMENSIONS, BULLET_DIMENSIONS)).convert() self.rect = self.image.get_rect() self.dx = math.cos(math.radians(angle)) * self.speed self.dy = math.sin(math.radians(angle)) * self.speed self.setXY(ship, type) def setXY(self, ship, type): self.rect.x = ship.rect.centerx if type == 'friend': self.rect.y = ship.rect.top elif type == 'enemy': self.rect.y = ship.rect.bottom def update(self): if self.rect.bottom < 0: self.kill() else: self.rect.x -= self.dx self.rect.y -= self.dy if type == 'friend': self.rect.y = -self.rect.y self.rect.x = -self.rect.x class Powerup(Entity): def __init__(self, xden, pillCount): Entity.__init__(self) self.speed = 3 self.density = xden self.image = pygame.Surface((PILL_WIDTH, PILL_HEIGHT)).convert() self.rect = self.image.get_rect() self.rect = self.rect.move(100,100) def restart(self): pass def update(self): if self.rect.y > WIN_H: del self else: self.rect = self.rect.move((0, self.speed)) class Enemy(Entity): def __init__(self): Entity.__init__(self) self.begin = False self.run = False self.color = (153, 0, 76) class Planes(Enemy): def __init__(self, speed, energy, size, location): Enemy.__init__(self) self.speed = speed self.energy = energy self.image = pygame.Surface(size).convert() self.image.fill(self.color) self.rect = self.image.get_rect() self.rect.centerx = location[0] self.rect.y = location[1] def shoot(self, enemyBulletGroup): bullet_1 = Bullet(self, 240, 'enemy') bullet_2 = Bullet(self, 270, 'enemy') bullet_3 = Bullet(self, 300, 'enemy') enemyBulletGroup.add(bullet_1, bullet_2, bullet_3) def update(self, enemyGroup, enemyBulletGroup): if TIMER == 300: self.begin = True elif TIMER == 900: self.run = True elif self.rect.x > WIN_W or self.energy == 0: self.kill() if self.run: self.rect.x += self.speed[0] self.rect.y += self.speed[1] if TIMER % 100 == 0: self.shoot(enemyBulletGroup) elif self.begin: self.rect.y += self.speed[1] if self.rect.y > WIN_H/4: self.rect.y = WIN_H/4 if TIMER % 100 == 0: self.shoot(enemyBulletGroup) def main(): # Initialize Everything pygame.init() global TIMER fps = 60 lLeft = lRight = lUp = lDown = shoot = False clock = pygame.time.Clock() play = True pygame.display.set_caption('Pong') screen = pygame.display.set_mode((WIN_W, WIN_H), pygame.SRCALPHA) # Create Game Objects ship = Ship(pygame.rect.Rect(0, 0, WIN_W, WIN_H)) score1 = Text("Score: " + str(ship.score), 40, BLACK, (WIN_W/2, (WIN_H/25))) enemy_1 = Planes((1, 1), 10, (WIN_W/5, WIN_H/15), (WIN_W/1.4, -WIN_H/15)) # Create Groups powerupGroup = pygame.sprite.Group() shipGroup = pygame.sprite.Group() shipGroup.add(ship) textGroup = pygame.sprite.Group() textGroup.add(score1) shipBulletGroup = pygame.sprite.Group() enemyBulletGroup = pygame.sprite.Group() enemyGroup = pygame.sprite.Group() enemyGroup.add(enemy_1) # Gameplay while play: # Checks if window exit button pressed for event in pygame.event.get(): if event.type == pygame.QUIT: sys.exit() elif event.type == pygame.KEYDOWN: if event.key == pygame.K_ESCAPE: pygame.quit() sys.exit() # Update powerupGroup.update() ship.update(shipBulletGroup) shipBulletGroup.update() textGroup.update() enemyGroup.update(enemyGroup, enemyBulletGroup) enemyBulletGroup.update() enemyCollisions = pygame.sprite.groupcollide(shipBulletGroup, enemyGroup, True, False) for key in enemyCollisions: print enemyCollisions[key].energy # Print Background/Sprites screen.fill(WHITE) powerupGroup.draw(screen) shipGroup.draw(screen) shipBulletGroup.draw(screen) textGroup.draw(screen) enemyGroup.draw(screen) enemyBulletGroup.draw(screen) # Print Score Bar hori_partition = pygame.Surface((WIN_W, 1)) screen.blit(hori_partition, (0, WIN_H/25)) TIMER += 1 # Limits frames per iteration of while loop clock.tick(fps) # Writes to main surface pygame.display.flip() if __name__ == "__main__": main()
The pygame.sprite.groupcollide() function returns a dictionary which values are list objects: Every Sprite inside group1 is added to the return dictionary. The value for each item is the list of Sprites in group2 that intersect. Thats the reason why calling print enemyCollisions[key].energy when iterating over the return dict fails, since a list object -- the value of enemyCollisions[key] -- does not have an energy() method. To access all values of a dictionary in Python 2.X you could use the .itervalues() method of a dict instance. To get each colliding sprite, iterate again over these values: enemyCollisions = pygame.sprite.groupcollide(shipBulletGroup, enemyGroup, True, False) #iterate over all values of the enemyCollisions dict for enemyCollisions in enemyCollisions.itervalues(): #access all enemies which collided with an shipBullet for enemy in enemyCollisions: print enemy.energy
The syntax for accessing the collided sprite's property is as follows: collisions = pygame.sprite.spritecollide(self, pillGroup, True) for key in collisions: self.density += key.density