Contents
Player movement is one of the defining elements of any game experience. It is one of the first things players will notice, and if handled poorly it will drive players away in spite of how rich the game may be in other aspects.
This article describes several methods to enhance and control player movement.
Controlling Movement Speed
Controlling the speed that players move is a great concern. Without any control, players will zip around the map so quickly that players with slower connections may not even notice them passing. A poor movement control scheme will result in jerky movement and a bad playing experience.Movement Timer
One of the simplest ways to control player movement is with a movement timer. Each time the player tries to move, the program tests the timer to see if enough time has passed since the player last moved.
mob |
Most people want to override mob/Move() to slow the player as in the example above. If something external happens to move the player (like stepping on a teleporter) before the timer expires, that movement will be blocked as well. I prefer to override client/Move(), so that movement is only delayed if the player tries to move with the arrow keys. If some other force moves the player, it will move them without regard to whether the player moved herself recently. On the downside, the designer must be careful to limit non-player mobs within the AI code.
It only requires a couple minor modifications to change the above mob style movement timer code for client style speed control.
mob |
Movement Accumulator
Another method of controlling movement speed is to test an accumulator within some sort of life cycle proc. A life cycle proc loops periodically throughout the lifespan of a mob. Deadron's Event Loop library is an excellent example of a life cycle proc. This article will use simpler mob-specific life cycles for demonstration.Each time through the life cycle, the accumulator is increased. When the accumulator exceeds a predefined amount, the accumulator drops by that amount and the player is allowed to move.
var |
The accumulator provides finer control over movement speed than a timer does. Timers are limited to even tick rates, meaning that if you speed up a mob by just one level, they move a full tick faster. With an accumulator, a slightly faster mob gets an advantage over time. By using a larger ACTION_RATE, the programmer may create more degrees of control.
| Example: Mob 1 has a speed of 10 and Mob 2 has a speed of 11. The ACTION_RATE is 20. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Enhancing Movement
The rest of this article covers some enhanced styles of movement for BYOND games.Animation Timer
One thing that annoys many BYOND players is the way movement animations only flash a frame or two before the next step if the mob is moving too fast to play the entire movement animation. The animation timer works just like a movement timer, but it operates independently of the movement timer. A player may run as fast as she wants, but the animation will not repeat frames unless the previous animation is complete.You can see an example of an animation timer in the Halloween Edition of Tanks. Join the green team and watch how the blob always flows properly, no matter how fast you move.
To use animation timers, forget about the built-in movement states altogether. They are handy for beginner projects, but this method bypasses it completely. The following code requires that mobs have an icon state called "walk" for the animation of the moving mob.
mob |
Pausing To Turn
The default movement routines move your mob immediately in the direction of the arrow key you press. Press down, your mob turns south and takes a step. Press left, your mob turns west and takes a step. Sometimes it would be nice to face a direction without automatically taking a step.For example, your mob is facing south. Pressing the down arrow moves the mob south as normal. If you press the left arrow, the mob faces west but does not move. The next time you press the left arrow, the mob moves west. SpaceTug has a mode to enable this style of movement.
It's easy to override the client directional proc so that when you press a direction your mob is not facing, it turns the mob that direction without moving.
client |
It is my motto that if you find yourself retyping the same thing over and over again with minor changes, there is a shorter way to do it. In this case, you could override client.Move().
client/Move(Loc) // player is trying to move to Loc |
Rotational Movement
Rotational movement is a slightly more complex movement style that allows the player to rotate her mob by pressing the left and right arrow keys and step forward or backward by pressing the up and down arrows respectively. Tanks provides a good example of rotational movement.
client |
Strafing
Now you know how to rotate and step forward and backward. Why not step sideways? Sideways movement in video games is also called strafing. Nano Wars provides an example of strafing movement.This snippet will make the mob step left or right by pressing the south (down) diagonals. Just replace the Southeast() and Southwest() procs in the Rotational Movement snippet with these:
Southeast() |
You can even make the North diagonals turn and step forward in a single action.
Northeast() |
Acceleration (Vehicle-like Movement)
Vehicle style movement is a little more complex. It should be a rotational system that allows the up and down arrows to modify the vehicle's speed.This snippet uses an action cycle (movement accumulator) to provide these controls:
| Numeric Keypad | |||
|---|---|---|---|
| 7 Home forward & turn left |
8 Up Arrow forward |
9 Pg Up forward & turn right |
What do all these mean? forward - accelerate in the direction the vehicle is facing. reverse - accelerate away from the direction the vehicle is facing. brake - decelerate to 0 velocity |
| 4 Left Arrow turn left |
5 brake |
6 Right Arrow turn right |
|
| 1 End reverse & turn left |
2 Down Arrow reverse |
3 Pg Dn reverse & turn right |
|
Here is a snippet that makes it possible.
var |
Combining Movement Styles in One Program
Some games have a variety of movement styles the programmer will want to include. Perhaps you want vehicles to work one way while pedestrians move differently, or you just want to allow players to choose their preference from a variety of styles. The key to sorting out multiple movement styles is in the client directional procs.Here is an example snippet from Darke Dungeon, which allows players to select their preference from quick movement (traditional BYOND movement), directional movement (as in Pausing to Turn above), and rotational movement (with strafing.) Darke Dungeon uses a variation the movement accumulator method outlined above. The lifecycle() and constant declarations are not important to understand the theory presented here.
client |