Search code examples
pythonpygame

Pygame: How to rotate a rectangle clockwise/counterclockwise depending on input


I have made one rectangle so far that follows the user's mouse and rotates counterclockwise with the a key and clockwise with the d key.

Currently the rectangle follows the mouse but once the user starts to rotate the rectangle, the rectangle becomes very laggy and disfigured. I need help with keeping the rectangle the same and a constant FPS. Thank you for your help!

Here is the code:

import pygame as py  

# define constants  
WIDTH = 500  
HEIGHT = 500  
FPS = 200

# define colors  
BLACK = (0 , 0 , 0)  
GREEN = (0 , 255 , 0)

# initialize pygame and create screen  
py.init()  
screen = py.display.set_mode((WIDTH , HEIGHT))  
# for setting FPS  
clock = py.time.Clock()  

rot = 0  
rot_speed = 2  

# define a surface (RECTANGLE)  
image_orig = py.Surface((1 , 100))  
# for making transparent background while rotating an image  
image_orig.set_colorkey(BLACK)  
# fill the rectangle / surface with green color  
image_orig.fill(GREEN)  
# creating a copy of orignal image for smooth rotation  
image = image_orig.copy()  
image.set_colorkey(BLACK)  
# define rect for placing the rectangle at the desired position  
rect = image.get_rect()
x, y = py.mouse.get_pos()
rect.center = (x, y)  
# keep rotating the rectangle until running is set to False
running = True  
while running:  

    x, y = py.mouse.get_pos()
    # set FPS  
    clock.tick(FPS)  
    # clear the screen every time before drawing new objects  
    screen.fill(BLACK)  
    # check for the exit  
    for event in py.event.get():  
        if event.type == py.QUIT:  
            running = False
    # making a copy of the old center of the rectangle  
    old_center =(x, y)
    # defining angle of the rotation  
    rot = (rot + rot_speed) % 360  
    # rotating the orignal image
    keys = py.key.get_pressed()
    rot_speed = .2 
    image_orig = py.transform.rotate(image_orig , 0)  
    rect = image_orig.get_rect()  
        # set the rotated rectangle to the old center  
    rect.center = (x, y)  
        # drawing the rotated rectangle to the screen  
    screen.blit(image_orig , rect)  
        # flipping the display after drawing everything  
    py.display.flip()
    if(keys[py.K_a]):
        rot_speed = .2 
        image_orig = py.transform.rotate(image_orig , rot)  
        rect = image_orig.get_rect()  
        # set the rotated rectangle to the old center  
        rect.center = (x, y)  
        # drawing the rotated rectangle to the screen  
        screen.blit(image_orig , rect)  
        # flipping the display after drawing everything  
        py.display.flip()
    if(keys[py.K_d]):
        rot_speed = -.2 
        image_orig = py.transform.rotate(image_orig , rot)  
        rect = image_orig.get_rect()  
        # set the rotated rectangle to the old center  
        rect.center = (x, y)  
        # drawing the rotated rectangle to the screen  
        screen.blit(image_orig , rect)  
        # flipping the display after drawing everything  
        py.display.flip()
    rect.center = (x, y)

py.quit()  

Solution

  • The mayor issue is that you continuously rotate and manipulate the original image. That causes that the image gets distorted. See How do I rotate an image around its center using Pygame?

    Compute the new angle of the image:

    rot = (rot + rot_speed) % 360  
    

    Create a new image which is rotated around its center:

    image = py.transform.rotate(image_orig, rot)  
    rect = image.get_rect(center = (x, y)) 
    

    And blit the rotated image:

    screen.blit(image, rect)  
    

    When A or D is pressed then the new direction is set by rot_speed = .2 respectively rot_speed = -.2.

    Full example code:

    import pygame as py  
    
    # define constants  
    WIDTH = 500  
    HEIGHT = 500  
    FPS = 200
    
    # define colors  
    BLACK = (0 , 0 , 0)  
    GREEN = (0 , 255 , 0)
    
    # initialize pygame and create screen  
    py.init()  
    screen = py.display.set_mode((WIDTH , HEIGHT))  
    # for setting FPS  
    clock = py.time.Clock()  
    
    rot = 0  
    rot_speed = .2  
    
    # define a surface (RECTANGLE)  
    image_orig = py.Surface((1 , 100))  
    # for making transparent background while rotating an image  
    image_orig.set_colorkey(BLACK)  
    # fill the rectangle / surface with green color  
    image_orig.fill(GREEN)  
    # creating a copy of orignal image for smooth rotation  
    image = image_orig.copy()  
    image.set_colorkey(BLACK)  
    # define rect for placing the rectangle at the desired position  
    rect = image.get_rect()
    x, y = py.mouse.get_pos()
    rect.center = (x, y)  
    # keep rotating the rectangle until running is set to False
    
    running = True  
    while running:  
    
        x, y = py.mouse.get_pos()
        # set FPS  
        clock.tick(FPS)  
        # clear the screen every time before drawing new objects  
        screen.fill(BLACK)  
        # check for the exit  
        for event in py.event.get():  
            if event.type == py.QUIT:  
                running = False
    
        # rotating the orignal image
        keys = py.key.get_pressed()
        if keys[py.K_a]:
            rot_speed = .2 
        if keys[py.K_d]:
            rot_speed = -.2 
    
        # defining angle of the rotation  
        rot = (rot + rot_speed) % 360  
        # rotating the orignal image
        image = py.transform.rotate(image_orig, rot)  
        rect = image.get_rect(center = (x, y))  
        # drawing the rotated rectangle to the screen  
        screen.blit(image, rect)  
        # flipping the display after drawing everything  
        py.display.flip()
    
    py.quit()