Spawning enemy sprites - python

For my computing project I need to make some sort of app or game. I decided I would make space invaders. I have managed to get the basics working, the player sprite would spawn I could move it and the background and music worked properly, but now when I have tried to create enemy sprites I keep getting this error:
C:\Python27\python.exe "C:/Users/Harry/Desktop/Computing Project/Galaxian.py"
Traceback (most recent call last):
File "C:/Users/Harry/Desktop/Computing Project/Galaxian.py", line 87, in <module>
mobs.add(Mob)
TypeError: unbound method add() must be called with Mob instance as first argument (got type instance instead)
Process finished with exit code 1
If anyone could help I would really appreciate it! Here is my code:
import pygame
import random
# --- constants --- (UPPER_CASE names)
WHITE = (255, 255, 255)
BLACK = ( 0, 0, 0)
RED = (255, 0, 0)
GREEN = ( 0, 255, 0)
BLUE = ( 0, 0, 255)
ORANGE = (255, 255, 0)
YELLOW = ( 0, 255, 255)
DISPLAY_WIDTH = 720
DISPLAY_HEIGHT = 720
FPS = 60
# --- classes --- (CamelCase names)
class Player(pygame.sprite.Sprite):
# <-- empty line for readabelity
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("images\\user1.gif").convert()
self.image = pygame.transform.scale(self.image, (50, 50))
self.rect = self.image.get_rect()
self.speed_x = 0
def update(self):
self.speed_x = 0
keystate = pygame.key.get_pressed()
if keystate[pygame.K_LEFT]:
self.speed_x = -7
if keystate[pygame.K_RIGHT]:
self.speed_x = 7
self.rect.x += self.speed_x
if self.rect.right > DISPLAY_WIDTH:
self.rect.right = DISPLAY_WIDTH
if self.rect.left < 0:
self.rect.left = 0
class Mob(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((30, 40))
self.image.fill(RED)
self.rect = self.image.get_rect()
self.rect.x = random.randrange(0, DISPLAY_WIDTH - self.rect.width)
self.rect.y = random.randrange(-100, -40)
self.speedy = random.randrange(1, 8)
def update(self):
self.rect.y +=self.speedy
if self.rect.top > DISPLAY_HEIGHT + 10:
self.rect.x = random.randrange(0, DISPLAY_WIDTH - self.rect.width)
self.rect.y = random.randrange(-100, -40)
self.speedy = random.randrange(1, 8)
# --- functions --- (lower_case names)
# empty
# --- main --- (lower_case names)
# - init -
pygame.init()
pygame.mixer.init()
display = pygame.display.set_mode((DISPLAY_WIDTH, DISPLAY_HEIGHT))
display_rect = display.get_rect()
# - objects -
all_sprites = pygame.sprite.Group()
mobs = pygame.sprite.Group()
player = Player()
player.rect.center = ((DISPLAY_WIDTH / 2), 650)
all_sprites.add(player)
for z in range(8):
mobs = Mob()
all_sprites.add(mobs)
mobs.add(Mob)
background = pygame.image.load("C:\\Users\\Harry\\Desktop\\Computing Project\\images\\background.jpg")
background = pygame.transform.scale(background, (DISPLAY_WIDTH, DISPLAY_HEIGHT))
# - other -
pygame.mixer.music.load("C:\\Users\\Harry\\Desktop\\Computing Project\\Audio\\music\\soundtrack.mp3")
pygame.mixer.music.play(-1)
pygame.mixer.music.set_volume(0.4)
# - mainloop -
crashed = False
clock = pygame.time.Clock()
while not crashed:
# - events -
for event in pygame.event.get():
if event.type == pygame.QUIT:
crashed = True
print(event)
# - updates (without draws) -
all_sprites.update()
# - draws (without updates) -
display.blit(background, (0, 0))
all_sprites.draw(display)
pygame.display.update()
# - FPS -
clock.tick(FPS)
# - end -
pygame.quit()

TypeError: unbound method add() must be called with Mob instance as first argument (got type instance instead)
The problem is that you've called the add method and passed in the name of the class Mob but not an instance of Mob.
all_sprites.add(player)
for z in range(8):
mobs = Mob()
all_sprites.add(mobs)
mobs.add(Mob) # This is the class name
Depending on the interface of add() you'll probably want to do:
mob = Mob()
mobs.add(mob)
But it's a bit unclear here what you're trying to accomplish

Related

add() argument after * must be an iterable, not int [duplicate]

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

Get a specific sprite from a group in Pygame

I am trying to find a certain sprite in a collision group. In this case, My code checks every platform to see if the player is touching it. If the player is touching the platform, I want the player's bottom y to become the platform's (that the player is touching) top y. I do not know how to grab a certain platform, and edit the attributes of that one. How would I edit my code to make this work?
import pygame
import random
WIDTH = 500
HEIGHT = 400
FPS = 30
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
playerImage = "blockBandit/BlockBandit.png"
class Player(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((50, 50))
self.image = pygame.image.load(playerImage).convert()
self.rect = self.image.get_rect()
self.rect.center = (WIDTH / 2, HEIGHT / 2)
self.vx = 0
self.vy = 0
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(GREEN)
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
pygame.init()
pygame.mixer.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Block Bandit")
clock = pygame.time.Clock()
allPlatforms = pygame.sprite.Group()
all_sprites = pygame.sprite.Group()
player = Player()
p1 = Platform(0, HEIGHT - 40, WIDTH, 40)
all_sprites.add(p1)
allPlatforms.add(p1)
all_sprites.add(player)
def moveCharacter(object):
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
object.vx += -2
if keys[pygame.K_RIGHT]:
object.vx += 2
if keys[pygame.K_UP]:
object.vy -= 12
pygame.quit()
object.vx = object.vx * 0.9
if abs(object.vx) < 1:
object.vx = 0
if abs(object.vx) > 10:
if object.vx < 0:
object.vx = -10
else:
object.vx = 10
object.vy = object.vy + 1
object.rect.x += object.vx
object.rect.y += object.vy
hits = pygame.sprite.spritecollide(object, allPlatforms, False)
if hits:
# object.rect.y = hits[0].rect.midbottom
object.rect.y -= 1
object.vy = 0
if object.rect.bottom < allPlatforms.top:
object.rect.y = allPlatforms.top
print(object.rect.midbottom)
running = True
while running:
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
moveCharacter(player)
# Update State
all_sprites.update()
# Render
screen.fill(BLACK)
all_sprites.draw(screen)
# screen.blit(player.icon, (20, 40))
pygame.display.flip()
pygame.quit()
hits is a list of the colliding platform sprites, so you can iterate over it with a for loop and set the object.rect.bottom to the platform.rect.top.
hits = pygame.sprite.spritecollide(object, allPlatforms, False)
for platform in hits:
object.vy = 0
object.rect.bottom = platform.rect.top

Appending a csv file in python

So I am making a space invaders game in python, the game will take the score the player has achieved and will add it to a csv file. My code for the csv file is:
col = pygame.sprite.spritecollideany(player, mobs)
if col:
with open("rec_Scores.csv", "a", newline" ") as f:
w = csv.writer(f, dilimiter = ",")
for i in range(len(score)):
w.writerow(name[i], score[i]])
crashed = True
However, I get the error:
File "C:\Users\Harry\Desktop\Desktop\Computing Project\Galaxian.py", line 162
with open("rec_Scores.csv", "a", newline" ") as f:
^
SyntaxError: invalid syntax
I am really stuck with this problem and I have no idea how to solve it. Any help would be much appreciated. Here is my code because I am probably going about this in a completely idiotic way:
import pygame
import random
import sys
import csv
# --- constants --- (UPPER_CASE names)
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
ORANGE = (255, 255, 0)
YELLOW = (0, 255, 255)
DISPLAY_WIDTH = 720
DISPLAY_HEIGHT = 720 # sets res for the screen
FPS = 60
# --- classes --- (CamelCase names)
class Player(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("images\\user1.gif").convert()
self.image = pygame.transform.scale(self.image, (50, 50))
self.rect = self.image.get_rect()
self.speed_x = 0
def update(self):
self.speed_x = 0
keystate = pygame.key.get_pressed()
if keystate[pygame.K_LEFT]:
self.speed_x = -10
if keystate[pygame.K_RIGHT]:
self.speed_x = 10
self.rect.x += self.speed_x
if self.rect.right > DISPLAY_WIDTH:
self.rect.right = DISPLAY_WIDTH
if self.rect.left < 0:
self.rect.left = 0
def shoot(self):
bullet = Bullet(self.rect.centerx, self.rect.top)
all_sprites.add(bullet)
bullet_group.add(bullet)
class Mob(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.speed_y = random.randrange(5, 11)
self.image = pygame.image.load("images\\enemy1.gif").convert()
self.image = pygame.transform.scale(self.image, (50, 50))
self.rect = self.image.get_rect()
self.speed_x = 0
self.rect.x = random.randrange(0, DISPLAY_WIDTH - self.rect.width)
self.rect.y = random.randrange(-500, -40)
self.speedy = random.randrange(5, 11)
def update(self):
self.rect.y += self.speedy
if self.rect.top > DISPLAY_HEIGHT + 10:
self.rect.x = random.randrange(0, DISPLAY_WIDTH - self.rect.width)
self.rect.y = random.randrange(-500, -40)
class Bullet(pygame.sprite.Sprite):
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("images\\laser1.gif").convert() # sets the laser to be the image laser1.gif
self.image = pygame.transform.scale(self.image, (15, 25)) # trasforms the size to fit the screen
self.rect = self.image.get_rect() # sets hit box up, will fit around the image
self.rect.bottom = y
self.rect.centerx = x
self.speed_y = -30
def update(self):
self.rect.y += self.speed_y
if self.rect.bottom < 0:
self.kill()
# --- functions --- (lower_case names)
# --- main --- (lower_case names)
score =0
name = raw_input("Enter your name: ")
# - init -
pygame.init()
pygame.mixer.init()
display = pygame.display.set_mode((DISPLAY_WIDTH, DISPLAY_HEIGHT))
display_rect = display.get_rect()
# - objects and groups -
all_sprites = pygame.sprite.Group() # creates class that all sprites will be in
mobs = pygame.sprite.Group() # creates class that all mobs will be stored in
bullet_group = pygame.sprite.Group() # creates class that all bullets will be stored in
player = Player() # assigns the player variable to the player class
player.rect.center = ((DISPLAY_WIDTH / 2), DISPLAY_HEIGHT / 1.2) # sets the player to spawn at the bottom and in the middle of the screen
all_sprites.add(player) # adds player to the all_sprites group
for z in range(12): # spawns 13 enemies
mob = Mob()
mobs.add(mob)
all_sprites.add(mob)
# - other -
pygame.mixer.music.load("audio\\soundtrack.mp3")
pygame.mixer.music.play(-1) # sets music to play in an infinite loop
pygame.mixer.music.set_volume(0.2)
# - mainloop -
crashed = False
clock = pygame.time.Clock()
while not crashed:
# - events -
for event in pygame.event.get():
if event.type == pygame.QUIT:
crashed = True
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_LCTRL:
player.shoot()
print(event)
# - updates (without draws) -
all_sprites.update() # updates sprite positions without drawing them onto the screen
# - draws (without updates) -
background = pygame.image.load("images\\background.jpg") # assigns the picture to a variable called background
background = pygame.transform.scale(background, (DISPLAY_WIDTH, DISPLAY_HEIGHT)) # streches the picture to fit the screen
display.blit(background, (0, 0)) # displays the background image
all_sprites.draw(display) # draws all sprites onto the screen
font = pygame.font.SysFont("monospace", 15)
text = font.render("Score: " + str(score), True, BLACK)
display.blit(text, (0, 0))
pygame.display.update() # updates display
# - Checks for a hit -
col = pygame.sprite.groupcollide(mobs, bullet_group, True, True)
if col: # if col = true then
mob = Mob() # spawns new mob
mobs.add(mob)
all_sprites.add(mob)
score += 10
# - checks for a collision -
col = pygame.sprite.spritecollideany(player, mobs)
if col:
with open("rec_Scores.csv", "a", newline" ") as f:
w = csv.writer(f, dilimiter = ",")
for i in range(len(score)):
w.writerow(name[i], score[i]])
crashed = True
# - FPS -
clock.tick(FPS) # built in function to make the program stay below specified frame per second
# - end -
pygame.quit()
Thank you in advance for any help.
with open("rec_Scores.csv", "a", newline" ") as f:
Should be:
with open("rec_Scores.csv", "a") as f:
delimiter is misspelled as dilimiter but is unneeded anyway.
The f.writerow arguments are not quite what you want here.
Next time try making a working reproducer that has all bits of code needed to work including import statements.
Actual working version:
import csv
name=['foo','bar']
score=[12345,54321]
with open("rec_Scores.csv", "a") as f:
w = csv.writer(f)
for i in range(len(score)):
w.writerow([str(name[i]),str(score[i])])

TypeError: 'Alien' object is not iterable

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

TypeError: unbound method sprites()

For my advanced higher computing course I need to do a project, mines is making space invaders, I have never used python before and I am pretty happy with my progress so far, however I have recently encountered an error that I dont know how to deal with. The code is below.
import pygame
import random
import sys
# --- constants --- (UPPER_CASE names)
WHITE = (255, 255, 255)
BLACK = ( 0, 0, 0)
RED = (255, 0, 0)
GREEN = ( 0, 255, 0)
BLUE = ( 0, 0, 255)
ORANGE = (255, 255, 0)
YELLOW = ( 0, 255, 255)
DISPLAY_WIDTH = 720
DISPLAY_HEIGHT = 720
FPS = 60
# --- classes --- (CamelCase names)
class Player(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("images\\user1.gif").convert()
self.image = pygame.transform.scale(self.image, (50, 50))
self.rect = self.image.get_rect()
self.speed_x = 0
def update(self):
self.speed_x = 0
keystate = pygame.key.get_pressed()
if keystate[pygame.K_LEFT]:
self.speed_x = -7
if keystate[pygame.K_RIGHT]:
self.speed_x = 7
self.rect.x += self.speed_x
if self.rect.right > DISPLAY_WIDTH:
self.rect.right = DISPLAY_WIDTH
if self.rect.left < 0:
self.rect.left = 0
def shoot(self):
bullet = Bullet(self.rect.centerx, self.rect.top)
all_sprites.add(bullet)
class Mob(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("images\\enemy1.gif").convert()
self.image = pygame.transform.scale(self.image, (50, 50))
self.rect = self.image.get_rect()
self.speed_x = 0
self.rect.x = random.randrange(0, DISPLAY_WIDTH - self.rect.width)
self.rect.y = random.randrange(-500, -40)
self.speedy = random.randrange(5, 11)
def update(self):
self.rect.y +=self.speedy
if self.rect.top > DISPLAY_HEIGHT + 10:
self.rect.x = random.randrange(0, DISPLAY_WIDTH - self.rect.width)
self.rect.y = random.randrange(-100, -40)
self.speed_y = random.randrange(5, 11)
class Bullet(pygame.sprite.Sprite):
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("images\\laser1.gif").convert()
self.image = pygame.transform.scale(self.image, (15, 25))
self.rect = self.image.get_rect()
self.rect.bottom = y
self.rect.centerx = x
self.speed_y = -20
def update(self):
self.rect.y += self.speed_y
if self.rect.bottom < 0:
self.kill()
# --- functions --- (lower_case names)
# empty
# --- main --- (lower_case names)
# - init -
pygame.init()
pygame.mixer.init()
display = pygame.display.set_mode((DISPLAY_WIDTH, DISPLAY_HEIGHT))
display_rect = display.get_rect()
# - objects and groups -
all_sprites = pygame.sprite.Group()
mobs = pygame.sprite.Group()
bullet_group = pygame.sprite.Group
player = Player()
player.rect.center = ((DISPLAY_WIDTH / 2), DISPLAY_HEIGHT/1.2)
all_sprites.add(player)
for z in range(8):
mob = Mob()
mobs.add(mob)
all_sprites.add(mob)
background = pygame.image.load("images\\background.jpg")
background = pygame.transform.scale(background, (DISPLAY_WIDTH, DISPLAY_HEIGHT))
# - other -
pygame.mixer.music.load("audio\\soundtrack.mp3")
pygame.mixer.music.play(-1)
pygame.mixer.music.set_volume(0.4)
# - mainloop -
crashed = False
clock = pygame.time.Clock()
while not crashed:
# - checks for a hit -
col = pygame.sprite.spritecollideany(player, mobs)
if col:
sys.exit()
col = pygame.sprite.groupcollide(mobs, bullet_group, True, True)
# - events -
for event in pygame.event.get():
if event.type == pygame.QUIT:
crashed = True
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
player.shoot()
print(event)
# - updates (without draws) -
all_sprites.update()
# - draws (without updates) -
display.blit(background, (0, 0))
all_sprites.draw(display)
pygame.display.update()
# - FPS -
clock.tick(FPS)
# - end -
pygame.quit()
This is the error message I am receiving, any help would be great, thanks.
C:\Python27\python.exe "C:/Users/Iain/Desktop/Computing Project/Galaxian.py"
Traceback (most recent call last):
File "C:/Users/Iain/Desktop/Computing Project/Galaxian.py", line 132, in <module>
col = pygame.sprite.groupcollide(mobs, bullet_group, True, True)
File "C:\Python27\lib\site-packages\pygame\sprite.py", line 1382, in groupcollide
c = SC(s, groupb, dokillb, collided)
File "C:\Python27\lib\site-packages\pygame\sprite.py", line 1339, in spritecollide
for s in group.sprites():
TypeError: unbound method sprites() must be called with Group instance as first argument (got nothing instead)
Process finished with exit code 1
An "unbound method" is a method object that is obtained from a class. When called, it needs an instance of the class passed to it.
A "bound method" is a method that is bound to an instance of a class. It can be called "normally" since it already has the instance.
In your case, you have a simple typo. You have an unbound method, but it should have been a bound method. The message is misleading because the real problem is the argument you passed to pygame is incorrect.
On line 132 of your program, you call groupcollide. One of the arguments you provide is a variable named bullet_group.
The root cause of the problem is this line:
bullet_group = pygame.sprite.Group
You missed the parentheses, so as a result the name bullet_group refers to the class pygame.sprite.Group. You simply need to add the parentheses to call the class to create an instance of it.
bullet_group = pygame.sprite.Group()
You did this correctly on the preceding lines for mobs and all_sprites.

Categories

Resources