2

I'm trying to rotate the whole screen, and all the objects on the surface. But when I blit the surface it just creates a new one, leaving me with four. In other words; I have two images that are not rotating, and two that are. I want to remove the ones that are not rotating. I've looked for hours trying to find answers. But nothing. Is it even possible...? (Rotates when the mouse is moving.)

# import os
import pygame
from pygame.locals import *

pygame.init()
screen = pygame.display.set_mode((500, 500), pygame.RESIZABLE)
pic = pygame.image.load("image.png")
pic2 = pygame.image.load("image.png")

pygame.display.flip()

angle = 1


while True:
    screen.fill((0, 0, 0))
    screen.blit(pic, (30, 20))
    screen.blit(pic2, (22, 40))
    # This creates a copy and blitz it. So there's 4, when there should be 2.
    # The 2 that are not rotating should not be on the screen.
    screen.blit(pygame.transform.rotate(screen, angle), (100, 0))  # x = 100 so you 
can see the other 2 behind it.
    pygame.display.flip()

    angle += 1

    pygame.event.pump()
    event = pygame.event.wait()
    if event.type == QUIT:
        pygame.display.quit()
    elif event.type == VIDEORESIZE:
        screen = pygame.display.set_mode(event.dict['size'], HWSURFACE | DOUBLEBUF 
| RESIZABLE)
        pygame.display.flip()
Three Point 14
  • 150
  • 2
  • 8

1 Answers1

2

The code is not handling events properly, this is why it only rotates while the mouse is moving.

The two images continually appear because they are being re-drawn in the main loop. The code draws them to the window, then copies the window, rotates it, and finally re-paints it offset to the right. So it is duplicating what's on the screen already, thus you see 4x objects.

The wording of your question is not 100% clear to me, but I think you just want to see an image of those objects rotating. So the first thing to do is make an off-screen Surface containing those images, and use that for rotation and drawing to the actual screen:

screen = pygame.display.set_mode((400, 400), pygame.RESIZABLE)
pic = pygame.image.load("emitter_128.png")
pic2 = pygame.image.load("big_alien.png")

# Make the original surface to rotate
original_surface = pygame.Surface( ( screen.get_rect().width, screen.get_rect().height ) )
original_surface.fill( (0, 0, 0))
original_surface.blit( pic, (30, 20))
original_surface.blit( pic2, (22, 40))

Then in the main body of the code, rotate the original_surface, and paint that to the screen.

# This creates a copy and blitz it. So there's 4, when there should be 2.
# The 2 that are not rotating should not be on the screen.
screen.fill( ( 0, 0, 50 ) )
if ( rotating ):
    angle += 1
    rotated_surface = pygame.transform.rotate( original_surface, angle )
    rotated_surface_rect = rotated_surface.get_rect()
    rotated_surface_rect.center = screen_centre

screen.blit( rotated_surface, rotated_surface_rect )

When square bitmap images rotate, the size changes, since the result (say now diamond shape, with a corner up) still has to fit inside a square bitmap. If you just keep drawing to the same co-ordinate, the rotation looks wobbly.

One way of fixing this is to draw the rotated bitmap about its centre, keeping that central point at the same position on-screen. This causes the bitmap to appear to be rotating about itself (around it centroid). To do this we need to move the bitmap's centre to the desired screen co-ordinate. This is why we need to deal with the rotated_surface Rect.

NOTE: The horrible flashing background colour combination was chosen to illustrate what part is rotated bitmap, and what part is the screen behind it.

Apologies for the poor animated .GIF framerate. It's quite smooth on-screen.

rotatey-thing

Reference Code:

import pygame

pygame.init()
SURFACE = pygame.HWSURFACE | pygame.DOUBLEBUF | pygame.RESIZABLE
screen  = pygame.display.set_mode((400, 400), SURFACE )
pic1    = pygame.image.load("emitter_128.png")
pic2    = pygame.image.load("big_alien.png")

# Make the original surface to rotate
original_surface = pygame.Surface( ( screen.get_rect().width, screen.get_rect().height ) )
original_surface.fill( (0, 0, 0))
original_surface.blit( pic1, (30, 20))
original_surface.blit( pic2, (22, 40))

# We need to centre the image so the rotation looks smooth
screen_centre = ( screen.get_rect().width//2, screen.get_rect().height//2 )

angle = 1
rotating = True  # used to pause rotation
running  = True  # used to exit
while running:
    # Handle user-input
    for event in pygame.event.get():
        if ( event.type == pygame.QUIT ):
            running = False          # exit
        elif ( event.type == pygame.KEYDOWN ):
            rotating = not rotating  # pause rotation on any key
        elif ( event.type == pygame.VIDEORESIZE ):
            screen = pygame.display.set_mode(event.dict['size'], SURFACE )
            screen_centre = ( screen.get_rect().width//2, screen.get_rect().height//2 )

    # This creates a copy and blitz it. So there's 4, when there should be 2.
    # The 2 that are not rotating should not be on the screen.
    # screen.fill( ( 0, 0, 50 ) ) - use for horrible background
    screen.fill( ( 0, 0, 0 ) )
    if ( rotating ):
        angle += 1
        rotated_surface = pygame.transform.rotate( original_surface, angle )
        rotated_surface_rect = rotated_surface.get_rect()
        rotated_surface_rect.center = screen_centre

    # finally draw the rotated bitmap to the screen
    screen.blit( rotated_surface, rotated_surface_rect )

    # Update the window
    pygame.display.flip()

pygame.display.quit()
Kingsley
  • 14,398
  • 5
  • 31
  • 53
  • 1
    Wow. That's more then what I was even asking for. Sorry if I was unclear by the way. But yes. I just wanted to rotate everything, (the two objects) with out doubling it and getting 4. But I'll use all of your tips to improve more. Thanks for the help! – Three Point 14 Jul 02 '20 at 17:48