在 pygame 中旋转时,船舶向上和向左移动的速度比向下和向右移动的速度快
Ship moves up and left faster than down and right when rotating in pygame
我正在开发一个简单的游戏。我创建了一个 pygame 精灵,并通过使其以一致的速度向前移动和旋转来对其进行测试。然而,它向左和向上移动(其中 sin 和 cos 为负)比向右和向下移动(其中 sin 和 cos 为正)更快。我在没有移动和旋转的情况下测试了它,它可以工作。
代码如下:
import pygame
import sys
from math import cos, sin, pi
from time import sleep
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 800
FPS = 60
pygame.init()
DISPLAY = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
CLOCK = pygame.time.Clock()
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
SHIP_BLUE_IMG = pygame.image.load('./spaceshooter/PNG/playerShip1_blue.png').convert()
SHIP_RED_IMG = pygame.image.load('./spaceshooter/PNG/playerShip1_red.png').convert()
LASER_BLUE_IMG = pygame.image.load('./spaceshooter/PNG/Lasers/laserBlue16.png').convert()
LASER_RED_IMG = pygame.image.load('./spaceshooter/PNG/Lasers/laserRed16.png').convert()
LASER_SPEED = 10
PLAYER_SHIP_SPEED = 5
all_sprites = pygame.sprite.Group()
class Player(pygame.sprite.Sprite):
def __init__(self, img, pos, angle):
super().__init__()
img.set_colorkey((0, 0, 0, 0))
self.angle = angle
self.original_img = pygame.transform.rotate(img, 180) # Becase these images come upside down
self.image = self.original_img
self.rect = self.image.get_rect()
self.rect.center = pos
self._update_image()
def _update_image(self):
x, y = self.rect.center
self.image = pygame.transform.rotate(self.original_img, self.angle)
self.rect = self.image.get_rect()
self.rect.center = (x, y)
def _get_radeons(self):
return (self.angle*pi)/180
def rotate(self, degrees):
self.angle += degrees
self._update_image()
def update(self):
self.rotate(5)
x, y = self.rect.center
nx = sin(self._get_radeons())*PLAYER_SHIP_SPEED + x
ny = cos(self._get_radeons())*PLAYER_SHIP_SPEED + y
self.rect.center = (nx, ny)
player = Player(SHIP_BLUE_IMG, (300, 300), 45)
all_sprites.add(player)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
DISPLAY.fill(BLACK)
all_sprites.update()
all_sprites.draw(DISPLAY)
pygame.display.update()
CLOCK.tick(FPS)
描述一下我运行它的样子,它是一艘黑色背景的船,一边逆时针旋转,一边向前移动,应该是一个圆圈。但相反,它正在形成一种螺旋,慢慢靠近屏幕的左上角。
这是一个准确性问题。由于 pygame.Rect
应该表示屏幕上的一个区域,因此 pygame.Rect
对象只能存储整数数据。
The coordinates for Rect objects are all integers. [...]
当玩家的新位置分配给 Rect 对象时,坐标的小数部分丢失:
self.rect.center = (nx, ny)
由于每帧都这样做,位置误差会随着时间累积。
如果要以浮点精度存储对象位置,则必须将对象的位置分别存储在单独的变量属性 (self.pos
) 中,并同步 pygame.Rect
对象。 round
坐标并将其分配给矩形的位置(例如.center
):
class Player(pygame.sprite.Sprite):
def __init__(self, img, pos, angle):
# [...]
self.pos = pos
# [...]
def update(self):
self.rotate(5)
nx = sin(self._get_radeons())*PLAYER_SHIP_SPEED + self.pos[0]
ny = cos(self._get_radeons())*PLAYER_SHIP_SPEED + self.pos[1]
self.pos = (nx, ny)
self.rect.center = round(nx), round(ny)
另见 Move and rotate。
最小示例:
import math
import pygame
class Player(pygame.sprite.Sprite):
def __init__(self, img, pos, angle):
super().__init__()
img.set_colorkey((0, 0, 0, 0))
self.angle = angle
self.original_img = pygame.transform.rotate(img, 180)
self.image = self.original_img
self.rect = self.image.get_rect()
self.rect.center = pos
self.pos = pos
self.speed = 5
self.angle_step = 5
self._update_image()
def _update_image(self):
x, y = self.rect.center
self.image = pygame.transform.rotate(self.original_img, self.angle)
self.rect = self.image.get_rect()
self.rect.center = (x, y)
def update(self):
self.angle += self.angle_step
self._update_image()
nx = math.sin(math.radians(self.angle)) * self.speed + self.pos[0]
ny = math.cos(math.radians(self.angle)) * self.speed + self.pos[1]
self.pos = (nx, ny)
self.rect.center = round(nx), round(ny)
pygame.init()
window = pygame.display.set_mode((300, 300))
clock = pygame.time.Clock()
background = pygame.Surface(window.get_size())
background.set_alpha(5)
all_sprites = pygame.sprite.Group()
ship_image = pygame.image.load('Rocket64.png').convert_alpha()
player = Player(ship_image, (window.get_width()//2-40, window.get_height()//2+40), 45)
all_sprites.add(player)
run = True
while run:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
all_sprites.update()
window.blit(background, (0, 0))
all_sprites.draw(window)
pygame.display.update()
pygame.quit()
exit()
我正在开发一个简单的游戏。我创建了一个 pygame 精灵,并通过使其以一致的速度向前移动和旋转来对其进行测试。然而,它向左和向上移动(其中 sin 和 cos 为负)比向右和向下移动(其中 sin 和 cos 为正)更快。我在没有移动和旋转的情况下测试了它,它可以工作。
代码如下:
import pygame
import sys
from math import cos, sin, pi
from time import sleep
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 800
FPS = 60
pygame.init()
DISPLAY = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
CLOCK = pygame.time.Clock()
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
SHIP_BLUE_IMG = pygame.image.load('./spaceshooter/PNG/playerShip1_blue.png').convert()
SHIP_RED_IMG = pygame.image.load('./spaceshooter/PNG/playerShip1_red.png').convert()
LASER_BLUE_IMG = pygame.image.load('./spaceshooter/PNG/Lasers/laserBlue16.png').convert()
LASER_RED_IMG = pygame.image.load('./spaceshooter/PNG/Lasers/laserRed16.png').convert()
LASER_SPEED = 10
PLAYER_SHIP_SPEED = 5
all_sprites = pygame.sprite.Group()
class Player(pygame.sprite.Sprite):
def __init__(self, img, pos, angle):
super().__init__()
img.set_colorkey((0, 0, 0, 0))
self.angle = angle
self.original_img = pygame.transform.rotate(img, 180) # Becase these images come upside down
self.image = self.original_img
self.rect = self.image.get_rect()
self.rect.center = pos
self._update_image()
def _update_image(self):
x, y = self.rect.center
self.image = pygame.transform.rotate(self.original_img, self.angle)
self.rect = self.image.get_rect()
self.rect.center = (x, y)
def _get_radeons(self):
return (self.angle*pi)/180
def rotate(self, degrees):
self.angle += degrees
self._update_image()
def update(self):
self.rotate(5)
x, y = self.rect.center
nx = sin(self._get_radeons())*PLAYER_SHIP_SPEED + x
ny = cos(self._get_radeons())*PLAYER_SHIP_SPEED + y
self.rect.center = (nx, ny)
player = Player(SHIP_BLUE_IMG, (300, 300), 45)
all_sprites.add(player)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
DISPLAY.fill(BLACK)
all_sprites.update()
all_sprites.draw(DISPLAY)
pygame.display.update()
CLOCK.tick(FPS)
描述一下我运行它的样子,它是一艘黑色背景的船,一边逆时针旋转,一边向前移动,应该是一个圆圈。但相反,它正在形成一种螺旋,慢慢靠近屏幕的左上角。
这是一个准确性问题。由于 pygame.Rect
应该表示屏幕上的一个区域,因此 pygame.Rect
对象只能存储整数数据。
The coordinates for Rect objects are all integers. [...]
当玩家的新位置分配给 Rect 对象时,坐标的小数部分丢失:
self.rect.center = (nx, ny)
由于每帧都这样做,位置误差会随着时间累积。
如果要以浮点精度存储对象位置,则必须将对象的位置分别存储在单独的变量属性 (self.pos
) 中,并同步 pygame.Rect
对象。 round
坐标并将其分配给矩形的位置(例如.center
):
class Player(pygame.sprite.Sprite):
def __init__(self, img, pos, angle):
# [...]
self.pos = pos
# [...]
def update(self):
self.rotate(5)
nx = sin(self._get_radeons())*PLAYER_SHIP_SPEED + self.pos[0]
ny = cos(self._get_radeons())*PLAYER_SHIP_SPEED + self.pos[1]
self.pos = (nx, ny)
self.rect.center = round(nx), round(ny)
另见 Move and rotate。
最小示例:
import math
import pygame
class Player(pygame.sprite.Sprite):
def __init__(self, img, pos, angle):
super().__init__()
img.set_colorkey((0, 0, 0, 0))
self.angle = angle
self.original_img = pygame.transform.rotate(img, 180)
self.image = self.original_img
self.rect = self.image.get_rect()
self.rect.center = pos
self.pos = pos
self.speed = 5
self.angle_step = 5
self._update_image()
def _update_image(self):
x, y = self.rect.center
self.image = pygame.transform.rotate(self.original_img, self.angle)
self.rect = self.image.get_rect()
self.rect.center = (x, y)
def update(self):
self.angle += self.angle_step
self._update_image()
nx = math.sin(math.radians(self.angle)) * self.speed + self.pos[0]
ny = math.cos(math.radians(self.angle)) * self.speed + self.pos[1]
self.pos = (nx, ny)
self.rect.center = round(nx), round(ny)
pygame.init()
window = pygame.display.set_mode((300, 300))
clock = pygame.time.Clock()
background = pygame.Surface(window.get_size())
background.set_alpha(5)
all_sprites = pygame.sprite.Group()
ship_image = pygame.image.load('Rocket64.png').convert_alpha()
player = Player(ship_image, (window.get_width()//2-40, window.get_height()//2+40), 45)
all_sprites.add(player)
run = True
while run:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
all_sprites.update()
window.blit(background, (0, 0))
all_sprites.draw(window)
pygame.display.update()
pygame.quit()
exit()