Pygame — Проблемы с созданием снарядов, «аргумент add() после * должен быть повторяющимся, а не int»

#python #pygame

Вопрос:

Я создаю игру типа «Астероиды» с использованием Pygame, и у меня возникают проблемы с стрельбой снарядами. У меня есть группа спрайтов для объекта снаряда и некоторый код для добавления снаряда.

 if pressed[pygame.K_SPACE]:
     projectiles.add(Projectile(player.rect.x, player.rect.y, player.direction))
 

Проблема в том, что когда я нажимаю пробел в игре, чтобы запустить снаряд, я получаю ошибку «аргумент add() после * должен быть повторяющимся, а не int».

У меня есть очень похожее заявление для добавления астероидов, когда игра начинается без каких-либо проблем, поэтому я не совсем уверен, в чем проблема. Я оставлю остальную часть кода ниже. Вопросы, связанные с инструкцией add, находятся в основной функции внизу. Любая помощь будет признательна.

 #Import Modules
import pygame
import math
import random

#Movement Function
def calculate_new_xy(old_xy,speed,direction):
    new_x = old_xy[0]   (speed*math.cos(direction))
    new_y = old_xy[1]   (speed*math.sin(direction))
    return new_x, new_y

#Collision Function
def isColliding(x, y, xTo, yTo, size):
    if x > xTo - size and x < xTo   size and y > yTo - size and y < yTo   size:
        return True
    return False

#Draw Text Function
def drawText(msg, color, x, y, s, center=True):
    screen_text = pygame.font.SysFont("Impact", s).render(msg, True, color)
    if center:
        rect = screen_text.get_rect()
        rect.center = (x, y-50)
    else:
        rect = (x, y)
    display.blit(screen_text, rect)

#Initialize Variables

#Colors
white = (255, 255, 255)
black = (0, 0, 0)

#Display Height/Width
display_width = 800
display_height = 600

#Asteroid Class
class Asteroid(pygame.sprite.Sprite):
    #Initialize values
    def __init__(self, pos=(0, 0)):
        #Initialize sprite class
        pygame.sprite.Sprite.__init__(self)
        #Asteroid sprite
        self.asteroid = pygame.image.load("asteroid.png").convert()
        self.image = self.asteroid
        #Rectangle
        self.rect = self.image.get_rect()
        self.rect.center = pos
        #Initialize random starting angle
        self.angle = random.randint(0, 360)
        #Asteroid random Speed
        self.speed = random.randint(2, 3)
        #Asteroid random direction
        self.direction = math.radians(random.randrange(0, 360, 3))

    #Update asteroid object
    def update(self):
        #Constantly rotate asteroid
        self.angle -= 3 % 360

        #Get image angle and position
        self.image = pygame.transform.rotate(self.asteroid, self.angle*-1)

        #Use rectangle to get center of image
        #Save ship's current center.
        x, y = self.rect.center
        #Replace old rect with new rect.
        self.rect = self.image.get_rect()
        #Put the new rect's center at old center.
        self.rect.center = (x, y)

        #Move Asteroid
        self.rect.center = calculate_new_xy(self.rect.center,self.speed,self.direction)

        #Screen Border
        #Moves the asteroid to the opposite side of the screen if they go outside the border
        if self.rect.x > display_width:
            self.rect.x = -20
        elif self.rect.x < -20:
            self.rect.x = display_width
        elif self.rect.y > display_height:
            self.rect.y = -20
        elif self.rect.y < -20:
            self.rect.y = display_height

#Projectile Class
class Projectile(pygame.sprite.Sprite):
    #Initialize values
    def _init_(self,x,y,direction):
        self.x = x
        self.y = y
        self.dir = direction
        self.ttl = 30

    #Update projectile object
    def update(self):
        #Changing direction
        self.x  = projectilespd * math.cos(self.direction)
        self.y  = projectilespd * math.sin(self.direction)

        #Draw projectile
        pygame.draw.circle(display, white, (self.x,self.y),1)

        #Screen Border
        if self.x > display_width:
            self.x = 0
        elif self.x < 0:
            self.x = display_width
        elif self.y > display_height:
            self.y = 0
        elif self.y < 0:
            self.y = display_height
        self.ttl -= 1        

