Riding the curve Animation via Bezier curve manipulation.
So, last time we spoke, I left you this teaser…
I mean how hard could it be? right?
OK So, hum, an easy enough exercise….. for a path-based animation like we saw last time.
But how do I draw such a path? How do I time the inflections in speed for that path, since time of occurrence is dependent on speed and not position?
Hmm, a roller-coaster seems like the ideal thing. I mean, it is a path and then the internal animation in that path depends on the path itself. In other words, the lower you are the faster you go…. right?
So let’s start drawing, beginning with a plain svg path that I draw in my old Inkscape…. that is the basis of our roller coaster.
All good, right? Next I need to move this to the 0,0 in Inkscape (not the page 0,0, but the real 0,0). Once the path is in place, copy the svg path code and insert it on the:
PathInterpolator {
id: pathInterpolator
path: Path {
PathSvg { path: "M 0,147.09358 C..........}..}
This works great! Make a car item bound to the progress property and… this is easy! But it’s not very lifelike: it’s just a car going at a constant speed across a a path.
Now the big question…. How do I make the animation believable?
I know, I will use my old friend spreadsheet and numerical math… First of all, let’s break this path into multiple segments so that I have an x,y coordinate system of sorts.
Inserting a console log that spews out the Y position with a timer did the trick for me.
OK, next we move this to a spreadsheet and say, for simplification, that the speed is Y. All good, now we have a position in path vs speed graphic, we had an initial speed factor, and a final speed, so we can play with it.. and we get this:
But what we need is a time vs speed graphic.
Now let’s calculate, at each position, its time in a cumulative fashion. We have that p=po+vt (we can say that v=(v0+v1)/2) (p=position). So because p0=p-1, we have:
p=p-1+(v0+v1)/2t<=>2/(v0+v1)=t
This produces our new x axis ….for the speed.
Next we just need to integrate the speeds over the time periods (position in the path at time) in order to create a curve shape that makes sense to easing.bezierCurve:
Then we need to move this image (orange line) back into Inkscape in order to create a path out of it.
Almost there…. OK, remember that the direction on Inkscape is y down so we have to mirror this path down. Also, QML does not take real svg paths for this but a rather normalized curve that starts on 0,0 and ends on 1,1, and all nodes contain control points on both ends. To make things even simpler, they need to be described in absolute coordinates (Inkscape likes to save as relative). After some fiddling, I found out I can force Inkscape to use absolute coordinates when saving its xml… and I managed to put the path at point 0,0 to 1,1.
Now for the final step, just create a little script that transforms the svg string into a bezier array of points and we are good to go…… almost.
Add 2 more carts connected to the same base animation, make them all randomly bounce a bit, make them rotate while in the “fake” jump for fun and we are done.
Download the rollercoaster.ods file if you for are interested.
Note: The jump phase implies that the path used for the car movements and the path used to acquire the speed are not exactly the same so a bit of testing and fiddling was needed.
Conclusion
It is not the easiest of processes to achieve such an animation, but it’s flexible enough to solve a lot of similar problems where you know the speed you want at a given position, but don’t know how to get there. It’s useful if you want to simulate a physics-driven animation but you think adding a real physics engine to do it is overkill.
# The size of the bezier curve is limited for longer curves I would suggest breaking our curve into multiple ones.
The next blog will be about abusing the particle systems for profit, and fun… But that is something for next year.
Hello Pinheiro, thank you very much. This article shows that PathInterpolator component should have a separate property for speed.
Also You can make your animation more accurate by using acceleration.
Thank you, the animation is accurate enough (I mean it did what I wanted it to do). This was mostly an exercise around reverse-engineering the easing curves.
I suspect I should revisit this exercise with the new timeline animation stuff in the Qt design studio. but that requires a new blog post.
A big yes from my side for a blog post with the new timeline animation stuff!