当我尝试使用 pygame.transform.rotate 旋转时,为什么我的精灵会重置到屏幕的左上角?

Why does my sprite reset to the top left of the screen when I try to rotate it with pygame.transform.rotate?

每当玩家按下 A 和 D 键时,我都会尝试将 sprite 旋转 90 度,我已经成功了,但每当发生这种情况时,sprite 总是被发送到屏幕的左上角.有人可以阐明这一点吗?除此之外,我还试图通过创建一个小行星并将其附加到列表中来使一个射击系统与射击小行星一起工作,但是当我尝试时它似乎变成了一个元组而不是 pygame 矩形更改它的 y,有人可以帮忙吗?

import pygame, sys, random
from pygame.locals import *
#Imports pygame, system and random as modules to use later in the code. 
#Also imports extra stuff from pygame that contains useful variables.

pygame.init()
mainClock = pygame.time.Clock()
FONT = pygame.font.SysFont(None, 48)
#Initialises pygame, sets up the clock to stop the program running too fast
#And also makes the font (must happen after pygame initialises)

WINDOWWIDTH = 1000
WINDOWHEIGHT = 1000
BACKGROUNDCOLOUR = (255, 255, 255)
TEXTCOLOUR = (0, 0, 0)
FPS = 60
PLAYERSPEED = 5
PLAYERIMAGE = pygame.image.load("images/P1.png")
PLAYERRECT = PLAYERIMAGE.get_rect()
ASTEROIDIMAGE = pygame.image.load("images/asteroid.png")
ASTEROIDRECT = ASTEROIDIMAGE.get_rect()
ASTEROIDMINSIZE = 3
ASTEROIDMAXSIZE = 5
ASTEROIDSPEED = 5
ASTEROIDS = []
#Defining Variables and setting up player sprite

def terminate():
    pygame.quit()
    sys.exit()

def pendingKey():
    while True:
        for event in pygame.event.get():
            if event.type == QUIT:
                terminate()
            if event.type == KEYDOWN:
                if event.key == K_ESCAPE:
                    terminate()
                return

def drawText(text, font, surface, x, y):
    textobj = font.render(text, 1, TEXTCOLOUR)
    textrect = textobj.get_rect()
    textrect.topleft = (x, y)
    surface.blit(textobj, textrect)

#Defining functions, to quit pygame and the system.
#And to wait for the escape key to be pressed to start the terminate function.
#And to wait for the quit event (such as at the end of the game).
#And a function to create text on the screen, such as for the title.


WINDOWSURFACE = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))
pygame.display.set_caption('Space Penguin Remastered')
pygame.mouse.set_visible(False)
#Creates the games window, sets the name of the window, and makes the mouse invisible

WINDOWSURFACE.fill(BACKGROUNDCOLOUR)
drawText('Space Penguin Remastered', FONT, WINDOWSURFACE, (WINDOWWIDTH / 3), (WINDOWHEIGHT / 3))
drawText('Press a key to start!', FONT, WINDOWSURFACE, (WINDOWWIDTH / 3) - 30, (WINDOWHEIGHT / 3) + 50)
pygame.display.update()
pendingKey()
#Sets the colour of the background and draws the title and some basic instructions
#And updates the display and activates the terminate function

