Unity 3D RTS/MOBA Player Controller
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, 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](https://sharpcoderblog.com/public/images/e2f/e2fc3e6506047582d9ce23538da4255d.jpg)
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 3D.
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);
}
}
}
}
![](https://sharpcoderblog.com/public/images/87c/87c4dfab8bb5f58721380f72b3432cfd.png)
Step 2
Now let’s set up a player controller and game level.
- Create a new GameObject and call it ‘RTSPlayer’
- Add RTSPlayerController.cs component to it (NOTE: Upon adding, it will automatically add another component called NavMeshAgent, this component will be needed later)
![](https://sharpcoderblog.com/public/images/d33/d33f0c8dc3530c8f5932d89b69615631.png)
- Now 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)
![](https://sharpcoderblog.com/public/images/56c/56cfb2d98f5fbdb6ed2b3c8a38fb4591.png)
![](https://sharpcoderblog.com/public/images/2b8/2b877445b3aa0ad894fd666e6626ec00.jpg)
- Select ‘RTSPlayer’ and in NavMeshAgent tweak the Radius and Height until it matches the player model
![](https://sharpcoderblog.com/public/images/473/473ae91519a8a4c4cfa391a2c1f914df.png)
- Now let’s create a target Indicator prefab. This is just a simple GameObject with a Quad that will indicate where we have clicked on the map.
![](https://sharpcoderblog.com/public/images/ad5/ad57f2613fac0dbeefa077e5b31387ad.jpg)
![](https://sharpcoderblog.com/public/images/22a/22a309e79035e5bf18e14f9a6f90e1fa.png)
![](https://sharpcoderblog.com/public/images/519/5198df4a2b3e7debad6f62198eb666a7.png)
You can use the texture below:
![real-time strategy target indicator](https://sharpcoderblog.com/public/images/078/0788965286b6212f7a4d6bf8b8dfaa3e.png)
- And lastly, select ‘RTSPlayer’ and assign all the necessary variables at the RTSPlayerController:
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
![](https://sharpcoderblog.com/public/images/5bd/5bdd06e84e389891c1880d154a1adb54.png)
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:
![](https://sharpcoderblog.com/public/images/c24/c2480b436818072224f0ca9ae203fe86.jpg)
![](https://sharpcoderblog.com/public/images/2ac/2ac5c01189b5a1cb71834205df9379d5.png)
- Go to Window -> AI -> Navigation
![](https://sharpcoderblog.com/public/images/275/2753afaca22b5dc15d69f598e7983ab3.png)
- Under the Bake tab change the values of Agent Radius and Agent Height (those should match the values from NavMeshAgent), then click Bake.
![](https://sharpcoderblog.com/public/images/5b6/5b69c0cf32e2d298fbf834aa1d9a5f14.png)
- After Baking is finished you’ll notice a bluish outlined mesh, which represents the walkable area.
![](https://sharpcoderblog.com/public/images/0f1/0f1df3912e7b1e6eeccac154b9d03419.jpg)
NOTE: To prevent the player from walking over the hills, go back to the Bake tab and decrease the Max Slope angle then rebake navmesh.
![](https://sharpcoderblog.com/public/images/b18/b183855ea290184ce09872458ce7d728.png)
![](https://sharpcoderblog.com/public/images/268/26809ac1728af2ce593a888b51bab1ab.jpg)
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:
Tip: Tweak Speed, Angular Speed, and Acceleration value at NavMeshagent to fit your needs.