/ #mechanics 

Movement

Movement is one of the most basic mechanics used in nearly all games - it is also an essential mechanic in turn-based strategy games.

So what is movement? Fundamentally, movement means changing the position of something in the game world or level.

A critical detail to observe in that definition is that we are changing the position within a world. Without some external frame of reference, movement is meaningless. Changing the player characters coordinates without having that reflected in a change of position on the screen or as a change of scenery around the player, makes it meaningless to a player. If moving doesn’t visibly change anything, then a moving character is indistinguishable from a stationary character.

The following demo tries to illustrate this:

  1. First, try moving around with the arrows: this movement mechanic works, you can see the player moving around on the screen.
  2. Now press X to turn on camera following and try moving around again: this movement mechanic sucks! If the player (x,y) coordinates were not displayed you would have no way of telling that the player is moving.
  3. Now press C to turn on terrain and try moving around again. The addition of terrain in the background and a border around the map gives a frame of reference. The movement mechanic works again despite the camera following the player.

There are a few other subtleties I haven’t covered here like direct versus indirect control. What’s shown in the demo above is direct control - input translates directly into movement.

An example of indirect control would be a real-time strategy game: in these, the player usually clicks the mouse at the point where they want a unit to move to, and AI is then used to move the character to the designated position.

Another one is the physics-based movement mechanic, which substitutes the straightforward movement code below, for more realistic physics simulation.

Indirect control might be relevant for some turn-based strategy games, but you can safely ignore physics-based movement mechanics if you are only interested in turn-based strategy mechanics.

Code Example

This section highlights the essential bits of the code for this mechanic.

The full code for the demo above is available at https://gitlab.com/tbs-mechanics/movement. I built the demo with PICO-8, so here’s an API Reference which should clarify anything that’s not vanilla Lua.

Data

The data needed to represent movement is fairly simple. A Cartesian coordinate, so (x,y) in 2D space, or (x,y,z) in 3D space. Along with that, a speed which determines how much we are going to change the coordinates on each input.

In this example, I have one speed setting for horizontal and vertical movement, but it is often practical to have different values for each direction as most game systems use displays that are wider than they are tall.

function _init()
  entities={}

  player={}
  player.x=64
  player.y=64
  player.speed=2

  map_w=64
  map_h=64

  -- map initialisation also happens here,
  -- but that's out of scope for this demo
end

Also, note the global map_w and map_h variables for the map width and height. These variables are used in calculations to prevent the character from moving out of the bounds of the world.

Update Function

In directly controlled movement the update loop is simply responsible for taking an input and applying it to the data, scaled by speed:

function _update()
  if btn(0) then
   player.x=max(0,player.x-player.spd)
  end
  if btn(1) then
   player.x=min((map_w-1)*8,player.x+player.spd)
  end
  if btn(2) then
   player.y=max(0,player.y-player.spd)
  end
  if btn(3) then
   player.y=min((map_h-1)*8,player.y+player.spd)
  end
end

The min and max functions clip the player coordinates to the level bounds, thereby preventing the player from moving outside of the level.

Also, note the fact that I didn’t use if ... elseif - this allows the player to hold down two keys at once to move diagonally.

Render Function

function _draw()
  -- Demo code sets up the camera offset here...

  -- ... then clears the screen (differently if terrain enabled)

  -- ... then draws the map

  -- draw the player
  spr(player.spr,player.x,player.y)

  -- draws the UI text over everything else
end

You are welcome to examine the full demo code to see the subtleties of handling the camera and the map, but for a basic movement mechanic, the important thing is to draw the moving entity at its current position.

Author

Matt Van Der Westhuizen

Back-end service developer at Ubisoft Blue Byte by day - wannabe game designer & developer by night.