Skip to content

Animation

aspiringLich edited this page Feb 6, 2023 · 11 revisions

Now that you've got some graphics on the screen, you might want to make it a bit more dynamic. Lucky for you, there's a built in animation system that's simple™, easy™, and capable™. The following methods are defined in Animatable.

Animation Methods Paramteters Description
colorTo() (int r, int g, int b, double duration) Fades from an element's current color, to the defined one using RGB to define the color
colorTo() (int hex, double duration) Fades from an element's current color, to the defined one using 8-bit RGB hex literal to define the color
colorTo() (Color color, double duration) Fades from an element's current color, to the defined one using a Color to define the color.
rotateTo() (int degrees, double duration) Rotates an element to degrees degrees. So, rotateTo(360) would do a 360° counter-clockwise flip if the object was originally at 0° rotation.
rotateBy() (int degrees, double duration) Rotates an element from its current rotation, to it's current rotation + degrees. Positive is counter-clockwise, negative is clockwise.
moveTo() (int x, int y, double duration) Moves an element from its current position, to this specific x and y position. This is absolute movement, so if an element is at 100, 100 and you call moveTo(0, 100) it moves to 0, 100.
moveBy() (int x, int y, double duration) Moves an element x pixels horizontally, and y pixels vertically. This is relative movement, so if an element is at 100, 100 and you call moveTo(0, 100) it moves to 100, 200.
moveHorizontalBy() (int x, int y, double duration) Moves an element x pixels horizontally, equivalent to moveBy(x, 0)
moveVerticalBy() (int x, int y, double duration) Moves an element y pixels vertically, equivalent to moveBy(0, y)
fadeIn() (double duration) Fades an element in if it has been faded out before
fadeOut() (double duration) Fades an element out, basically making it dissapear

Also, unless specified otherwise, duration is in seconds.

These methods can be called on AnimationBuilder or Drawable, and queue animations one after another.

Circle c = new Circle(100, 100, 50);

c.moveTo(0, 0, 3);                  // move to (0, 0) over 3 seconds
c.colorTo(new Color(255, 0, 0), 1)  // make the circle red over one second
c.fadeOut(5.3);                     // fade out the circle over 5.3 seconds
c.fadeIn(1);                        // fade in the circle over 1 second

badge-info
Remember, even though duration is a double, integers will auto-convert into doubles so you can use them instead. So .wait(3) and .wait(3.23) are both valid.

Advanced Animation

Now that system is all well and good but it does not allow you to run multiple animations at the same time. To do this you need to learn how animation scheduling works!

To start assigning animations to a shape, you first need to call .animate() on it.

Circle circle = new Circle(100, 100, 40);   // create a new circle
circle.animate()                            // animate the circle
      .add(Animation.ColorTo(255, 0, 0), 3) // add an animation to make it red over 3 seconds
      .with(Animation.moveTo(100, 200), 3); // while the circle is turning red, also move it to (100, 200)
                                            //     over the next 3 seconds.

You may notice another static method being called to define the animation. These are defined in the Animation class, and simply return the corrosponding animation. They are the same as the ones defined in Animatable, but do not include a duration parameter.

Notice the add() method being called. There are multiple methods available that you can use to schedule animations, defined in the AnimationBuilder class.

Method Parameters Description
add() (Animation, double duration) Waits until all previously scheduled animations have wrapped up, then schedules Animation for duration seconds after previous animations have wrapped up
with() (Animation, double duration) Schedules the next animation alongside the previous animation
schedule() (double time, Animation, double duration) Schedules the animation at some point in the future, with() and add() are unaffected
wait() (double delay) Schedules the next animations delay seconds after it normally would

badge-info
add, with, schedule, and wait all take an optional extra parameter, which sets the time unit. By default it's seconds, but it can also be set to TimeUnit.Frames

Circle circle = new Circle(100, 100, 40);
Square square = new Square(0, 0, 50);

circle.animate()
      .add(Animation.colorTo(Color.RED), 3, TimeUnit.Seconds);

square.animate()
      // by default, we run at 30 fps
      .with(Animation.moveTo(100, 100), 90, TimeUnit.Frames)
       

badge-warning
Please remember that these methods schedule animations, and don't actually wait for the animation to finish. If you want to run some code after all your scheduled animations finish, remember to use .sleep()

Canvas canvas = new Canvas();

Circle circle = new Circle(100, 100, 40);
circle.moveBy(0, 100, 3);

System.out.println("I will run before the animation finishes");

circle.moveBy(100, 0, 3);
canvas.sleep();

System.out.println("I will run after the animation finishes");

Graphical Explanation

Now that probably wasn't very easy to understand, but hopefully this explanation will help:

Square square = new Square(0, 0, 40);

Imagine a timeline: +1 is 1 second into the future, +2 is 2 seconds into the future etc.

Square square = new Square(0, 0, 40);

square.animate()
    .add(Animation.moveTo(100, 0), 4);

Notice the green and blue markers, PREV and NEXT. NEXT points to the end of the last animation, and PREV points to the start of the last animation.

add() adds the animation after the NEXT marker (previously on Now), and then the markers adjust for the next animation.

Square square = new Square(0, 0, 40);

square.animate()
    .add(Animation.moveTo(100, 0), 4)
    .add(Animation.colorTo(Color.RED), 4);

Now it should be obvious how you can keep chaining together add()'s into infinity and have all the animations play one after another, but just this does not allow you to run two animations in parallel. For that you need with().

Square square = new Square(0, 0, 40);

square.animate()
    .add(Animation.moveTo(100, 0), 4)
    .with(Animation.colorTo(Color.RED), 5);

As you can see, instead of adding the next animation after the NEXT marker, it adds it after the PREV marker. This makes it so both animations play at the same time.

Also note that the NEXT marker moved to accomodate the duration of with().

Square square = new Square(0, 0, 40);

square.animate()
    .add(Animation.moveTo(100, 0), 4)
    .with(Animation.colorTo(Color.RED), 5)
    .wait(1);

Now here, the wait() method is at play. As you can see, wait() simply pushes back the next animation(s) duration seconds.

Square square = new Square(0, 0, 40);

square.animate()
    .add(Animation.moveTo(100, 0), 4)
    .with(Animation.colorTo(Color.RED), 5)
    .wait(1)
    .with(Animation.rotateTo(360), 3);

Now if you have followed along so far this should make sense. Notice how wait() does not cause the NEXT marker to go backwards; wait() and add() can only cause the markers to go forwards.

Square square = new Square(0, 0, 40);

square.animate()
    .add(Animation.moveTo(100, 0), 4)
    .with(Animation.colorTo(Color.RED), 5)
    .wait(1)
    .with(Animation.rotateTo(360), 3)
    .add(Animation.colorTo(Color.BLUE), 4);

Again, if you have followed along so far this should make sense. Now this is getting a bit complicated is there a more flexible way to assign animations? Yes there is! If you remember schedule(), let's try and rewrite it all with that instead.

Square square = new Square(0, 0, 40);

square.animate()
    .schedule(0, Animation.moveTo(100, 0), 4)
    .schedule(0, Animation.colorTo(Color.RED), 5)
    .schedule(1, Animation.rotateTo(360), 3)
    .schedule(6, Animation.colorTo(Color.BLUE), 4);

badge-warning
Remember: schedule() does NOT move the PREV and NEXT markers, so it doesn't affect the outcome of wait() or add().

And that's basically all there is to know about animations!

Clone this wiki locally