Chaining Tweens Together¶
Bounce then Role: A First Attempt¶
Suppose we want to create something like:
That is, we want the ball to bounce then role to the right off the screen.
We can re-use the previous example fall tween. That is:
fall = ty.Tween(1.0, ball,
{"y" : screen.get_height() / 2},
ease_func=bounce)
Then we need a tween for rolling. So, we must now modify the x attribute so it is off screen. Consider:
roll = ty.Tween(1.0, ball,
{"x" : screen.get_width() + ball.r},
ease_func=quad)
One might be tempted to do:
ty.default_manager.add(fall)
ty.default_manager.add(roll)
But that does not quite work. Observe:
What Went Wrong? (And How to Fix It!)¶
For more complicated movements, we may need to tween multiple values at once. In fact, this is more likely to happen than sequentially running tween after tween. Thus, simply adding the tweens to a manager will run them concurrently. Fortunately, it is not too hard to fix. We will use the transytion.chain function to force a sequence of tweens to run in order. Replace:
ty.default_manager.add(fall)
ty.default_manager.add(roll)
with
ty.default_manager.add(ty.chain([fall, roll]))
The transytion.chain, in this case, will return a new tween that runs the fall tween and then the roll tween.
For the sake of completeness, here is the entire example (it should look similar to the previous example!):
import transytion as ty
from dataclasses import dataclass
from transytion.ease_funcs import bounce, quad
import pygame
pygame.init()
screen = pygame.display.set_mode((1280, 720))
clock = pygame.time.Clock()
running = True
dt = 0
@dataclass
class Ball:
x: float
y: float
r: float
ball = Ball(screen.get_width() / 2.0, 0.0 - 40.0, 40.0)
fall = ty.Tween(1.0, ball,
{"y" : screen.get_height() / 2},
ease_func=bounce)
roll = ty.Tween(1.0, ball,
{"x" : screen.get_width() + ball.r},
ease_func=quad)
ty.default_manager.add(ty.chain([fall, roll]))
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
ty.default_manager.update(dt)
screen.fill((0,0,0))
pygame.draw.circle(screen, "red", (ball.x, ball.y), ball.r)
pygame.display.flip()
dt = clock.tick(60) / 1000
pygame.quit()