RTS and MOBA Player Controller for Unity

In video games, the term RTS stands for Real-time strategy.

The difference between RTS and conventional First / Third Person shooter games is that the characters are controlled using the mouse pointer rather than the usual W, A, S, and D buttons.

The player is given an eagle-eye view of the battlefield with the ability to give orders to the troops, without directly controlling them. Examples of RTS games are Warcraft, Starcraft, Cossacks, etc.

Warcraft 3 gameplay screenshot

On the other hand, MOBA stands for Multiplayer Online Battle Arena, it's a somewhat newer subgenre of RTS games where the player controls just one character instead of many.

Examples of such games are League of Legends and Dota 2.

In this tutorial, I will be showing how to create an RTS/MOBA-style controller in Unity.

Step 1: Let's create the necessary script(s)

This tutorial is quite simple, as it only requires one script.

RTSPlayerController.cs

//You are free to use this script in Free or Commercial projects
//sharpcoderblog.com @2018

using UnityEngine;
using UnityEngine.AI;

[RequireComponent(typeof(NavMeshAgent))]

public class RTSPlayerController : MonoBehaviour
{
    public Camera playerCamera;
    public Vector3 cameraOffset;
    public GameObject targetIndicatorPrefab;
    NavMeshAgent agent;
    GameObject targetObject;

    // Use this for initialization
    void Start()
    {
        agent = GetComponent<NavMeshAgent>();
        //Instantiate click target prefab
        if (targetIndicatorPrefab)
        {
            targetObject = Instantiate(targetIndicatorPrefab, Vector3.zero, Quaternion.identity) as GameObject;
            targetObject.SetActive(false);
        }
    }

    // Update is called once per frame
    void Update()
    {
#if (UNITY_ANDROID || UNITY_IOS || UNITY_WP8 || UNITY_WP8_1) && !UNITY_EDITOR
            //Handle mobile touch input
            for (var i = 0; i < Input.touchCount; ++i)
            {
                Touch touch = Input.GetTouch(i);

                if (touch.phase == TouchPhase.Began)
                {
                    MoveToTarget(touch.position);
                }
            }
#else
        //Handle mouse input
        if (Input.GetKeyDown(KeyCode.Mouse0))
        {
            MoveToTarget(Input.mousePosition);
        }
#endif

        //Camera follow
        playerCamera.transform.position = Vector3.Lerp(playerCamera.transform.position, transform.position + cameraOffset, Time.deltaTime * 7.4f);
        playerCamera.transform.LookAt(transform);
    }

    void MoveToTarget(Vector2 posOnScreen)
    {
        //print("Move To: " + new Vector2(posOnScreen.x, Screen.height - posOnScreen.y));

        Ray screenRay = playerCamera.ScreenPointToRay(posOnScreen);

        RaycastHit hit;
        if (Physics.Raycast(screenRay, out hit, 75))
        {
            agent.destination = hit.point;

            //Show marker where we clicked
            if (targetObject)
            {
                targetObject.transform.position = agent.destination;
                targetObject.SetActive(true);
            }
        }
    }
}

Step 2

Now let's set up a player controller and game level.

  • Create a new GameObject and call it 'RTSPlayer'
  • Attach the RTSPlayerController.cs script to it (NOTE: Upon attaching, it will automatically add another component called NavMeshAgent, this component will be needed later)

  • Add a player body (in my case I will be using a simple capsule with a cube, but you can add a player model if you have any). Scale it down until the desired size.
  • Move the player model inside the 'RTSPlayer' GameObject (NOTE: Before parenting, make sure 'RTSPlayer' is placed at the bottom of the player model)

  • Select 'RTSPlayer' and in NavMeshAgent tweak the Radius and Height until it matches the player model

  • Next is to create a Target Indicator prefab. This is just a simple GameObject with a Quad that will indicate where we have clicked on the map.

You can use the texture below:

real-time strategy target indicator

  • And lastly, select 'RTSPlayer' and assign all the necessary variables in the RTSPlayerController script:

Player Camera - is self-explanatory, this can be any camera

Camera Offset - how far the camera should be from the player

Target Indicator Prefab - the prefab we just created

While in Play mode, you'll notice that clicking on the map does not make the player move. That's because we have one last thing to do, which is Bake a Navigation Mesh (Navmesh):

  • Select all the objects that are part of the map and mark them static:

  • Go to Window -> AI -> Navigation

  • Under the Bake tab change the values of Agent Radius and Agent Height (those should match the values from NavMeshAgent), then click Bake.

  • After Baking is finished you'll notice a bluish outlined mesh, which represents the walkable area.

NOTE: To prevent the player from walking over the hills, go back to the Bake tab and decrease the Max Slope angle then rebake the navmesh.

Much better!

Finally, go back to Play mode and left-click somewhere on the map.

The player should now move towards the target while avoiding the obstacles:

Sharp Coder Video Player

Tip: Tweak Speed, Angular Speed, and Acceleration value at NavMeshagent to fit your needs.

Suggested Articles
Player 3D and 2D Wall Jump Tutorial for Unity
Top-Down Player Controller Tutorial for Unity
Rigidbody-based Planetary Player Controller for Unity
Airplane Controller for Unity
Adding Crouching to FPS Player in Unity
Dialogue System for Unity
Flashlight Tutorial for Unity