#Player Class
class Player(pygame.sprite.Sprite):
    #Initialize ship sprite, angle lines, and rectangle
    def __init__(self, pos=(0, 0), size=(200, 200)):
        #Player sprite
        self.ship = pygame.image.load("ship.png").convert()
        self.image = self.ship
        #Rectangle
        self.rect = self.image.get_rect()
        self.rect.center = pos
        #Initialize angle
        self.angle = 0
        #Initialize direction
        self.direction = 0

    #Update player object
    def update(self):
        #Rotation
        pressed = pygame.key.get_pressed()
        if pressed[pygame.K_LEFT]: self.angle -= 3 % 360
        if pressed[pygame.K_RIGHT]: self.angle  = 3 % 360

        #Get image angle and position
        self.image = pygame.transform.rotate(self.ship, self.angle*-1)

        #Use rectangle to get center of image
        #Save ship's current center.
        x, y = self.rect.center
        #Replace old rect with new rect.
        self.rect = self.image.get_rect()
        #Put the new rect's center at old center.
        self.rect.center = (x, y)

        #Convert angle to radians
        self.direction = math.radians(self.angle-90)

        #Increase speed if Up is pressed
        if pressed[pygame.K_UP]: self.speed = 5
        else: self.speed = 0

        #Move Ship
        self.rect.center = calculate_new_xy(self.rect.center,self.speed,self.direction)

        #Screen Border
        #Moves the player to the opposite side of the screen if they go outside the border
        if self.rect.x > display_width:
            self.rect.x = -50
        elif self.rect.x < -50:
            self.rect.x = display_width
        elif self.rect.y > display_height:
            self.rect.y = -50
        elif self.rect.y < -50:
            self.rect.y = display_height

#Main Function
def main(gameState):
    #Player starting position
    player = Player(pos=(400, 300))
    #Asteroid group
    asteroids = pygame.sprite.Group()
    #Projectile group
    projectiles = pygame.sprite.Group()

    #Create asteroids
    for x in range(8):
        asteroids.add(Asteroid(pos=(100   (x*120), 100   (x*20))))

    while True:
        for event in pygame.event.get():
            #closes game
            if event.type == pygame.QUIT:
                done = True
                pygame.quit()
                exit()
        #Game Menu
        while gameState == "Menu":
            #Fill background
            display.fill((0,0,0))
            #Display menu text
            drawText("ASTEROIDS", white, display_width / 2, display_height / 2, 150)
            drawText("Press any key to START", white, display_width / 2, display_height / 2   120, 40)
            #Check game start or end
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    done = True
                    pygame.quit()
                    exit()
                if event.type == pygame.KEYDOWN:
                    gameState = "Playing"
            pygame.display.update()
            #Low frame rate for menu
            clock.tick(5)

        #Get key inputs
        pressed = pygame.key.get_pressed()

        #Fill background
        display.fill(black)

        #Check for player collision with asteroid
        for asteroid in asteroids:
            if gameState != "Game Over":
                if isColliding(player.rect.x, player.rect.y, asteroid.rect.x, asteroid.rect.y, 30):
                    gameState = "Game Over"

        #Update and draw player if not game over
        if gameState != "Game Over":
            #Update player
            player.update()
            #Draw player
            display.blit(player.image, player.rect)

        #Update asteroids
        asteroids.update()

        #Draw asteroids
        asteroids.draw(display)

        #Fire Projectiles
        if pressed[pygame.K_SPACE]:
            projectiles.add(Projectile(player.rect.x, player.rect.y, player.direction))

        #Update projectiles
        projectiles.update()

        #Draw projectiles
        projectiles.draw(display)

        #Display Game Over and restart option
        if gameState == "Game Over":
            drawText("GAME OVER", white, display_width / 2, display_height / 2, 150)
            drawText("Press R to restart", white, display_width / 2, display_height / 2   120, 40)
            if pressed[pygame.K_r]: 
                main(gameState = "Playing")

        #Makes updates to the game screen
        pygame.display.update()

        #Frame rate
        clock.tick(60)

#Initialize Game
if __name__ == '__main__':
    #initialize pygame
    pygame.init()

    #initialize display settings
    display = pygame.display.set_mode((display_width,display_height))
    pygame.display.set_caption('Asteroids')

    #initialize game clock
    clock = pygame.time.Clock()

    #start main function
    main(gameState = "Menu")
 

Ответ №1:

Проблема не в pygame.sprite.Group.add операции, а в том, что obejct, который вы хотите добавить, не является pygame.sprite.Sprite объектом, потому что объект вообще не построен.
Вы пропустили super вызов в конструкторе Projectile . Кроме того, имя конструктора должно быть __init__ скорее _init_ :

 class Projectile(pygame.sprite.Sprite):
    #Initialize values
    def __init__(self,x,y,direction):
        super.__init__()
        self.x = x
        self.y = y
        self.dir = direction
        self.ttl = 30