# What would be the best way to implement a multi-directional “board game” movement system?

I'm pretty new to game dev, and can't figure out how to do this, even though it is probably really easy. If you need more reference, look up some gameplay of the Wii game Dokapon Kingdom, that's the kind of system I'm trying to create. I also made a picture to help you better understand my dilemma. Thank you all so much in advance!

• This is quite similar to how the Unity UI widget navigation system works, so you might want to look to it for inspiration. – DMGregory May 4 at 13:45

## The MapNode class

I would represent each node on the map with an own gameObject which gets a MonoBehaviour I would name MapNode. That class would have four variables representing its neighbors:

public MapNode upNeighbor;
public MapNode rightNeighbor;
public MapNode downNeighbor;
public MapNode leftNeighbor;


Another option might be to make those a public MapNode[] neighbors, as this allows any number of neighbors in any direction. So when you want to add diagonal or 3d connections, you could do that. But as long as all connections are in cardinal directions, that might just overcomplicate this.

For a first proof-of-concept I would populate those neighbors manually in the inspector. But in the long run I might write some code to set up those connections automatically, either at runtime or at design time through a bunch of handy editor script.

This turns the whole network of map nodes into a graph. This is a prerequisite for a lot of neat things. Like route finding, for example. But what matters now it that it tells you what move options a game piece has when they are on a given tile.

## The GamePiece class

The GamePiece would be a MonoBehavior for any game object which moves from MapNode to MapNode. The player might be one of such objects, but there might be a lot more in your game which exhibit this behavior. So I would not call it "Player".

This class has the purpose to move the gameObject towards the tile it is supposed to be. In order to do that, it needs 3 properties:

• The moveSpeed with which it moves between nodes (could be made a static if you want it to be the same for everything)
• The currentNode where it is supposed to be (keep in mind that it might not be there yet)
• Whether or not it IsMoving to the node its supposed to be (as opposed to being already there).

The Update-method then would have two jobs:

• Move the object a bit closer to its currentNode, taking moveSpeed and deltaTime into account. The new position can be calculated with the handy utility method Vector3.MoveTowards.
• Determine if it reached the destination and change isMoving accordingly.

This class could look like this:

public class GamePiece : MonoBehaviour {
public float moveSpeed = 10.0f; // units per second
public bool isMoving{ get; private set; }
public MapNode currentNode;

private void Update() {
transform.position = Vector3.MoveTowards(transform.position, currentNode.transform.position, moveSpeed * Time.deltaTime);
isMoving = transform.position != currentNode.transform.position;
}
}


To make the character move to a different node, just set currentNode to the node you want it to move to. Check isMoving to determine if its moving or stationary.

This example uses the classic AWSD control scheme. This is not a very good solution. In a real game, you would want those keys to be rebindable, support different input devices, etc.. If you want to do it properly from the start, then you might want to look at the new input system. But how to do proper input handling in Unity goes beyond the scope of this answer. So here is a script which is sufficient as a proof of concept. I am doing this as a separate script PlayerInput, because not every GamePiece would be player-controlled:

public class PlayerInput : MonoBehaviour {
private GamePiece myGamePiece;

private void Start() {
myGamePiece = GetComponent<GamePiece>();
}

private void Update() {
if (!myGamePiece.isMoving && myGamePiece.currentNode != null) {
if (Input.GetKeyDown(KeyCode.W))  {
MoveToNode(myGamePiece.currentNode.upNeighbor);
}
if (Input.GetKeyDown(KeyCode.A))  {
MoveToNode(myGamePiece.currentNode.leftNeighbor);
}
if (Input.GetKeyDown(KeyCode.S))  {
MoveToNode(myGamePiece.currentNode.downNeighbor);
}
if (Input.GetKeyDown(KeyCode.D))  {
MoveToNode(myGamePiece.currentNode.rightNeighbor);
}
}
}

private void MoveToNode(MapNode node) {
if (node != null) {
myGamePiece.currentNode = node;
}
}
}