-1

SUMMARY very basic pygame animation results in choppy visuals. How to resolve?

DETAIL I have very basic python/pygame code to animate a rotating circle moving around in circular path. However when run the white circle's movement is choppy and uneven - at paints along the path the circle looks like it's jumping or bouncing! Set up: pygame 2.4.0 (SDL 2.26.4, Python 3.9.7), Win, 8GB, 1.6 GHz, 4 core Corei5-8265U. I know this is a very basic laptop but it doesn't have any problems with simple graphics and animations in other programs. The 'frame rate' and step size in the animation are quite low so not sure why there's problem.

Here's the code:

import pygame
from pygame.locals import *
import math
pygame.init()
screen = pygame.display.set_mode((1080, 720))
ORIGIN_X, ORIGIN_Y = 540, 360
RADIUS = 100
clock = pygame.time.Clock()
FRAME_RATE = 60
WHITE = (255, 255, 255)
BLACK = (  0,   0,   0)
PATH_RADIUS = 200
THETA_STEP = -3
def draw_objects(surface):
    pygame.draw.circle(surface, WHITE, centre_rotated_surface, RADIUS)
    pygame.draw.line(surface, BLACK, (0, surface_height // 2), (surface_width, surface_height // 2), 1)
    return
def rotate_objects(surface, angle):
    rect_surface = surface.get_rect()
    surface_rotated = pygame.transform.rotate(surface, angle)
    rect_rotated_surface = surface_rotated.get_rect()
    centre_rotated_surface = rect_rotated_surface.center
    return surface_rotated, centre_rotated_surface
surface_width, surface_height = 2 * RADIUS, 2 * RADIUS
surface = pygame.Surface((surface_width, surface_height), SRCALPHA)
centre_rotated_surface = (RADIUS, RADIUS)
draw_objects(surface)
THETA = 0
running = True
while running:
    clock.tick(FRAME_RATE)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
    circle_centre_x = round(ORIGIN_X + PATH_RADIUS * math.cos(math.pi * THETA / 180)) 
    circle_centre_y = round(ORIGIN_Y + PATH_RADIUS * math.sin(math.pi * THETA / 180))
    surface_rotated, centre_rotated_surface = rotate_objects(surface, THETA)
    screen.fill(BLACK)
    screen.blit(surface_rotated, (circle_centre_x - surface_width // 2, circle_centre_y - surface_height // 2))
    pygame.display.update()
    THETA = (THETA + THETA_STEP) % 360
pygame.quit()

ATTEMPTED FIXES

  • using pygame.display.flip() instead
  • double buffering These make no discernible difference to my eye.

Edit (2nd Jun 2023) Thanks for @The_spider's correcting my maths/logic. Can anyone help also with the issue of the glitches that still remain? See imgur video: animation with glitches

  • Please look at [this question](https://stackoverflow.com/questions/4183208/how-do-i-rotate-an-image-around-its-center-using-pygame) to help you understand how to correctly rotate with PyGame. – import random Jun 01 '23 at 03:36

1 Answers1

0

The problem is that when you rotate the circle, its surface gets bigger. Although the image visually looks as a circle, pygame sees it as a rectangle. When using pygame.transform.rotate, all the pixels around the circle are rotated too. As the resulting rotated rectangle is no longer axis-aligned, it is placed in a new, bigger rectangle.

However, you still use the width and height of the initial, unrotated circle to find the blitting position. Instead of using the original width and height, you should determine the new width and height of the rotated surface and use that to blit it.

Thus, you should change this line:

screen.blit(surface_rotated, (circle_centre_x - surface_width // 2, circle_centre_y - surface_height // 2))

into this:

screen.blit(surface_rotated, (circle_centre_x - surface_rotated.get_width() // 2, circle_centre_y - surface_rotated.get_height() // 2))
The_spider
  • 1,202
  • 1
  • 8
  • 18