0

I'm trying to rotate a sprite 90 degrees whenever the player presses the A and D keys, and I've got that working, but the sprite is always sent to the top left corner of the screen whenever this happens. Can someone shed some light on this? As well as that, I've tried to get a shooting system working with shooting asteroids, by creating an asteroid and appending it to a list, but it seems to become a tuple instead of a pygame rectangle when I try to change the y of it, can someone help with that as well?

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

Thanks in advance

Derek T
  • 3
  • 2

1 Answers1

1

Note that you should only call pygame.event.get() once in your application.

When you rotate, you set your player rect as such:

PLAYERRECT = PLAYERIMAGE.get_rect()

You have never specified the value of PLAYERIMAGE.get_rect() and it is (0, 0) by default, so if the player is transported to the top left of the screen. To fix that, simply remove it, it serves no purpose.

Also, your movement code can be simplified.

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

Thats it.

Code to handle rotation can be simplified as well. Make a function that gets the players rotation angle:

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

Then use that to rotate your image and draw it.

#https://stackoverflow.com/questions/4183208/how-do-i-rotate-an-image-around-its-center-using-pygame
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)

Your asteroid isn't drawing because you are trying to draw it before you clear the screen, which draws over the asteroids.

Also you cannot do

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

because there is only one asteroid.rect object, so what you are appending is a reference to the same object over and over. You need to create a new rect if your want to use a rect, but I got around the problem by using a list.

 ASTEROIDS.append(list(PLAYERRECT.center))

and then later:

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

Lastly I changed pending key function:

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

It takes events as argument to avoid calling pygame.event.get() in the function. I also removed the return statement at the end of it since it was causing the function to exit before it got to to through all the events.

Here is the new code:

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)

    #https://stackoverflow.com/questions/4183208/how-do-i-rotate-an-image-around-its-center-using-pygame
    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)