Let’s Make Honey!
We finally get to finish version 0.15 by making sprites.
I tried to avoid this for a long time, I think because I’m still afraid of allocating and deleting in C++. Now I think I was crazy to wait so long. Sprites are so damned convenient.
The concept here is simple. We make a class which abstracts a 2d object drawn to the screen. It draws a particular picture (a graphics label in our system). It has all the things our 2d graphics system is currently aware of: position, color, rotation, scale, and opacity. It has methods to get and set each of these, and what’s more, it has methods to set each of these with a transition animation, by using an effect under the hood.
When using Honey, instead of calculating all of these things in the draw method for each picture we want to draw, we now create a Sprite, set the parameters wherever we want, and in the draw method, we just call sprite.draw().
I feel really dumb for not introducing this earlier, because it is a core element of all 2d graphics systems since the Logo Turtle.
Anyway, here is the diff for sprite.cpp.
In lines 13 through 20, we have a constructor which takes a label (assumed to be defined in graphics), position, color, opacity, rotation, and scale.
In lines 22 through 116, we have ordinary getters and setters, all simple, as well as animated set methods. The animated set methods take an animation duration, and each define a tween effect which starts at the old value, ends at the new value, and lasts for the specified duration. For now, these are all going to use the tween style that I think is best for that type.
Color requires three tweens, one each for R, G, and B. We could have had one tween from 0 to 1, but we would have had to store both colors, which is less good if someone calls the animation method twice quickly. More on that in a minute.
Opacity gets one additional convenience method to fade the sprite in and out. We use a sinewave tween from 0 to 1 to do this. Position also gets an additional method to shake the position.
We have two draw methods, one that just uses the default position, and (for drawing the same object multiple times) one which takes a new position value.
Lines 118 to 120 is the method that uses the default position. It just calls the other method with the default position.
Lines 122 to 165 are the proper draw method.
We take each thing, position, color, opacity, rotation, and scale, start with the stored value, adding the tweens if they’re busy, using my chosen blending style. I chose sigmoid for position, color and scale, linear for opacity and rotation, and sinewave for the in-and-out opacity fade.
Note that the tweens actually update the values as they go, so if someone creates a second animation to override the first one, it won’t reset to the oldest position, but instead start from the current location.
We call graphics to set the color, and finally we call graphics to draw the image with all the other values.
Done! That was not hard.
Well, sort of. In a subsequent hot fix, I gave each sprite a unique id and used it to make tween labels unique for each sprite. This was necessary because multiple sprites were interfering with each other’s animations. The hot fix also made Textbox a subclass of Sprite, which was natural.