python - Pygame 坐标在不同对象之间同步
问题描述
我正在使用 pygame 制作一个简单的 2d 游戏。我试图让玩家用他的枪射击子弹。然而,出于某种原因,子弹总是跟随玩家并与他同步他们的位置。
from pygame.locals import *
from threading import Thread
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 draw(self):
pygame.draw.rect(WINDOW, (28, 28, 28),
pygame.Rect(self.coordinates[0], self.coordinates[1], 40, 10))
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
shoot_thread = Thread(target=self.shoot_thread)
shoot_thread.start()
def shoot_thread(self):
for i in range(15):
print("MOVING")
self.move_x(self.direction[0] * self.speed)
self.move_y(self.direction[1] * self.speed)
self.draw()
time.sleep(0.1)
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()
# class Bullet(GameObject):
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
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()
我尽力在互联网上找到解决方案,但我失败了。我真的很感激这个问题的任何帮助。谢谢!
解决方案
问题很可能来自shoot
方法共享数据的方式:
# Gun
def shoot(self):
self.bullets.append(Bullet())
self.bullets[-1].shoot(self.coordinates)
# Bullet
def shoot(self, start_pos):
print("shooting!!!")
self.coordinates = start_pos
coordinates
是一个列表,它是一个可变容器——列表可以在您将它传递给另一个函数后随时修改。当你Gun
将它的坐标传递给 时Bullet
,两个对象最终共享同一个列表——所以当枪移动时(每当玩家移动时都会发生这种情况),所有的子弹都会移动——同样,当子弹移动时,枪也动!
我建议防止此类错误的方法是将您存储coordinates
为元组而不是列表:
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"""
x, y = self.coordinates
self.coordinates = x + where * self.speed, y
def move_y(self, where):
"""Moving player by y axis"""
x, y = self.coordinates
self.coordinates = x, y + where * self.speed
元组是不可变的,这意味着:
- 您不能修改其中的单个元素。所以...
- 您只能通过创建一个全新的元组来修改它们。所以...
- 您与之共享元组的任何其他内容仍将具有它的原始版本
对于跟踪独立游戏状态的片段,这是一件好事,因为它可以防止对一个对象状态的更改无意影响另一个对象。
另一种选择是继续使用列表,但在传递列表时要非常小心,例如:
# Gun
def shoot(self):
self.bullets.append(Bullet())
self.bullets[-1].shoot(self.coordinates.copy())
对于这个特定的错误,这是一个稍微容易一点的修复——但是通过这个修复,将来类似的错误也很容易弹出,这就是为什么我推荐使用元组的路线。
推荐阅读
- blazor - Blazor 的 Telerik UI:在代码中将项目添加到网格
- liferay - 如何在 Liferay 中的站点之间共享母版页?
- stored-procedures - 我可以在雪花存储过程中运行外部文件吗?
- c++ - C++ 动态数组没有请求大小
- python - 类中两个属性之间的差异
- git - 将 react 依赖推送到 github 项目中共享
- javascript - 部署 next.js 应用程序时静态页面上的预渲染错误
- django - 如何在 docker 容器中使用 crontab 运行定期任务?
- java - 处理 - 图片未加载,因为未使用 X
- ibm-midrange - JTOpen 中的 IBM i 命令提示不适用于 Java 9 及更高版本