Created
October 17, 2022 10:32
-
-
Save KokoseiJ/389f9c6c8573a61ba771cd9275fce93d to your computer and use it in GitHub Desktop.
Moving objects smoothly in pygame with decreasing acceleration rate
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import pygame | |
import time | |
class SmoothMove: | |
def __init__(self, surface, orig, dest, duration): | |
self.surface = surface | |
self.orig = orig | |
self.dest = dest | |
self.duration = duration | |
self.starttime = None | |
self.y = 360 | |
self.distance = dest - orig | |
self.start_speed = 2 * self.distance / duration | |
self.acceleration = -self.start_speed / duration | |
@property | |
def is_started(self): | |
return self.starttime is not None | |
@property | |
def elapsed_time(self): | |
if self.is_started: | |
return time.perf_counter() - self.starttime | |
else: | |
return None | |
@property | |
def is_running(self): | |
return self.is_started and not self.elapsed_time > self.duration | |
def start(self): | |
self.starttime = time.perf_counter() | |
def reset(self): | |
self.starttime = None | |
def get_pos(self): | |
return self._get_pos(self.elapsed_time) | |
def draw(self, surface): | |
return surface.blit(self.surface, (self.get_pos(), self.y)) | |
def _get_pos(self, time_): | |
if not self.is_started: | |
cur_pos = self.orig | |
elif self.elapsed_time <= self.duration: | |
# s = v0t + 1/2at^2 | |
cur_pos = ( | |
self.orig | |
+ self.start_speed * time_ | |
+ self.acceleration * time_**2 / 2 | |
) | |
else: | |
cur_pos = self.dest | |
return cur_pos | |
class SmoothMoveXY: | |
def __init__(self, surface, orig, dest, duration): | |
self.surface = surface | |
self.orig = orig | |
self.dest = dest | |
self.duration = duration | |
self.starttime = None | |
self.distance_x = dest[0] - orig[0] | |
self.start_speed_x = 2 * self.distance_x / duration | |
self.acceleration_x = -self.start_speed_x / duration | |
self.distance_y = dest[1] - orig[1] | |
self.start_speed_y = 2 * self.distance_y / duration | |
self.acceleration_y = -self.start_speed_y / duration | |
@property | |
def is_started(self): | |
return self.starttime is not None | |
@property | |
def elapsed_time(self): | |
if self.is_started: | |
return time.perf_counter() - self.starttime | |
else: | |
return None | |
@property | |
def is_running(self): | |
return self.is_started and not self.elapsed_time > self.duration | |
def start(self): | |
self.starttime = time.perf_counter() | |
def reset(self): | |
self.starttime = None | |
def get_pos(self): | |
return self._get_pos(self.elapsed_time) | |
def draw(self, surface): | |
return surface.blit(self.surface, self.get_pos()) | |
def _get_pos(self, time_): | |
if not self.is_started: | |
cur_pos = self.orig | |
elif self.elapsed_time <= self.duration: | |
# s = v0t + 1/2at^2 | |
cur_pos_x = ( | |
self.orig[0] | |
+ self.start_speed_x * time_ | |
+ self.acceleration_x * time_**2 / 2 | |
) | |
cur_pos_y = ( | |
self.orig[1] | |
+ self.start_speed_y * time_ | |
+ self.acceleration_y * time_**2 / 2 | |
) | |
cur_pos = (cur_pos_x, cur_pos_y) | |
else: | |
cur_pos = self.dest | |
return cur_pos | |
pygame.init() | |
clock = pygame.time.Clock() | |
screen = pygame.display.set_mode((1280, 720)) | |
surface = pygame.Surface((300, 300), pygame.SRCALPHA) | |
pygame.draw.circle(surface, "red", (150, 150), (150)) | |
sm = SmoothMoveXY(surface, (0, 0), (1280 - 300, 720 - 300), 1) | |
while True: | |
for event in pygame.event.get(): | |
if event.type == pygame.QUIT: | |
exit() | |
elif event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE: | |
if sm.is_started and not sm.is_running: | |
sm.reset() | |
else: | |
sm.start() | |
screen.fill("gray") | |
sm.draw(screen) | |
pygame.display.flip() | |
clock.tick_busy_loop(60) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment