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

