Single Mode

The default mode of GLC is “bounce”. This causes the animated properties of your objects to go from their starting values to their ending values, and then back again. All nice and smooth. Pretty hard to create a non-smoothly-looping animation with that default setup.

But once you switch over to “single” mode, things become more difficult. Most simple animations will look horrible because they’ll animate from one state to another, and then jump back to the initial state. Very jarring. But there are some tricks to making decent single mode animations, and once you get it, I’d say these animations are even superior to ones created in bounce mode.

The biggest single point to understand, is that for each object in the render list, what’s on screen at the start of the animation point has to match what’s on screen in that same location at the end of the animation.

Now at first glance, that seems impossible. You’re changing something from state A to state B. How could it be at state A when it ends at state B? Well, one example would just be to rotate something 360 degrees. Like this:

list.addRect({
    x: 100,
    y: 100,
    w: 100,
    h: 100,
    rotation: [0, 360]
});

single01

Since 360 degrees is the same as 0 degrees, we’re in the same state, and we have a smoothly running single mode animation.

Actually, because we have a square there, we can even rotate it to any multiple of 90 degrees and still have it wind up in the same visible state it starts at. It won’t technically BE in the same state, because 90 isn’t 0, but what you see on screen in that location will be the same.

list.addRect({
    x: 100,
    y: 100,
    w: 100,
    h: 100,
    rotation: [0, 90]
});

single02

But there are other tricks. Consider this: if an object starts in some state where you can’t see it, and ends in some other state where you can’t see it, that’s the same too. So we could have it start and end off screen.

list.addRect({
    x: [-50, 250],
    y: 100,
    w: 100,
    h: 100
});

single03

But off screen isn’t the only way something can be invisible. We could set the alpha down to zero or change the alpha channel of the color down to zero, or simply have the color change to match the background. In all of these cases, you won’t be able to see the object.

list.addRect({
    x: [-50, 100],
    y: 100,
    w: 100,
    h: 100,
    globalAlpha: [1, 0]
});

single04

In this last example, the square starts off invisible, because it’s off screen to the left. It ends invisible because its alpha is 0. So it’s all nice and smooth. You could reverse this and have it start off with zero alpha, and fade in as it moves off screen.

Or, you could reduce the size of the object to zero.

list.addRect({
    x: [-50, 100],
    y: 100,
    w: [100, 0],
    h: [100, 0],
});

single05

How about hiding it by moving it behind something?

list.addRect({
    x: [-50, 100],
    y: 100,
    w: 50,
    h: 50
});
list.addRect({
    x: 100,
    y: 100,
    w: 75,
    h: 200
});

single06

Here, there’s another rect in the middle of the screen. The first rect is hiding behind it so you don’t notice it snapping out of existence and returning to the starting point.

This last one is key because it gives us the starting point to the most powerful method of single mode animations – multiple objects. In this example, we have one object start where the other one ends.

list.addRect({
    x: [-50, 100],
    y: 100,
    w: 50,
    h: 50
});
list.addRect({
    x: [100, 250],
    y: 100,
    w: 50,
    h: 50
});

single07

Here we have the first square starting off screen to the left and moving to a position of 100, 100. And we have another square starting at 100, 100 and moving off screen to the right. At the end of the animation the first square winks out of existence and jumps back to its starting position on the left. At the same instant, the second square jumps back into the middle of the screen. But because these two things match up, you never see the change.

Now because we have easing on, it does stop there briefly in the middle of the screen. But that’s only due to the easing. If we turn off easing, we have a nice smooth transition.

single08

Realize that it doesn’t matter what the first square does or looks like before it reaches its end point. And it doesn’t matter what that second square changes into or where it goes after that initial state. As long as A’s end matches B’s start, we’re golden.

list.addRect({
    x: [-50, 100],
    y: 100,
    w: [20, 50],
    h: [200, 50],
    fillStyle: ["red", "black"]
});
list.addRect({
    x: [100, 250],
    y: [100, -50],
    w: 50,
    h: 50,
    fillStyle: ["black", "green"],
    rotation: [0, 360]
});

single09

Here, the first square starts out as a red rectangle. The second one turns green as it spins out through the top right corner. But at that transition point, they are the same, so it’s smooth.

Just like juggling, once you get two objects down, you can move to three.

list.addRect({
    x: [-50, 100],
    y: 100,
    w: [20, 50],
    h: [200, 50],
    fillStyle: ["red", "black"]
});
list.addRect({
    x: [100, 250],
    y: [100, 50],
    w: 50,
    h: 50,
    fillStyle: ["black", "green"],
    rotation: [0, 360]
});
list.addRect({
    x: 250,
    y: [50, 150],
    w: [50, 0],
    h: [50, 0],
    fillStyle: "green",
    globalAlpha: [1, 0]
});

single10

Here the second rectangle doesn’t go off screen, but it joins a third one that moves down as it shrinks and fades away.

Now we have two merge points where one object is swapping over with another. And we can chain as many as we want this way. But the first and last objects need to start and end invisible. Unless… they merge with each other.

list.addRect({
    x: [50, 150],
    y: 50,
    w: 50,
    h: 50,
});
list.addRect({
    x: 150,
    y: [50, 150],
    w: 50,
    h: 50,
});
list.addRect({
    x: [150, 50],
    y: 150,
    w: 50,
    h: 50,
});
list.addRect({
    x: 50,
    y: [150, 50],
    w: 50,
    h: 50,
});

single11

Here we have four squares. The first one moves left to right, where it joins with the second one, which moves down. This meets with the third, which moves back to the left, meeting the fourth that moves up. The fourth square ends where the first starts, so everything joins together.

And we can do whatever we want with any of these shapes as long as the end of one matches the start of the next one, all the way around.

list.addRect({
    x: [50, 150],
    y: 50,
    w: 50,
    h: 50,
    fillStyle: ["red", "blue"]
});
list.addRect({
    x: 150,
    y: [50, 150],
    w: 50,
    h: 50,
    fillStyle: ["blue", "green"],
    rotation: [0, 45]
});
list.addRect({
    x: [150, 50],
    y: 150,
    w: [50, 25],
    h: [50, 75],
    fillStyle: ["green", "orange"],
    rotation: [45, 360]
});
list.addRect({
    x: 50,
    y: [150, 50],
    w: [25, 50],
    h: [75, 50],
    fillStyle: ["orange", "red"]
});

single12

So, it takes a bit more work, thinking and planning than bounce mode, but the results are well worth it.

Leave a Reply