Hello I am new to pygame and I am trying to write a shmup game.
However I am always having this error:
TypeError: add() argument after * must be an iterable, not int
self.add(*group)
This is the traceback of the error:
File "C:/Users/Pygame/game.py", line 195, in
player.shoot()
File "C:/Users/Pygame/game.py", line 78, in shoot
bullet = Bullets(self.rect.center,self.angle)
File "C:/Users/Pygame/game.py", line 124, in init
super(Bullets,self).init(pos,angle)
This is the code I have written so far, it works well however when the user wants to shoot the error is being raised.
import os
import pygame
import random
import math
WIDTH = 480
HEIGHT = 600
FPS = 60
#colors:
WHITE = (255,255,255)
BLACK = (0,0,0)
GREEN = (0,250,0)
RED = (255,0,0)
BLUE = (0,0,255)
YELLOW = (255,255,0)
#setup assets
game_folder = os.path.dirname("C:/Users/PygameP/")
img_folder = os.path.join(game_folder,"img")
#intialise pygame
pygame.init()
pygame.mixer.init()
screen = pygame.display.set_mode((WIDTH,HEIGHT))
clock = pygame.time.Clock()
class Player(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((50,40))
self.image.fill(GREEN)
self.rect = self.image.get_rect()
self.rect.centerx = WIDTH/2
self.rect.bottom = HEIGHT-10
#controls the speed
self.angle = 0
self.orig_image = self.image
#self.rect = self.image.get_rect(center=pos)
def update(self):
keystate = pygame.key.get_pressed()
if keystate[pygame.K_LEFT]:
self.angle -= 5
self.rotate()
if keystate[pygame.K_RIGHT]:
self.angle += 5
self.rotate()
def rotate(self):
self.image = pygame.transform.rotozoom(self.orig_image, self.angle, 1)
self.rect = self.image.get_rect(center=self.rect.center)
def shoot(self):
bullet = Bullets(self.rect.center,self.angle)
all_sprites.add(bullet)
bullets.add(bullet)
class Mob(pygame.sprite.Sprite):
def __init__(self):
super(Mob,self).__init__()
self.image = pygame.Surface((30,40))
self.image = meteor_img
self.image = pygame.transform.scale(meteor_img,(50,38))
self.image.set_colorkey(BLACK)
self.rect = self.image.get_rect()
self.radius = int(self.rect.width/2)
self.rect.x = random.randrange(0,WIDTH - self.rect.width)
self.rect.y = random.randrange(-100,-40)
self.speedy = random.randrange(1,8)
#updating the position of the sprite
def update(self):
self.rect.y += self.speedy
if self.rect.top > HEIGHT + 10:
self.rect.x = random.randrange(0,WIDTH - self.rect.width)
self.rect.y = random.randrange(-100,-40)
self.speedy = random.randrange(1,8)
class Bullets(pygame.sprite.Sprite):
def __init__(self,pos,angle):
super(Bullets,self).__init__(pos,angle)
# Rotate the image.
self.image = pygame.Surface((10,20))
self.image = bullet_img
self.image = pygame.transform.scale(bullet_img,(50,38))
self.image = pygame.transform.rotate(bullet_img, angle)
self.rect = self.image.get_rect()
speed = 5
self.velocity_x = math.cos(math.radians(-angle))*speed
self.velocity_y = math.sin(math.radians(-angle))*speed
#store the actual position
self.pos = list(pos)
def update(self):
self.pos[0] += self.velocity_x
self.pos[1] += self.velocity_y
self.rect.center = self.pos
if self.rect.bottom <0:
self.kill()
#load all game graphics
background = pygame.image.load(os.path.join(img_folder,"background.png")).convert()
background_rect = background.get_rect()
player_img = pygame.image.load(os.path.join(img_folder,"arrow.png")).convert()
bullet_img = pygame.image.load(os.path.join(img_folder,"bullet.png")).convert()
meteor_img = pygame.image.load(os.path.join(img_folder,"m.png")).convert()
#creating a group to store sprites to make it easier to deal with them
#every sprite we make goes to this group
all_sprites = pygame.sprite.Group()
mobs = pygame.sprite.Group()
bullets = pygame.sprite.Group()
player = Player()
all_sprites.add(player)
for i in range(8):
m = Mob()
all_sprites.add(m)
mobs.add(m)
running = True
while running:
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
player.shoot()
#Update
all_sprites.update()
#checking if a bullet hits a mob
hits = pygame.sprite.groupcollide(mobs,bullets,True,True)
for hit in hits:
m = Mob()
all_sprites.add(m)
mobs.add(m)
hits = pygame.sprite.spritecollide(player,mobs, False,pygame.sprite.collide_circle)
#drawing the new sprites here
screen.fill(BLACK)
#show the background image
screen.blit(background,background_rect)
all_sprites.draw(screen)
pygame.display.flip()
pygame.quit()
Any comments?
You're passing the pos and the angle to the __init__ method of pygame.sprite.Sprite here,
super(Bullets,self).__init__(pos,angle)
but you can only pass sprite groups to which this sprite instance will be added. So just remove those arguments:
super(Bullets,self).__init__()
Related
import pygame
import math
#initialise pygame
pygame.init()
#game window
WINDOW_WIDTH = 1200
WINDOW_HEIGHT = 750
#create game window
win = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))
pygame.display.set_caption('Castle Defender')
clock = pygame.time.Clock()
FPS = 60
#load images
background_img = pygame.image.load('Animations/BG.png').convert_alpha()
background = pygame.transform.scale(background_img,(1200,750))
castle_img = pygame.image.load('Animations/Castle.png').convert_alpha()
bullet_img = pygame.image.load('Animations/SmallBullet.png').convert_alpha()
b_w = bullet_img.get_width()
b_h = bullet_img.get_height()
bullet_img = pygame.transform.scale(bullet_img, (int(b_w * 0.075), int(b_h * 0.075)))
WHITE =(255,255,255)
#Castle class
class Castle():
def __init__(self, image, x, y, scale):
self.health = 1000
self.max_health = self.health
width = image.get_width()
height = image.get_height()
self.image = pygame.transform.scale(image, (int(width * scale), int(height * scale)))
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
def shoot(self):
pos = pygame.mouse.get_pos()
x_dist = pos[0] - self.rect.midleft[0]
y_dist = -(pos[1] - self.rect.midleft[1])
self.angle = math.degrees(math.atan2(y_dist, x_dist))
#mouseclick
if pygame.mouse.get_pressed()[0] and self.fired == False:
self.fired = True
bullet = Bullet(bullet_img, self.rect.right[0], self.rect.right[1], self.angle)
bullet_group.add(bullet)
#reset mouseclick
if pygame.mouse.get_pressed()[0] == False:
self.fired = False
#Method
def draw(self):
self.image = self.image
win.blit(self.image, self.rect)
class Bullet(pygame.sprite.Sprite):
def __init__(self, image, x, y, angle):
pygame.sprite.Sprite.__init__(self)
self.image = image
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.angle = math.radians(angle)
self.speed = 10
self.dx = math.cos(self.angle) * self.speed
self.dy = -(math.sin(self.angle) * self.speed)
def update(self):
#check if bullet has gone off the screen
if self.rect.right < 0 or self.rect.left > SCREEN_WIDTH or self.rect.bottom < 0 or self.rect.top > SCREEN_HEIGHT:
self.kill()
#move bullet
self.rect.x += self.dx
self.rect.y += self.dy
castle = Castle(castle_img, WINDOW_WIDTH - 1350, WINDOW_HEIGHT - 400, 0.7)
bullet_group = pygame.sprite.Group()
run = True
while run:
clock.tick(FPS)
win.blit(background, (0, 0))
castle.draw()
castle.shoot()
#bullet drawing
bullet_group.update()
bullet_group.draw(win)
print(len(bullet_group))
#event handler
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
#update display window
pygame.display.update()
pygame.quit()
I am trying to see the line from my base and my mouse. However I get an error of the following
bullet = Bullet(bullet_img, self.rect.right[0], self.rect.right[1], self.angle)
(My end goal is for bullets to come out of the castle and i am relatively new to coding and this will be my first project) . Also i keep getting an error when trying to submit this saying it is mostly code so the parenthisis was me rambling on
The issue the code is trying to use self.rect.right as if it was a python list. But self.rect.right is an integer.
self.rect.right[0]
self.rect.right[1]
Probably this should be self.rect.right and self.rect.top (since it deals with the y-dimension).
Then you also need to correct references to SCREEN_WIDTH and SCREEN_HEIGHT. It looks like these should be WINDOW_ etc.
After these changes are made, your program does not exit with an error when the mouse is clicked.
import pygame
import math
#initialise pygame
pygame.init()
#game window
WINDOW_WIDTH = 1200
WINDOW_HEIGHT = 750
#create game window
win = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))
pygame.display.set_caption('Castle Defender')
clock = pygame.time.Clock()
FPS = 60
#load images
background_img = pygame.image.load('Animations/BG.png').convert_alpha()
background = pygame.transform.scale(background_img,(1200,750))
castle_img = pygame.image.load('Animations/Castle.png').convert_alpha()
bullet_img = pygame.image.load('Animations/SmallBullet.png').convert_alpha()
b_w = bullet_img.get_width()
b_h = bullet_img.get_height()
bullet_img = pygame.transform.scale(bullet_img, (15,15))
WHITE =(255,255,255)
#Castle class
class Castle():
def __init__(self, image, x, y, scale):
self.health = 1000
self.max_health = self.health
self.fired = False
width = image.get_width()
height = image.get_height()
self.image = pygame.transform.scale(image, (int(width * scale), int(height * scale)))
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
def shoot(self):
pos = pygame.mouse.get_pos()
x_dist = pos[0] - self.rect.midright[0]
y_dist = -(pos[1] - self.rect.midtop[1])
self.angle = math.degrees(math.atan2(y_dist, x_dist))
#mouseclick
if pygame.mouse.get_pressed()[0] and self.fired == False:
self.fired = True
bullet = Bullet(bullet_img, self.rect.right, self.rect.top, self.angle)
bullet_group.add(bullet)
#reset mouseclick
if pygame.mouse.get_pressed()[0] == False:
self.fired = False
#Method
def draw(self):
self.image = self.image
win.blit(self.image, self.rect)
class Bullet(pygame.sprite.Sprite):
def __init__(self, image, x, y, angle):
pygame.sprite.Sprite.__init__(self)
self.image = image
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.angle = math.radians(angle) #angle to radians
self.speed = 10 # Speed !!!
self.dx = math.cos(self.angle) * self.speed #caculate speed of x
self.dy = -(math.sin(self.angle) * self.speed) # caculate speed of y
def update(self):
#check if bullet has gone off the screen
if self.rect.right < 0 or self.rect.left > WINDOW_WIDTH or self.rect.bottom < 0 or self.rect.top > WINDOW_HEIGHT:
self.kill()
#move bullet
self.rect.x += self.dx
self.rect.y += self.dy
castle = Castle(castle_img, WINDOW_WIDTH - 1350, WINDOW_HEIGHT - 400, 0.7)
bullet_group = pygame.sprite.Group()
run = True
while run:
clock.tick(FPS)
win.blit(background, (0, 0))
castle.draw()
castle.shoot()
#bullet drawing
bullet_group.update()
bullet_group.draw(win)
print(len(bullet_group))
#event handler
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
#update display window
pygame.display.update()
pygame.quit()
import pygame
import math
#initialise pygame
pygame.init()
#game window
WINDOW_WIDTH = 1200
WINDOW_HEIGHT = 750
#create game window
win = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))
pygame.display.set_caption('Castle Defender')
clock = pygame.time.Clock()
FPS = 60
#load images
background_img = pygame.image.load('Animations/BG.png').convert_alpha()
background = pygame.transform.scale(background_img,(1200,750))
castle_img = pygame.image.load('Animations/Castle.png').convert_alpha()
bullet_img = pygame.image.load('Animations/SmallBullet.png').convert_alpha()
b_w = bullet_img.get_width()
b_h = bullet_img.get_height()
bullet_img = pygame.transform.scale(bullet_img, (15,15))
WHITE =(255,255,255)
#Castle class
class Castle():
def __init__(self, image, x, y, scale):
self.health = 1000
self.max_health = self.health
width = image.get_width()
height = image.get_height()
self.image = pygame.transform.scale(image, (int(width * scale), int(height * scale)))
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
def shoot(self):
pos = pygame.mouse.get_pos()
x_dist = pos[0] - self.rect.midleft[0]
y_dist = -(pos[1] - self.rect.midleft[1])
self.angle = math.degrees(math.atan2(y_dist, x_dist))
#mouseclick
if pygame.mouse.get_pressed()[0] and self.fired == False:
self.fired = True
bullet = Bullet(bullet_img, self.rect.right[0], self.rect.right[1], self.angle)
bullet_group.add(bullet)
#reset mouseclick
if pygame.mouse.get_pressed()[0] == False:
self.fired = False
#Method
def draw(self):
self.image = self.image
win.blit(self.image, self.rect)
class Bullet(pygame.sprite.Sprite):
def __init__(self, image, x, y, angle):
pygame.sprite.Sprite.__init__(self)
self.image = image
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.angle = math.radians(angle)
self.speed = 10
self.dx = math.cos(self.angle) * self.speed
self.dy = -(math.sin(self.angle) * self.speed)
def update(self):
#check if bullet has gone off the screen
if self.rect.right < 0 or self.rect.left > SCREEN_WIDTH or self.rect.bottom < 0 or self.rect.top > SCREEN_HEIGHT:
self.kill()
#move bullet
self.rect.x += self.dx
self.rect.y += self.dy
castle = Castle(castle_img, WINDOW_WIDTH - 1350, WINDOW_HEIGHT - 400, 0.7)
bullet_group = pygame.sprite.Group()
run = True
while run:
clock.tick(FPS)
win.blit(background, (0, 0))
castle.draw()
castle.shoot()
#bullet drawing
bullet_group.update()
bullet_group.draw(win)
print(len(bullet_group))
#event handler
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
#update display window
pygame.display.update()
pygame.quit()
import pygame
import math
#initialise pygame
pygame.init()
#game window
WINDOW_WIDTH = 1200
WINDOW_HEIGHT = 750
#create game window
win = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))
pygame.display.set_caption('Castle Defender')
clock = pygame.time.Clock()
FPS = 60
#load images
background_img = pygame.image.load('Animations/BG.png').convert_alpha()
background = pygame.transform.scale(background_img,(1200,750))
castle_img = pygame.image.load('Animations/Castle.png').convert_alpha()
bullet_img = pygame.image.load('Animations/SmallBullet.png').convert_alpha()
b_w = bullet_img.get_width()
b_h = bullet_img.get_height()
bullet_img = pygame.transform.scale(bullet_img, (int(b_w * 0.075), int(b_h * 0.075)))
WHITE =(255,255,255)
#Castle class
class Castle():
def __init__(self, image, x, y, scale):
self.health = 1000
self.max_health = self.health
width = image.get_width()
height = image.get_height()
self.image = pygame.transform.scale(image, (int(width * scale), int(height * scale)))
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
def shoot(self):
pos = pygame.mouse.get_pos()
x_dist = pos[0] - self.rect.midleft[0]
y_dist = -(pos[1] - self.rect.midleft[1])
self.angle = math.degrees(math.atan2(y_dist, x_dist))
#mouseclick
if pygame.mouse.get_pressed()[0] and self.fired == False:
self.fired = True
bullet = Bullet(bullet_img, self.rect.right[0], self.rect.right[1], self.angle)
bullet_group.add(bullet)
#reset mouseclick
if pygame.mouse.get_pressed()[0] == False:
self.fired = False
#Method
def draw(self):
self.image = self.image
win.blit(self.image, self.rect)
class Bullet(pygame.sprite.Sprite):
def __init__(self, image, x, y, angle):
pygame.sprite.Sprite.__init__(self)
self.image = image
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.angle = math.radians(angle)
self.speed = 10
self.dx = math.cos(self.angle) * self.speed
self.dy = -(math.sin(self.angle) * self.speed)
def update(self):
#check if bullet has gone off the screen
if self.rect.right < 0 or self.rect.left > SCREEN_WIDTH or self.rect.bottom < 0 or self.rect.top > SCREEN_HEIGHT:
self.kill()
#move bullet
self.rect.x += self.dx
self.rect.y += self.dy
castle = Castle(castle_img, WINDOW_WIDTH - 1350, WINDOW_HEIGHT - 400, 0.7)
bullet_group = pygame.sprite.Group()
run = True
while run:
clock.tick(FPS)
win.blit(background, (0, 0))
castle.draw()
castle.shoot()
#bullet drawing
bullet_group.update()
bullet_group.draw(win)
print(len(bullet_group))
#event handler
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
#update display window
pygame.display.update()
pygame.quit()
So my code works without producing an error but when i shoot my bullet it comes out of the topright of the rectangle for my castle whereas i want it to be near the middle as for my image it is just shooting from the middle of nowhere as my image is not a square.
The starting position of the bullet should be the center of the rectangle:
bullet = Bullet(bullet_img, self.rect.right, self.rect.top, self.angle)
bullet = Bullet(bullet_img, self.rect.centerx, self.rect.centery, self.angle)
Set the center position of the bullet rectangle instead of the top left position:
class Bullet(pygame.sprite.Sprite):
def __init__(self, image, x, y, angle):
pygame.sprite.Sprite.__init__(self)
self.image = image
self.rect = self.image.get_rect()
self.rect.centerx = x # <---
self.rect.centery = y # <---
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 am making the game space invaders in pygame and I managed to collide the enemybullet with the player. But i cannot collide the playerbullet with the enemy. I am doing exactly the same, I think. But it gives the error below.
At this moment the enemy shoots with the button TAB, when I got this working I want to let the enemy to shoot the randomly.
line 148, in
hitenemy = pygame.sprite.spritecollide(enemy, bulletsPlayer, True)
line 1513, in spritecollide
spritecollide = sprite.rect.colliderect
AttributeError: 'Group' object has no attribute 'rect'
import pygame, sys
from pygame.locals import *
import random
screenWidth = 800
screenHeight = 600
FPS = 60
pygame.init()
pygame.mixer.init()
screen = pygame.display.set_mode((screenWidth,screenHeight))
pygame.display.set_caption("Space Invaders")
clock = pygame.time.Clock()
shipWidth = 78
#colors
black=(0,0,0)
blue=(0,0, 255)
green=(0,128,0)
red=(255,0,0)
white=(255,255,255)
yellow=(255,255,0)
def app_quit():
pygame.quit()
sys.exit("System exit.")
class Player(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("spaceship7.png").convert()
self.image.set_colorkey(white)#make white transparant
self.rect = self.image.get_rect()
self.rect.centerx = screenWidth / 2
self.rect.bottom = screenHeight - 10
self.speedx = 0
def update(self):
self.speedx = 0
if event.type == KEYDOWN and event.key == K_LEFT:
self.speedx = -2
elif event.type == KEYDOWN and event.key == K_RIGHT:
self.speedx = 2
self.rect.x += self.speedx
if self.rect.right > screenWidth:
self.rect.right = screenWidth
if self.rect.left < 0:
self.rect.left = 0
def shootPlayer(self):
bulletPlayer = BulletPlayer(self.rect.centerx, self.rect.top)
allSprites.add(bulletPlayer)
bulletsPlayer.add(bulletPlayer)
class Enemy(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("enemy.png").convert()
self.image.set_colorkey(white)
self.rect = self.image.get_rect()
self.rect.x = 0
self.rect.y = random.randrange(0, 200)
self.speedx = random.randrange(1, 2)
def update(self):
self.rect.x += self.speedx
if self.rect.right > screenWidth:
self.rect.x = 50
self.rect.y = random.randrange(0, 250)
self.speedx = random.randrange(1, 3)
if self.rect.x > screenWidth:
self.kill()
def shootEnemy(self):
bulletEnemy = BulletEnemy(self.rect.centerx, self.rect.bottom)
allSprites.add(bulletEnemy)
bulletsEnemy.add(bulletEnemy)
class BulletPlayer(pygame.sprite.Sprite):
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("bullet.png").convert()
self.image.set_colorkey(white)
self.rect = self.image.get_rect()
self.rect.bottom = y
self.rect.centerx = x
self.speedy = -3
def update(self):
self.rect.y += self.speedy
if self.rect.bottom < 0:
self.kill()
class BulletEnemy(pygame.sprite.Sprite):
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("bulletenemy.png").convert()
self.image.set_colorkey(white)
self.rect = self.image.get_rect()
self.rect.bottom = y
self.rect.centerx = x
self.speedy = 2
def update(self):
self.rect.y += self.speedy
if self.rect.bottom > screenHeight:
self.kill()
class Wall(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("wall.png").convert()
self.rect = self.image.get_rect()
self.rect.center = 100, 300
allSprites = pygame.sprite.Group()
player = Player()
enemy = pygame.sprite.Group()
bulletsPlayer = pygame.sprite.Group()
bulletsEnemy = pygame.sprite.Group()
wall = Wall()
allSprites.add(player, enemy, bulletsPlayer, bulletsEnemy, wall)
for i in range(1):
e = Enemy()
allSprites.add(e)
enemy.add(e)
running = True
while True:
for event in pygame.event.get():
if event.type == QUIT or (event.type == KEYUP and event.key == K_ESCAPE):
running = False
app_quit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
player.shootPlayer()
if event.key == pygame.K_TAB:
random.choice(enemy.sprites()).shootEnemy()
allSprites.update()
hitplayer = pygame.sprite.spritecollide(player, bulletsEnemy, True)
if hitplayer:
running = app_quit()
hitenemy = pygame.sprite.spritecollide(enemy, bulletsPlayer, True)
if hitenemy:
running = app_quit()
screen.fill(black)
allSprites.draw(screen)
pygame.display.flip()
pygame.quit()
Since enemy is not a Sprite, but a Group, using spritecollide is wrong.
You're looking for groupcollide, so change the line to
hitenemy = pygame.sprite.groupcollide(enemy, bulletsPlayer, True, True)
I'm working on a space shooter and I've made the sprites and added some basic collision detection, but when I added in collision detection for whether or not an alien sprite collides with the player sprite, it gave me this error message:
Traceback (most recent call last):
File "main.py", line 93, in <module>
game.new()
File "main.py", line 33, in new
self.run()
File "main.py", line 45, in run
self.collision()
File "main.py", line 58, in collision
hits = pygame.sprite.spritecollide(self.player, self.alien, False)
File "C:\Users\sidna\AppData\Local\Programs\Python\Python36-32\lib\site-packages\pygame\sprite.py", line 1525, in spritecollide
return [s for s in group if spritecollide(s.rect)]
TypeError: 'Alien' object is not iterable
Here's my code:
main.py
# IMPORTS
import pygame, random
from sprites import *
from config import *
# GAME
class Game():
def __init__(self):
# INIT PYGAME
pygame.init()
pygame.mixer.init()
pygame.display.set_caption(TITLE)
self.screen = pygame.display.set_mode((WIDTH, HEIGHT))
self.clock = pygame.time.Clock()
self.running = True
# NEW GAME
def new(self):
self.allSprites = pygame.sprite.Group()
self.allAliens = pygame.sprite.Group()
self.player = Player()
for i in range(ALIEN_AMOUNT):
self.alien = Alien()
self.allSprites.add(self.alien)
self.allAliens.add(self.alien)
self.allSprites.add(self.player)
self.run()
# RUN GAME
def run(self):
self.playing = True
while self.playing:
self.clock.tick(FPS)
self.events()
self.update()
self.draw()
self.collision()
# DRAW
def draw(self):
self.screen.fill(BLACK)
self.allSprites.draw(self.screen)
self.allAliens.draw(self.screen)
pygame.display.update()
# DETECT COLLISION
def collision(self):
# alien collision with player
hits = pygame.sprite.spritecollide(self.player, self.alien, False)
if hits:
running = False
# CHECK FOR EVENTS
def events(self):
for event in pygame.event.get():
if event.type == pygame.QUIT:
if self.playing:
self.playing = False
self.running = False
# UPDATE GAME
def update(self):
self.allSprites.update()
self.allAliens.update()
# GAME OVER
def gameOver(self):
pass
# START SCREEN
def startScreen(self):
pass
# END SCREEN
def endScreen(self):
pass
game = Game()
game.startScreen()
while game.running:
game.new()
game.gameOver()
pygame.quit()
quit()
sprites.py
import pygame, random
from config import *
class Player(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("assets/img/player.png").convert()
self.image.set_colorkey(BLACK)
self.rect = self.image.get_rect()
self.rect.centerx = WIDTH / 2
self.rect.bottom = HEIGHT - 10
self.velX = 0
def animate(self):
self.rect.x += self.velX
def collision(self):
# collision with walls
if self.rect.right > WIDTH:
self.rect.right = WIDTH
if self.rect.left < 0:
self.rect.left = 0
def control(self):
self.velX = 0
keystate = pygame.key.get_pressed()
if keystate[pygame.K_LEFT]:
self.velX = -5
if keystate[pygame.K_RIGHT]:
self.velX = 5
def update(self):
self.animate()
self.collision()
self.control()
class Alien(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("assets/img/alien.png").convert()
self.image.set_colorkey(BLACK)
self.rect = self.image.get_rect()
self.rect.x = random.randrange(0, WIDTH - self.rect.width)
self.rect.y = random.randrange(-100, -40)
self.velY = random.randrange(1, 4)
self.velX = random.randrange(-4, 4)
def animate(self):
self.rect.y += self.velY
self.rect.x += self.velX
def collision(self):
# collision with walls
if self.rect.top > HEIGHT + 10 or self.rect.left < -20 or self.rect.right > WIDTH + 20:
self.rect.x = random.randrange(0, WIDTH - self.rect.width)
self.rect.y = random.randrange(-100, -40)
self.velY = random.randrange(1, 4)
self.velX = random.randrange(-4, 4)
def update(self):
self.animate()
self.collision()
config.py
# IMPORTS
import pygame
# ENTIRE GAME VARIABLES
TITLE = "Alien Invasion"
WIDTH = 360
HEIGHT = 570
FPS = 60
# ALIEN CONFIG
ALIEN_AMOUNT = 10
# COLORS
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
The problem is here:
hits = pygame.sprite.spritecollide(self.player, self.alien, False)
The spritecollide() function works like this (from the docs):
spritecollide(sprite, group, dokill, collided = None) -> Sprite_list
You put 'self.alien' as the second parameter, but spritecollide expects a group there. If you just want to collide two different sprites, you want to use collide_rect:
hits = pygame.sprite.collide_rect(self.player, self.alien)
You'll get back True/False whether the two sprites are colliding.
See here for details on all the various collision methods:
http://www.pygame.org/docs/ref/sprite.html