This question already has answers here:
How can i shoot a bullet with space bar?
(1 answer)
How do I stop more than 1 bullet firing at once?
(1 answer)
Pygame: problems with shooting in Space Invaders
(1 answer)
Closed 1 year ago.
I am setting up a game were the main character spits fireballs at is enemies. When I spam the f key, when the fireball has used up its four seconds, it remains at the end of the screen.
I have not tried anything to solve this problem. This is because I have no clue of how to even start to solve this problem.
#Importing Modules
from random import randint
from pygame.locals import *
import pygame
import sys
import os
from time import sleep
# intalize Pygame
pygame.init()
# Set Up Screen
x_size = 1200
y_size = 750
screen = pygame.display.set_mode((x_size, y_size))
game_folder = os.path.dirname(__file__)
img_folder = os.path.join(game_folder, 'images')
player_img = pygame.image.load(os.path.join(img_folder, 'happy_face.png')).convert()
food_img = pygame.image.load(os.path.join(img_folder, 'food.png')).convert()
BAD_food_img = pygame.image.load(os.path.join(img_folder, 'bad_food.png')).convert()
fire_ball_img = pygame.image.load(os.path.join(img_folder, 'fire_ball.png')).convert()
enemy_img = pygame.image.load(os.path.join(img_folder, 'enemy.png')).convert()
# Varible Used "while" Loop
done = False
# Setting Caption of Pygame Tab
pygame.display.set_caption("Block Rush Game")
# Colors
WHITE = (255,255,255)
BLACK = (0,0,0)
RED = (255,0,0)
GREEN = (0,255,0)
BLUE = (0,0,255)
Lime = (0,255,0)
Yellow = (255,255,0)
Aqua = (0,255,255)
Magenta = (255,0,255)
Silver = (192,192,192)
Gray = (128,128,128)
Maroon = (128,0,0)
Olive = (128,128,0)
Purple = (128,0,128)
Teal = (0,128,128)
Navy = (0,0,128)
WIDTH = 50
HEIGHT = 50
clock = pygame.time.Clock()
class Player(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = player_img
self.rect = self.image.get_rect()
self.rect.center = (x_size // 2, y_size // 2)
self.rect.x = x_size / 2
self.rect.y = y_size / 2
def move_right(self):
self.rect.x += 20
def move_left(self):
self.rect.x += -20
def move_up(self):
self.rect.y += -20
def move_down(self):
self.rect.y += 20
def grow(self):
width, height = self.image.get_size()
self.image = pygame.transform.scale(player_img, (int(width + 20),int(height + 20)))
self.rect = self.rect.inflate(20,20)
def anti_grow(self):
width, height = self.image.get_size()
self.image = pygame.transform.scale(player_img, (int(width - 20), int(height - 20)))
self.rect = self.rect.inflate(-20,-20)
def super_anti_grow(self):
width, height = self.image.get_size()
self.image = pygame.transform.scale(player_img, (int(width - 40),int(height - 40)))
self.rect = self.rect.inflate(-40,-40)
def super_grow(self):
width, height = self.image.get_size()
self.image = pygame.transform.scale(player_img, (int(width + 40),int(height + 40)))
self.rect = self.rect.inflate(40,40)
class Food(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = food_img
self.rect = self.image.get_rect()
self.rect.center = (WIDTH / 2, HEIGHT / 2)
self.rect.x = randint(0,x_size*5)
self.rect.y = randint(0,y_size*5)
def move_right(self):
self.rect.x += -20
def move_left(self):
self.rect.x += 20
def move_up(self):
self.rect.y += 20
def move_down(self):
self.rect.y += -20
class BAD_Food(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = BAD_food_img
self.rect = self.image.get_rect()
self.rect.center = (WIDTH / 2, HEIGHT / 2)
self.rect.x = randint(-x_size*2.5,x_size*2.5)
self.rect.y = randint(0,y_size*5)
def move_right(self):
self.rect.x += -20
def move_left(self):
self.rect.x += 20
def move_up(self):
self.rect.y += 20
def move_down(self):
self.rect.y += -20
class FireBall(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = fire_ball_img
self.rect = self.image.get_rect()
self.rect.center = (WIDTH / 2, HEIGHT / 2)
self.rect.x = x_size/2
self.rect.y = y_size/2
self.cooldown = 4000
self.last = pygame.time.get_ticks()
def move(self):
self.rect.x += 20
class Enemy(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = enemy_img
self.rect = self.image.get_rect()
self.rect.center = (WIDTH / 2, HEIGHT / 2)
self.rect.x = randint(-x_size*2.5,x_size*2.5)
self.rect.y = randint(0,y_size*5)
def move_right(self):
self.rect.x += -20
def move_left(self):
self.rect.x += 20
def move_up(self):
self.rect.y += 20
def move_down(self):
self.rect.y += -20
all_sprites = pygame.sprite.Group()
food_list = []
BAD_food_list = []
enemy_list = []
player = Player()
all_sprites.add(player)
all_food = []
for i in range(100):
food = Food()
all_sprites.add(food)
food_list.append(food)
all_food.append(food)
for i in range(100):
BAD_food = BAD_Food()
all_sprites.add(BAD_food)
BAD_food_list.append(BAD_food)
all_food.append(BAD_food)
for i in range(100):
enemy = Enemy()
all_sprites.add(enemy)
enemy_list.append(enemy)
all_food.append(enemy)
x_cor_player = x_size*5/2
y_cor_player = y_size*5/2
# Most important code here
fireball = None
while not done:
clock.tick(120)
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
if event.type == KEYDOWN:
if event.key == K_w:
for food in all_food:
food.move_up()
y_cor_player += 20
if y_cor_player > y_size * 5:
player.move.down
elif player.rect.centery < y_size // 2:
player.move_down()
if event.key == K_s:
for food in all_food:
food.move_down()
y_cor_player += -20
if y_cor_player < 0:
player.move_up()
elif player.rect.centery > y_size // 2:
player.move_up
if event.key == K_a:
for food in all_food:
food.move_left()
x_cor_player += -20
if x_cor_player < 0:
player.move_right()
elif player.rect.centerx < x_size // 2:
player.move_right()
if event.key == K_d:
for food in all_food:
food.move_right()
x_cor_player += 20
if x_cor_player > x_size * 5:
player.move_left()
elif player.rect.centerx > x_size // 2:
player.move_left()
if event.key == K_f:
if fireball is None or pygame.time.get_ticks() - fireball.last >= fireball.cooldown:
fireball = FireBall()
all_sprites.add(fireball)
for food in food_list:
if player.rect.colliderect(food):
food.kill()
food_list.remove(food)
all_food.remove(food)
player.grow()
for foodz in BAD_food_list:
if player.rect.colliderect(foodz):
foodz.kill()
BAD_food_list.remove(foodz)
all_food.remove(foodz)
player.anti_grow()
for enemy in enemy_list:
if player.rect.colliderect(enemy):
enemy.kill()
enemy_list.remove(enemy)
all_food.remove(enemy)
player.super_anti_grow()
elif fireball != None:
if fireball.rect.colliderect(enemy):
enemy.kill()
enemy_list.remove(enemy)
all_food.remove(enemy)
player.super_grow()
if fireball is not None:
fireball.move()
if pygame.time.get_ticks() - fireball.last >= fireball.cooldown:
fireball.kill()
fireball = None
screen.fill(BLACK)
all_sprites.draw(screen)
pygame.display.update()
pygame.quit()
The expected result is that when ever I press the f key a fireball should spawn and live for 4 seconds. The actual result is that when ever I spam the f key the fireball stays at the end of the screen and doesn't spawn again.
First of all note, that the operation .kill() on a pygame.sprite.Sprite object, remove the Sprite from all Groups. So there is no need to remove the Sprite explicitly from a Group, after calling .kill().
Remove the variable fireball and all it usage from the entire program. Turen food_list, BAD_food_list, enemy_list and all_food to a pygame.sprite.Group. add a further Group for the fireballs. Note you've to use .add rather than append to add objects to the Group:
all_sprites = pygame.sprite.Group()
fire_balls = pygame.sprite.Group()
food_list = pygame.sprite.Group()
BAD_food_list = pygame.sprite.Group()
enemy_list = pygame.sprite.Group()
all_food = pygame.sprite.Group()
for i in range(100):
food = Food()
all_sprites.add(food)
food_list.add(food)
all_food.add(food)
for i in range(100):
BAD_food = BAD_Food()
all_sprites.add(BAD_food)
BAD_food_list.add(BAD_food)
all_food.add(BAD_food)
for i in range(100):
enemy = Enemy()
all_sprites.add(enemy)
enemy_list.add(enemy)
all_food.add(enemy)
Adapt the method move of the FireBall object. selk.kill() the object if 4 seconds are elapsed:
class FireBall(pygame.sprite.Sprite):
# [...]
def move(self):
self.rect.x += 20
if pygame.time.get_ticks() - self.last >= self.cooldown:
self.kill()
Spawn a new fireball when ever f is pressed:
while not done:
clock.tick(120)
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
if event.type == KEYDOWN:
# [...]
if event.key == K_f:
fireball = FireBall()
all_sprites.add(fireball)
fire_balls.add(fireball)
Use pygame.sprite.spritecollide to identify if the player collides with an object of a Group.
Use pygame.sprite.groupcollide() to find colliding enemies and fireballs.
When the 3rd respectively 4th parameter isTrue then the object is removed and killed:
while not done:
# [...]
for fireball in fire_balls:
fireball.move()
if pygame.sprite.spritecollide(player, food_list, True):
player.grow()
if pygame.sprite.spritecollide(player, BAD_food_list, True):
player.anti_grow()
if pygame.sprite.spritecollide(player, enemy_list, True):
player.super_anti_grow()
if pygame.sprite.groupcollide(fire_balls, enemy_list, False, True):
player.super_grow()
screen.fill(BLACK)
all_sprites.draw(screen)
pygame.display.update()
If the fireball should be "killed" when hitting an enemy, then you've to pass True to the 3rd parameter of pygame.sprite.groupcollide:
if pygame.sprite.groupcollide(fire_balls, enemy_list, Treu, True):
player.super_grow()
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.
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