Game Design 2 - Movement Patterns

Implementing movement patterns for enemies.

Written the by Thomas Cairns.

Introduction

This post is part three in a five part series. For more details please read previous posts.

Previous posts:

Task

One of the problems for me to solve, in order move our project one step closer to our goal, has been to create a system for enemy movement patterns. The basic premise was that enemies will only move along a very simple pattern. For example, moving along a line between two points, moving along the edge of a triangle and so on.

Unity NavMesh

Based on recommendation from one of my team mates, who has previously done 3D work in Unity, I looked into Unity's NavMesh system. The system allows for creation of planes that can be navigated by so called agents. An agent will try to find the shortest possible path between its current position and its targeted destination within a plane. What makes the system interesting is that it allows for both static and dynamic/moving obstacles. This allows you to have multiple moving obstacles that the agent will try to avoid while travelling towards its destination.

The NavMesh sounds just like the kind of system I was looking for, a system that takes care of all pathing logic and is even more advance than anything I could create within the short amount of time we have. However, while I was learning about the system and trying to implement it into our game I stumbled upon two factors that prevented us from using the NavMesh at the current stage of the project.

Illustration of a plane with and obstacle and how the NavMesh creates a pathable area

The white rectangle in the background represents the actual game field. The red circle is an obstacle within the play field. The light blue overlay is what the NavMesh creates as a pathable plane.

Same illustration as above however viewed in 3D

Same illustration as above however viewed in 3D. The white rectangle in the background represents the actual game field. The red circle is an obstacle within the play field. The light blue overlay is what the NavMesh creates as a pathable plane.

Axis

The planes of the NavMesh are locked into using the X and Z axis, which fits very well with the default 3D viewport and setup in Unity. The problem is that the 2D viewport is instead centered around using the X and Y axis. In order to use the NavMesh and still work in 2D you would have to rotate the camera and every sprite component, which creates a different kind of pipeline. The pipeline becomes a tiny bit more complex but depending on what kind of features you want it might very well be worth it. However I would say that it's a decision that should be made in the early stages of the project. For us it felt a bit late to change the pipeline half-way through the project even though the game is still small in size.

Illustration of NavMesh plane vs 2D plane

The red rectangle show the 2D plane rotation while the blue demonstrates the NavMesh plane.

3D Meshes

In order to us the NavMesh you have to work with meshes, which the name in itself implies. I was hoping that quad meshes would be enough to work with. A quad mesh in Unity is simply four points that together create a 2D rectangle. The quad mesh work perfectly fine in order to create a navigational plane however the objects actually need volume. Which means that all our game objects would require a 3D mesh. This would also append more complexity to the pipeline. Even though the previous problem was enough to discourage us this really put the nail in the coffin.

Disclaimer

However I should however put down a disclaimer that I don't have much experience with Unity and none of the statements above are definite facts. Rather they are my understanding of how Unity works based on the short amount of time I have had to do research. Any corrections are appreciated.

Transform Path

In the end I decided to go with a very simplistic approach. I created a script that fetches the position of each child object within a specified Transform object. Based on each child a relative path is created based on the position of the object that the script is attached to. In order to create a movement pattern I then simply have to create multiple position within another element and then store the collection as a prefab.

Hexagon movement pattern visualized in Unity

Hexagon movement pattern visualized in Unity.

A square moving along the hexagon pattern

A square moving along the hexagon pattern.

Code

CS_Enemy_Movement.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CS_Enemy_Movement : MonoBehaviour
{
  public float speed = 1.0f;
  public Transform path;

  private int current = 0;
  private List<Vector3> targets = new List<Vector3>();

  void Start()
  {
    if (path != null)
    {
      for (int i = 0; i < path.childCount; i++)
      {
        targets.Add(transform.position + path.GetChild(i).position);
      }
    }
  }

  void Update()
  {
    if (targets.Count == 0) { return; }

    if (transform.position == targets[current])
    {
      current = CS_Utils.Mod(current + 1, targets.Count);
    }

    transform.position = Vector3.MoveTowards(transform.position, targets[current], Time.deltaTime * speed);
  }
}