问题
I am working on a simple game. I created a pygame sprite which and tested it by making it move forward and rotating at a consistent speed. However, it seams to be moving left and up (where sin and cos are negative) quicker than right and down (where sin and cos are positive). I tested it without moving and just rotating and it works.
Here is the code:
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)
To describe what it looks like when I run it, it is a ship on a black background that rotates counter-clockwise while moving forward in what should be a circle. But instead, it is creating a sort of spiral, slowly getting closer to the top left corner of the screen.
回答1:
This is an accuracy issue. Since pygame.Rect is supposed to represent an area on the screen, a pygame.Rect
object can only store integral data.
The coordinates for Rect objects are all integers. [...]
The fraction part of the coordinates gets lost when the new position of the player is assigned to the Rect object:
self.rect.center = (nx, ny)
Since this is done every frame, the position error will accumulate over time.
If you want to store object positions with floating point accuracy, you have to store the location of the object in separate variables respectively attributes (self.pos
) and to synchronize the pygame.Rect
object. round the coordinates and assign it to the location (e.g. .center
) of the rectangle:
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)
See also Move and rotate.
Minimal example:
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()
来源:https://stackoverflow.com/questions/62411259/ship-moves-up-and-left-faster-than-down-and-right-when-rotating-in-pygame