while True: 
    LEFT = RIGHT = UP = DOWN = SHOOT = LEFTROTATE = RIGHTROTATE = False
    #Sets the players start position to half through the screen, and 50 pixels down
    #And sets the movement variables to false

    while True:
        for event in pygame.event.get():
            if event.type == QUIT:
                terminate()
            #Checks for events, first event being the game quitting
            if event.type == KEYDOWN:
                if event.key == K_LEFT:
                    RIGHT = False
                    LEFT = True
                if event.key == K_RIGHT:
                    LEFT = False
                    RIGHT = True
                if event.key == K_UP:
                    DOWN = False
                    UP = True
                if event.key == K_DOWN:
                    UP = False
                    DOWN = True
                if event.key == K_SPACE:
                    SHOOT = True
                if event.key == K_a:
                    RIGHTROTATE = False
                    LEFTROTATE = True
                if event.key == K_d:
                    LEFTROTATE = False
                    RIGHTROTATE = True
            #Checks for keys being pressed, corresponding to movement.
                if event.key == K_ESCAPE:
                    terminate()
            #Checks for escape being pressed, which quits the game.
            if event.type == KEYUP:
                if event.key == K_ESCAPE:
                    terminate()
                if event.key == K_LEFT:
                    LEFT = False
                if event.key == K_RIGHT:
                    RIGHT = False
                if event.key == K_UP:
                    UP = False
                if event.key == K_DOWN:
                    DOWN = False
                if event.key == K_SPACE:
                    SHOOT = False
                if event.key == K_a:
                    RIGHTROTATE = False
                    LEFTROTATE = False
                if event.key == K_d:
                    LEFTROTATE = False
                    RIGHTROTATE = False
                #Checks whether keys have been let go of. 
        
        if LEFT and PLAYERRECT.left > 0:
            PLAYERRECT.move_ip(-1 * PLAYERSPEED, 0)
        if RIGHT and PLAYERRECT.right < WINDOWWIDTH:
            PLAYERRECT.move_ip(PLAYERSPEED, 0)
        if UP and PLAYERRECT.top > 0:
            PLAYERRECT.move_ip(0, -1 * PLAYERSPEED)
        if DOWN and PLAYERRECT.bottom < WINDOWHEIGHT:
            PLAYERRECT.move_ip(0, PLAYERSPEED)
        if SHOOT:
            ASTEROIDS.append(ASTEROIDIMAGE.get_rect(center=PLAYERRECT.midtop))
        if LEFTROTATE:
            PLAYERIMAGE = pygame.transform.rotate(PLAYERIMAGE, 90)
            PLAYERRECT = PLAYERIMAGE.get_rect()
        if RIGHTROTATE:
            PLAYERIMAGE = pygame.transform.rotate(PLAYERIMAGE, -90)
            PLAYERRECT = PLAYERIMAGE.get_rect()
        for asteroid in ASTEROIDS:
            asteroid.y -= 4

        for asteroid in ASTEROIDS:
            WINDOWSURFACE.blit(ASTEROIDIMAGE, asteroid)

        #Moves the player a certain number of pixels in a direction and shoots asteroids

        WINDOWSURFACE.fill(BACKGROUNDCOLOUR)
        WINDOWSURFACE.blit(PLAYERIMAGE, PLAYERRECT)
        pygame.display.update()
        mainClock.tick(FPS)
        #Fills the background, draws the players image on the rectangle
        #And updates the screen and selects how many frames per second the game should tick by

提前致谢

请注意,您只能在应用程序中调用一次 pygame.event.get()

当你旋转时,你设置你的播放器矩形:

PLAYERRECT = PLAYERIMAGE.get_rect()

您从未指定 PLAYERIMAGE.get_rect() 的值,默认情况下为 (0, 0),因此如果播放器被传送到屏幕的左上角。要解决这个问题,只需将其删除即可,它没有任何用处。

此外,您的移动代码可以简化。

   keys = pygame.key.get_pressed()
   PLAYERRECT.move_ip
    (
        (keys[K_RIGHT] - keys[K_LEFT]) * PLAYERSPEED, 
        (keys[K_DOWN] - keys[K_UP]) * PLAYERSPEED
    )

就是这样。

处​​理旋转的代码也可以简化。制作一个获取玩家旋转角度的函数:

def getPlayerRotation(keys):
    if keys[K_a]: return 90
    elif keys[K_d]: return -90
    return 0

然后用它来旋转你的图像并绘制它。

#
rotated_image = pygame.transform.rotate(PLAYERIMAGE, getPlayerRotation(keys))
new_rect = rotated_image.get_rect(center = PLAYERIMAGE.get_rect(topleft = PLAYERRECT.topleft).center)
WINDOWSURFACE.blit(rotated_image, new_rect)

你的小行星没有绘制,因为你试图在清除屏幕之前绘制它,它绘制在小行星上。

