Pygame 不同对象之间的坐标同步
Pygame coordinates sync between different objects
我正在使用 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())
这是对这个特定错误的更简单的修复 -- 但是有了这个修复,将来也很容易弹出类似的错误,这就是为什么我推荐使用改为元组。
我正在使用 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())
这是对这个特定错误的更简单的修复 -- 但是有了这个修复,将来也很容易弹出类似的错误,这就是为什么我推荐使用改为元组。