Grid based movement in Unity game deployed on iPhone

 by • Reading Time: 6 minutes

Introduction

I this tutorial we are going to look at implementing a grid based movement in an iPhone game. I’ll use the materials from previous articles to make the movement of our character more responsive and robust. This classic kind of movement can be found in many examples of older generation of games. It is a perfect movement mechanism candidate for a game world comprising of tiles.

Table of contents:

  1. The idea behind the grid based worlds
  2. Preparing our character prefab
  3. Let’s put it all together – movement code

1. The idea behind the grid based worlds

The grid system was present in games for a long time. It is relatively easy to build levels comprising of tiles. This is mostly due to the fact that we are working with tiles of a precise size. Their placement in a grid is well defined and puts a certain level of limitations we have to work with. This is especially true when it comes to structuring the game mechanics around them.

The concept of a grid based movement

One of the most common features of games is that we can explore virtual worlds by moving our characters within them. However, in a grid based levels it is often required that our character moves exactly one cell at a time. For instance, we can ensure the integrity of the strategy game by not allowing our units to go beyond certain number of cells per turn. A prime example of this kind of movement can be observed in a well known Shining Force franchise released in the 90s.

Shining Force 2 grid based movement

Let’s see how we can implement a similar movement in a Unity game!

2. Preparing our character prefab for grid based movement

First we have to equip our character with something that will be able to detect what lies in the direction we want to move him towards. This will enable us to programmatically make a decision whether it is even allowed to move the character into the next cell. In other words, we are going to use a built-in physics engine to detect collisions between the direction point and the solid tiles. Start by creating an ‘Empty’ object and parenting it to the player game object prefab. It will be used as the beacon for detecting what is in front of the character in the direction we want to move him towards to. After that define a new layer and assign a tilemap which contains tiles that are deemed ‘unwalkable’. It is most likely a tilemap containing a ‘Tilemap Collider 2D‘.

Adding unwalkable layer

I’m going to use these two constructs to detect collisions in order to determine if the player can move a character to next cell. I will reuse the ‘PlayerMovement’ script that was written during my very first tutorial on the subject. First I’ll start by adding a reference to the ‘move point’ and the layer I have defined earlier.

public Transform movePoint;
public LayerMask stopMovementMask;

After that, in the ‘Start()’ function I’ll ‘unparent’ the move point so that is not relative to local coordinate position of the player prefab. This is important because we want to calculate its position relative to the player in the global coordinate space.

void Start()
{
    movePoint.parent = null;
}

We are now ready to bind it all together so lets rewrite the code in the ‘Update()’ function next!

3. Let’s put it all together – the grid based movement code

If you have followed my tutorial on deploying a Unity game to iPhone then in the ‘Player Movement’ script you already have a ‘SetMovementVector()’ and ‘NotifyMovementAnimator()’ functions. The former registers an input from the player while the other passes that information to the Animator to trigger walking animations. I’ll use those functions in order to get the movement vector that is necessary to determine the position of a movePoint. By tightly coupling the position of the player and move point I’ll be able to check if the character can be move to the next cell. That in turn shall be dictated whether the tile is on the ‘Unwalkable’ layer. Let’s start by assigning those to their corresponding fields in the engine.

The core of the grid based movement

In the ‘Update()’ function I will begin by getting input from the player and fire correct walking animations. After that, I’ll make my character to gradually walk towards the move point by a fixed time step. The built-in MoveTowards member function of Vector3 will be used for this purpose.

void Update()
{
   SetMovementVector();
   NotifyMovementAnimator();
   transform.position = Vector3.MoveTowards(transform.position, 
                    movePoint.position, 
                    moveSpeed * Time.fixedDeltaTime);

So far so good, but we need to still run few checks before we move towards our direction designated by move point. First let’s if check if the position of a move point and our character are close to each other. By doing so we will know if the character is ready to make the move to the next cell.

if (Vector3.Distance(transform.position, movePoint.position) <= .001f)
{
}
            

After that, I’ll test if the player has pressed either the horizontal or vertical directional buttons. To make the code a little bit more efficient, I’ll simply check the absolute value of the movement vector components.

if (Vector3.Distance(transform.position, movePoint.position) <= .001f)
{
   if (Mathf.Abs(movement.x) == 1f)
   {
   } 
   else if (Mathf.Abs(movement.y) == 1f)
   {
   }
}

Determining what tiles lie ahead of the character

Subsequently, I will check if the tile that is in the front of the character in the direction the user pressed is ‘unwalkable’. I’ll use the the OverlapCircle member function of built-in Physics2D for this purpose.

if (!Physics2D.OverlapCircle(movePoint.position + new Vector3(movement.x, 0.5f, 0f), .2f, stopMovementMask))
{
    movePoint.position += new Vector3(movement.x, 0f, 0f);
}

The above example is for a case scenario in which user presses one of the horizontal directional buttons.

  • Firstly, I’m positioning the ‘move point’ in the direction the user pressed. If your player pivot point is in the bottom center part of the sprite then you have to add 0.5f on the vertical axis. By doing so you’ll ensure that the bounding box of the move point will not collide with the adjacent cells.
  • Secondly, I’ll make the radius of the collider circle to be .2f and ensure that it will pick up only the tiles residing on the ‘unwalkable’ layer.
  • Thirdly, I’ll move the move point to the new position in case no unwalkable tile has been detected.

Create the analogous checks for the vertical movement. The final Update() function should now look like this.

void Update()
{
    SetMovementVector();
    NotifyMovementAnimator();
    
    transform.position = Vector3.MoveTowards(transform.position, movePoint.position, moveSpeed * Time.fixedDeltaTime);

    if (Vector3.Distance(transform.position, movePoint.position) <= .001f)
    {
        if (Mathf.Abs(movement.x) == 1f)
        {
            // we add 0.5f to 'y' component of the 'position'
            // to account the bottom pivot point of the sprite
            if (!Physics2D.OverlapCircle(movePoint.position + new Vector3(movement.x, 0.5f, 0f), .2f, stopMovementMask))
            {
                movePoint.position += new Vector3(movement.x, 0f, 0f);
            }
        } 
        else if (Mathf.Abs(movement.y) == 1f)
        {
            // we add 0.5f to 'y' component of the 'position'
            // to account the bottom pivot point of the sprite
            if (!Physics2D.OverlapCircle(movePoint.position + new Vector3(0, movement.y + 0.5f, 0f), .2f, stopMovementMask))
            {
                movePoint.position += new Vector3(0f, movement.y, 0f); 
            }
        }
    }

}

Congratulations! You have now implemented a grid based movement system! The end result should look something like this:

The grid based movement in an iPhone game

Conclusion

In this tutorial we have looked into the implementation of a grid based movement. This type of a system can be observed in classic games from the old school 90s era. I’ve used a range of Unity concepts and built-in functions to create a similar mechanism to move our character in a tilemap based world. Above all, I’ve used the Vector and Physics2d member functions to determine the movement of our character inside of our level. In conclusion, it is fairly simple to implement grid based movement in Unity game engine. In addition I have encapsulated the entire functionality in a single script.

References

Grid based movement in Unity by gamesplusjames