为什么我会得到第二张精灵图片,它不会旋转而且不应该出现在那里?

Why am I getting a second image of sprite that won't rotate and shouldn't be there?

我正在尝试创建一个从我的火箭飞船后部出来的 TractorBeam(或推力),当然,精灵将随着火箭飞船一起旋转。它似乎工作正常,但我得到了同一个 TractorBeam 图像的第二张图像,该图像在火箭船旋转和 TractorBeam 图像旋转时保持在相同的垂直位置。我对它的编程与从前面出来的激光相同(除了不同的速度、寿命等),而且激光似乎没有这个未知的第二个图像。

关于我哪里出错或如何消除第二个不需要的图像的任何建议?

import pygame as pg
import os
from random import uniform
vec = pg.math.Vector2

TITLE = "GRAVITAR"
WIDTH = 800
HEIGHT = 600
FPS = 60
GREY = (211, 211, 211)

# Player properties
ROCKET_SHIP = 'Images/Rocket_Ship.png'
PLAYER_ACC = 0.5
PLAYER_FRICTION = -0.00
PLAYER_GRAV = 0.1
PLAYER_ROT_SPEED = 200
LASER = 'Images/Laser_1.png'
LASER_SPEED = 400
LASER_LIFETIME = 1500
LASER_RATE = 150
LASER_COUNT = 1
LASER_SPREAD = 3
LASER_OFFSET = vec(20, -1)
TRACTOR_BEAM = 'Images/TractorBeam_1.png'
TRACTOR_BEAM_SPEED = 400
TRACTOR_BEAM_LIFETIME = 25
TRACTOR_BEAM_RATE = 25
TRACTOR_BEAM_COUNT = 1
TRACTOR_BEAM_SPREAD = 1
TRACTOR_BEAM_OFFSET = vec(-12, 0)

class Player(pg.sprite.Sprite):
    def __init__(self, game, x, y):
        pg.sprite.Sprite.__init__(self)
        self.game = game
        self.image = game.rocket_ship
        self.rect = self.image.get_rect()
        self.rect.center = (x, y)
        self.vel = vec(0, 0)
        self.pos = vec(x, y)
        self.rot = 90
        self.last_shot = 0
        self.thrust = False
        self.frame = 0
        self.last_update = 0

    def get_keys(self):
        self.rot_speed = 0
        self.acc = vec(0, PLAYER_GRAV)
        keys = pg.key.get_pressed()
        if keys[pg.K_LEFT]:
            self.rot_speed = PLAYER_ROT_SPEED
        if keys[pg.K_RIGHT]:
            self.rot_speed = -PLAYER_ROT_SPEED
        if keys[pg.K_UP]:
            self.vel += vec(PLAYER_ACC, 0).rotate(-self.rot)
        if keys[pg.K_SPACE]:
            self.shoot()
        if keys[pg.K_t]:
            self.tractor_beam()
        self.vel += self.acc + self.vel * PLAYER_FRICTION
        max_vel = 1.75
        self.vel[0] = max(-max_vel, min(max_vel, self.vel[0]))
        self.vel[1] = max(-max_vel, min(max_vel, self.vel[1]))
        self.pos += self.vel

    def shoot(self):
        now = pg.time.get_ticks()
        if now - self.last_shot > LASER_RATE:
            self.last_shot = now
            dir = vec(1, 0).rotate(-self.rot)
            pos = self.pos + LASER_OFFSET.rotate(-self.rot)
            for i in range(LASER_COUNT):
                spread = uniform(-LASER_SPREAD, LASER_SPREAD)
                Laser(self.game, pos, dir.rotate(spread), self)

    def tractor_beam(self):
        now = pg.time.get_ticks()
        if now - self.last_shot > TRACTOR_BEAM_RATE:
            self.last_shot = now
            dir = vec(1, 0).rotate(-self.rot + 180)
            pos = self.pos + TRACTOR_BEAM_OFFSET.rotate(-self.rot)
            spread = uniform(-TRACTOR_BEAM_SPREAD, TRACTOR_BEAM_SPREAD)
            TractorBeam(self.game, pos, dir.rotate(spread), self)

    def update(self):
        self.get_keys()
        self.rot = (self.rot + self.rot_speed * self.game.dt) % 360
        self.image = pg.transform.rotate(self.game.rocket_ship, self.rot)
        self.rect = self.image.get_rect()
        self.pos += self.vel * self.game.dt
        self.rect.center = self.pos
        if self.pos.x > WIDTH:
            self.pos.x = 0
        if self.pos.x < 0:
            self.pos.x = WIDTH
        if self.pos.y > HEIGHT:
            self.pos.y = 0
        if self.pos.y < 0:
            self.pos.y = HEIGHT


