You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Pygame开发2D游戏时子弹位置与玩家同步跟随问题求解

问题根因
  • 坐标引用绑定:你调用self.bullets[-1].shoot(self.coordinates)时,直接将枪的coordinates列表传给子弹,Python中列表是可变对象,直接赋值属于引用传递,后续枪的坐标变动会同步到子弹的坐标上,导致子弹永远和枪位置一致。
  • 子弹未在主渲染流程绘制:当前主循环只绘制了玩家和枪,没有遍历绘制子弹列表里的子弹,就算坐标正确也不会显示。
  • 多线程操作违反Pygame规范:Pygame的所有绘制操作必须在主线程执行,你在子线程中调用的self.draw()会被主线程每轮的背景填充直接覆盖,同时多线程修改坐标还可能出现数据同步异常。
  • 语法疏漏:主循环末尾的fpsClock.tick(FPS缺少右括号,同时未导入完整pygame模块,会导致运行报错。
修复方案
  1. 子弹初始化坐标时做值拷贝,避免引用绑定
  2. 移除子弹的多线程移动逻辑,将子弹的位置更新和绘制统一放到主线程的主循环中处理
  3. 新增子弹的生命周期管理,飞行超出屏幕后自动移除避免内存占用
  4. 补全语法和导入错误

完整可运行修改后代码

from pygame.locals import *
import pygame
import time


class GameObject:
    """Base object class"""
    def __init__(self):
        """Init all base values"""
        self.hp = 100
        self.coordinates = [0, 0]
        self.speed = 3

    def move_x(self, where):
        """Moving player by x axis"""
        self.coordinates[0] += where * self.speed

    def move_y(self, where):
        """Moving player by y axis"""
        self.coordinates[1] += where * self.speed


class Gun(GameObject):
    def __init__(self):
        super().__init__()
        self.coordinates = [25, 25]
        self.bullets = []
        self.direction = [1, 1]

    def update_bullets(self):
        # 每帧更新所有子弹位置,移除超出屏幕的子弹
        for bullet in self.bullets[:]:
            bullet.move_x(bullet.direction[0] * bullet.speed)
            bullet.move_y(bullet.direction[1] * bullet.speed)
            # 超出屏幕则移除
            if bullet.coordinates[0] > 1080 or bullet.coordinates[0] < 0 or bullet.coordinates[1] >720 or bullet.coordinates[1]<0:
                self.bullets.remove(bullet)

    def draw(self):
        pygame.draw.rect(WINDOW, (28, 28, 28),
                         pygame.Rect(self.coordinates[0], self.coordinates[1], 40, 10))
        # 绘制所有子弹
        for bullet in self.bullets:
            bullet.draw()

    def shoot(self):
        self.bullets.append(Bullet())
        self.bullets[-1].shoot(self.coordinates)


class Bullet(GameObject):
    def __init__(self):
        super().__init__()
        self.direction = [1, 0]

    def draw(self):
        pygame.draw.rect(WINDOW, (255, 0, 43),
                         pygame.Rect(self.coordinates[0], self.coordinates[1], 40, 10))

    def shoot(self, start_pos):
        print("shooting!!!")
        # 做值拷贝,避免引用原枪的坐标列表
        self.coordinates = start_pos.copy()


class Player(GameObject):
    def __init__(self):
        """Initiating all base values"""
        super().__init__()
        self.direction = "UP"
        self.gun = Gun()

    def check_move(self):
        if pygame.key.get_mods() == 1:
            self.speed = 5
        else:
            self.speed = 3
        if pygame.key.get_pressed()[K_e]:
            self.gun.shoot()
        if pygame.key.get_pressed()[K_a]:
            self.move_x(-1)
            self.gun.move_x(-1)
        if pygame.key.get_pressed()[K_d]:
            self.move_x(1)
            self.gun.move_x(1)
        if pygame.key.get_pressed()[K_w]:
            self.move_y(-1)
            self.gun.move_y(-1)
        if pygame.key.get_pressed()[K_s]:
            self.move_y(1)
            self.gun.move_y(1)

    def draw(self):
        pygame.draw.rect(WINDOW, (255, 0, 0),
                         pygame.Rect(self.coordinates[0], self.coordinates[1], 50, 50))
        self.gun.draw()


pygame.init()

# Colours
BACKGROUND = (255, 255, 255)

# Game Setup
FPS = 60
fpsClock = pygame.time.Clock()
WINDOW_WIDTH = 1080
WINDOW_HEIGHT = 720

WINDOW = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))
pygame.display.set_caption('super_shooter228')


# The main function that controls the game
def main():
    """Main function that does all the render"""
    looping = True
    # Get input

    player = Player()  # Init of the player structure
    while looping:
        pygame.event.get()
        player.check_move()  # Moving the player
        # 更新子弹位置
        player.gun.update_bullets()
        WINDOW.fill(BACKGROUND)  # This fills the backgroud with whatever you want, do all rendering after this!!
        player.draw()

        pygame.display.update()
        fpsClock.tick(FPS)


main()

内容的提问来源于stack exchange,提问作者DEMKS

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.09 13:18:03