你也做不到

 ASTEROIDS.append(ASTEROIDIMAGE.get_rect(center=PLAYERRECT.midtop))

因为只有一个 asteroid.rect 对象,所以你追加的是一遍又一遍地引用同一个对象。如果你想使用矩形,你需要创建一个新的矩形,但我通过使用列表解决了这个问题。

 ASTEROIDS.append(list(PLAYERRECT.center))

之后:

 for asteroid in ASTEROIDS:
        asteroid[1] -= 4

最后我更改了pending key函数:

def pendingKey(events):
    for event in events:
        if event.type == QUIT:
            terminate()
        if event.type == KEYDOWN:
            if event.key == K_ESCAPE:
                terminate()

它将事件作为参数以避免在函数中调用 pygame.event.get()。我还删除了它末尾的 return 语句,因为它导致函数在完成所有事件之前退出。

这是新代码:

import pygame, sys, random
from pygame.locals import *

WINDOWWIDTH = 1000
WINDOWHEIGHT = 1000
pygame.init()
mainClock = pygame.time.Clock()
FONT = pygame.font.SysFont(None, 48)


BACKGROUNDCOLOUR = (255, 255, 255)
TEXTCOLOUR = (0, 0, 0)
FPS = 60
PLAYERSPEED = 5
PLAYERIMAGE = pygame.image.load("images/P1.png")
PLAYERRECT = PLAYERIMAGE.get_rect()
ASTEROIDIMAGE = pygame.image.load("images/asteroid.png")
ASTEROIDRECT = ASTEROIDIMAGE.get_rect()
ASTEROIDMINSIZE = 3
ASTEROIDMAXSIZE = 5
ASTEROIDSPEED = 5
ASTEROIDS = []
#Defining Variables and setting up player sprite

def terminate():
    pygame.quit()
    sys.exit()

def pendingKey(events):
    for event in events:
        if event.type == QUIT:
            terminate()
        if event.type == KEYDOWN:
            if event.key == K_ESCAPE:
                terminate()

def drawText(text, font, surface, x, y):
    textobj = font.render(text, 1, TEXTCOLOUR)
    textrect = textobj.get_rect()
    textrect.topleft = (x, y)
    surface.blit(textobj, textrect)

WINDOWSURFACE = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))
pygame.display.set_caption('Space Penguin Remastered')
pygame.mouse.set_visible(False)

WINDOWSURFACE.fill(BACKGROUNDCOLOUR)
drawText('Space Penguin Remastered', FONT, WINDOWSURFACE, (WINDOWWIDTH / 3), (WINDOWHEIGHT / 3))
drawText('Press a key to start!', FONT, WINDOWSURFACE, (WINDOWWIDTH / 3) - 30, (WINDOWHEIGHT / 3) + 50)
pygame.display.update()

def getPlayerRotation(keys):
    if keys[K_a]: return 90
    elif keys[K_d]: return -90
    return 0

while True:
    events = pygame.event.get()
    pendingKey(events)

    keys = pygame.key.get_pressed()
    PLAYERRECT.move_ip((keys[K_RIGHT] - keys[K_LEFT]) * PLAYERSPEED, (keys[K_DOWN] - keys[K_UP]) * PLAYERSPEED)

    #
    rotated_image = pygame.transform.rotate(PLAYERIMAGE, getPlayerRotation(keys))
    new_rect = rotated_image.get_rect(center = PLAYERIMAGE.get_rect(topleft = PLAYERRECT.topleft).center)

    for event in events:
        if event.type == KEYDOWN and event.key == K_SPACE:
            ASTEROIDS.append(list(PLAYERRECT.center))

    for asteroid in ASTEROIDS:
        asteroid[1] -= 4

    WINDOWSURFACE.fill(BACKGROUNDCOLOUR)
    WINDOWSURFACE.blit(rotated_image, new_rect)
    for asteroid in ASTEROIDS:
        WINDOWSURFACE.blit(ASTEROIDIMAGE, asteroid)
    pygame.display.update()
    
    mainClock.tick(FPS)