Dev Blog - Movement in RuneScape
Hello! I'm Mod Nin. If you tuned into the Runescape keynote at Runefest in October, you would have seen a few technical prototypes of various game features. For one of them, called 'Smoother Movement', we showed a video of a character running through the Tree Gnome Village maze, turning around corners as smooth as butter. That feature is almost ready for you all to play with! And, if you're curious, I'd like to explain a bit about how we've made this seemingly simple change.
To understand, we first need to go over how movement in Runescape works. This means knowing a little bit about how Runescape functions in general.
When you play Runescape, you interact with the game client - that's the program you've downloaded to your device. This client connects to a game server, which is run by us at Jagex. The distinction between these is:
The important point here is that the movement of any player or NPC character in Runescape is controlled by the game server. Every 600 milliseconds (a game tick) the server updates your character's position and sends it to your game client. This is aligned to a grid.
But if that is all you saw, then your character would be moving very strangely...
To make this look more natural, the client interpolates between the character's last position and their new one, and makes them do a nice animation. Whenever the client receives a new position, we add it to that character's 'pending route', and animate them through it at a fixed speed, depending on whether they are walking, running, or crawling. If your character ends up too far behind its new position, its speed is increased by a fixed amount until it's caught up.
Step it up!
This is how movement has been in Runescape since at least the launch of Runescape 2 back in 2004. It's done a fine job of representing how player and NPC characters move, but there's definitely room for improvement. We're not aiming for a huge fundamental change to the movement here (sorry, the grid-based movement has to stay for now!) but here's the two big areas we can improve upon:
Rather than moving the character at a fixed speed, we will now give them an acceleration in addition to speed. When they start moving, we transition their speed from 0 to full-speed over the course of around 200 milliseconds. Then, when the server tells us that there's no more movement, we can decelerate back to 0. This will also apply when changing speed during movement. If your character runs out of energy and starts walking, they will slow down a bit more gently.
We've also been able to add a smarter 'catch-up' system. As I said earlier, your character would suddenly speed up if they ended up too far behind their actual position. With our new method of handling speed, we can make this a bit more seamless by subtly adjusting the character's speed based on how far behind they are. The longer the route, the faster the character moves - and when their speed changes, it does so gently. As well as making catch-up more seamless, this very slightly improves how responsive your movement inputs are; the closer we keep your character to the end of their pending route, the faster you will see them reach their most recent position. This will be happening all the time and, if I've done my job right, you should never even notice!
Turning is where things get interesting! It would be really nice if, instead of following our route in straight lines, we could follow it using curves as well. A simple and effective curve we can use is a Bézier curve (pronounced "beh-zee-ay"). Without getting into too much detail, a Bézier curve is a parametric curve created by interpolating between a number of points. In our case we will have three points per curve, so our curve will be a quadratic Bézier curve.
However, it's not enough to just take our existing points and turn them into curves. We'd end up with a bit of a mess, where our curves wouldn't line up properly depending on where we began our movement, and some turns would be more tight than others. Your character might also end up cutting corners and phasing through walls, so we need to do a bit more to make this work.
To tidy this up we just need to add more points along the way. Whenever we receive a new position from the server, we need to create additional points at half-tile steps towards that new position. Then, we only generate curves from every other point to make sure that we always enter and exit a tile in a way that will align nicely with the next point.
Great! Now we have some nice curves to interpolate across. When we move our character, we can take our speed and use it to move along our curve, with smooth acceleration and turning! In practice it's a bit more complicated (what happens if we receive our next position a bit late and have to start a new curve from the middle of our last one? Or if we only have two points?) but that explains the general inner workings of this new movement.
That wraps up this post. I hope you enjoyed reading it. Before I joined Jagex in 2016 I really enjoyed reading through the NXT dev blogs, so I hope some of you found this interesting! I'm part of the new 'Core Experience' team on Runescape, a team dedicated to making the general game experience better wherever we can, so expect more improvements like this in the future!
Mod Nin, Game Engine Programmer