class Laser(pg.sprite.Sprite):
    def __init__(self, game, pos, dir, player):
        self.groups = game.all_sprites  # , game.bullet
        pg.sprite.Sprite.__init__(self, self.groups)
        self.game = game
        self.player = player
        self.image = game.laser
        self.rect = self.image.get_rect()
        self.pos = vec(pos)
        self.rect.center = pos
        self.vec = dir * LASER_SPEED * uniform(0.9, 1.1)
        self.spawn_time = pg.time.get_ticks()
        self.rot = 90

    def update(self):
        self.image = pg.transform.rotate(self.game.laser, self.player.rot - 90)
        self.rect = self.image.get_rect()
        self.pos += self.vec * self.game.dt
        self.rect.center = self.pos
        if pg.time.get_ticks() - self.spawn_time > LASER_LIFETIME:
            self.kill()


class TractorBeam(pg.sprite.Sprite):
    def __init__(self, game, pos, dir, player):
        self.groups = game.all_sprites
        pg.sprite.Sprite.__init__(self, self.groups)
        self.game = game
        self.player = player
        self.image = game.tractor_beam
        self.rect = self.image.get_rect()
        self.pos = vec(pos)
        self.rect.center = pos
        self.pos = vec(pos)
        self.vec = dir * TRACTOR_BEAM_SPEED * uniform(0.9, 1.1)
        self.spawn_time = pg.time.get_ticks()
        self.rot = 0

    def update(self):
        self.image = pg.transform.rotate(self.game.tractor_beam, self.player.rot - 90)
        self.rect = self.image.get_rect()
        self.pos += self.vec * self.game.dt
        self.rect.center = self.pos
        if pg.time.get_ticks() - self.spawn_time > TRACTOR_BEAM_LIFETIME:
           self.kill()

class Game:
    def __init__(self):
        # Initialize pygame and create window
        pg.init()
        pg.mixer.init()
        pg.key.set_repeat(10, 50)
        os.environ['SDL_VIDEO_WINDOW_POS'] = '568, 101'
        self.screen = pg.display.set_mode((WIDTH, HEIGHT))
        pg.display.set_caption(TITLE)
        self.clock = pg.time.Clock()
        self.running = True
        self.load_data()

    def load_data(self):
        self.rocket_ship = pg.image.load(ROCKET_SHIP).convert_alpha()
        self.rocket_ship = pg.transform.scale(self.rocket_ship, (36, 18))
        self.laser = pg.image.load(LASER).convert_alpha()
        self.laser = pg.transform.scale(self.laser, (3, 8))
        self.tractor_beam = pg.image.load(TRACTOR_BEAM).convert_alpha()
        self.tractor_beam = pg.transform.scale(self.tractor_beam, (30, 30))

    def new(self):
        # Start a new game
        self.all_sprites = pg.sprite.Group()
        self.lasers = pg.sprite.Group()
        self.tractorBeams = pg.sprite.Group()
        self.player = Player(self, WIDTH / 2, HEIGHT / 4)
        self.all_sprites.add(self.player)
        self.run()

    def run(self):
        # Game loop
        self.playing = True
        while self.playing:
            self.dt = self.clock.tick(FPS) / 1000.0
            self.events()
            self.update()
            self.draw()

    def update(self):
        # Game loop update
        self.all_sprites.update()

    def events(self):
        # Game loop events
        for event in pg.event.get():
            if event.type == pg.QUIT:
                if self.playing:
                    self.playing = False
                self.running = False

    def draw(self):
        # Game loop draw
        pg.display.set_caption("{:.2f}".format(self.clock.get_fps()))
        self.screen.fill(GREY)
        self.all_sprites.draw(self.screen)

        # After drawing everything, flip display
        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()

似乎有 2 个牵引光束,但实际上只有一个。但是,TractorBeam 实例的 update 方法在绘制它的第一帧中没有被调用。它是在 playerGroupupdate 循环中构建的。在 update 期间添加到 GroupSprites 不会在这一帧更新,而是在下一帧更新。
您必须手动调用 update 一次:

class Player(pg.sprite.Sprite):
    # [...]

       def tractor_beam(self):
        now = pg.time.get_ticks()
        if now - self.last_shot > TRACTOR_BEAM_RATE:
            self.last_shot = now
            dir = vec(1, 0).rotate(-self.rot + 180)
            pos = self.pos + TRACTOR_BEAM_OFFSET.rotate(-self.rot)
            spread = uniform(-TRACTOR_BEAM_SPREAD, TRACTOR_BEAM_SPREAD)
            
            beam = TractorBeam(self.game, pos, dir.rotate(spread), self)
            beam.update()

激光也有同样的问题,但几乎没有引起注意。