I'm attempting to create an animation that shows a box bouncing off the edges of the screen. And, I'm attempting to accomplish this using time-based animation and dirty rectangles.
I was able to animate the box; however, the animation is pretty choppy. Here are two videos that illustrate what I'm talking about:
30 FPS: https://www.youtube.com/watch?v=0de8ENxn7GQ
60 FPS: https://www.youtube.com/watch?v=b5sXgeOlgHU
And here is my code:
import sys
import random
import pygame
class Box:
def __init__(self, x, y):
self.width = 38
self.height = 38
self.color = (255, 0, 0)
self.x = x
self.y = y
self.old_x = x
self.old_y = y
self.d_x = 1
self.d_y = -1
self.px_per_second = 200
def move(self):
self.old_x = self.x
self.old_y = self.y
if self.x <= 0:
self.d_x *= -1
if self.x + self.width >= task.width:
self.d_x *= -1
if self.y <= 0:
self.d_y *= -1
if self.y + self.height >= task.height:
self.d_y *= -1
self.x += ((self.px_per_second*self.d_x)*
(task.ms_from_last_frame/1000.0))
self.y += ((self.px_per_second*self.d_y)*
(task.ms_from_last_frame/1000.0))
def draw(self):
self.x_i = int(self.x)
self.y_i = int(self.y)
self.old_x_i = int(self.old_x)
self.old_y_i = int(self.old_y)
_old_rect = (pygame.Rect(self.old_x_i, self.old_y_i,
self.width, self.height))
_new_rect = (pygame.Rect(self.x_i, self.y_i, self.width, self.height))
if _old_rect.colliderect(_new_rect):
task.dirty_rects.append(_old_rect.union(_new_rect))
else:
task.dirty_rects.append(_old_rect)
task.dirty_rects.append(_new_rect)
pygame.draw.rect(task.screen, task.bg_color, _old_rect)
pygame.draw.rect(task.screen, (self.color), _new_rect)
class ObjectTask:
def __init__(self, width, height):
pygame.init()
self.max_fps = 60
self.clock = pygame.time.Clock()
self.width = width
self.height = height
self.bg_color = (255, 255, 255)
self.dirty_rects = []
self.screen = pygame.display.set_mode((self.width, self.height),
pygame.FULLSCREEN)
self.screen.fill(self.bg_color)
pygame.display.update()
def animation_loop(self):
self.box1 = Box(self.width/2, self.height/2)
while 1:
self.ms_from_last_frame = self.clock.tick(self.max_fps)
self.box1.move()
self.box1.draw()
pygame.display.update(self.dirty_rects)
self.dirty_rects = []
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
if __name__ == "__main__":
task = ObjectTask(726, 546)
task.animation_loop()
Is there anything I can do to reduce the choppiness? Also, I'm new to Pygame, so if you see anything that I'm doing incorrectly/inefficiently, please let me know.
I'm running the animation on a 64-bit Windows 7, i5-6300u machine with 12 GB of RAM. I'm using Python 2.7.12 and Pygame 1.9.2.
Thanks in advance!
I had some time over and thought I might show how I would write this program. I've tried to explain what everything do in comments. I removed your
ObjectTask
class because everything could fit in a single function and functions are neat (they're quicker and easier to read/debug in my opinion).I also changed it so you pass variables into methods instead of reading it from a global variable (the
task
object) because it makes the program more modular and easier to change/refactor.Lastly I put some attributes into one.
x
andy
are connected, so I put them into one common attributeposition
.In this example I didn't bother with tracking dirty rects. I've experienced that it's what causing the jitter. This example I've provided should work decent, but there's always some jitter from time to time. If you want to try out this example with tracking dirty rects, just change:
to
and
to