Unity 的 RTS 和 MOBA 玩家控制器

在视频游戏中,RTS 一词代表实时策略。

RTS 与传统第一人称/第三人称射击游戏的区别在于,角色是使用鼠标指针控制的,而不是通常的 W、A、S 和 D 按钮。

玩家可以鸟瞰战场,能够向部队下达命令,但无需直接控制他们。RTS 游戏的示例有《魔兽争霸》、《星际争霸》、《哥萨克》等。

魔兽争霸3游戏截图

另一方面,MOBA 代表多人在线战斗竞技场,它是 RTS 游戏的一种较新的子类型,玩家仅控制一个角色而不是多个角色。

此类游戏的例子有《英雄联盟》和《Dota 2》。

在本教程中,我将展示如何在 Unity 中创建 RTS/MOBA 风格的控制器。

第 1 步:让我们创建必要的脚本

本教程非常简单,因为它只需要一个脚本。

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);
            }
        }
    }
}

第2步

现在让我们设置玩家控制器和游戏关卡。

  • 创建一个新的 GameObject 并调用它 'RTSPlayer'
  • RTSPlayerController.cs 脚本附加到它(注意:附加后,它将自动添加另一个名为 NavMeshAgent 的组件,稍后将需要该组件)

  • 添加一个玩家主体(在我的例子中,我将使用一个带有 cube 的简单胶囊,但如果有的话,您可以添加一个玩家模型)。将其缩小直到所需的大小。
  • 将玩家模型移动到 'RTSPlayer' 游戏对象内(注意:在建立父级之前,请确保 'RTSPlayer' 放置在玩家模型的底部)

  • 选择 'RTSPlayer' 并在 NavMeshAgent 中调整半径和高度,直到它与玩家模型匹配

  • 接下来是创建一个目标指示器 prefab。这只是一个带有四边形的简单游戏对象,它将指示我们在地图上单击的位置。

您可以使用下面的纹理:

实时策略目标指标

  • 最后,选择 'RTSPlayer' 并在 RTSPlayerController 脚本中分配所有必要的变量:

玩家相机 - 不言自明,这可以是任何相机

相机偏移 - 相机距离玩家的距离

Target Indicator Prefab - 我们刚刚创建的预制件

在“游戏”模式下,您会注意到单击地图不会使玩家移动。那是因为我们还有最后一件事要做,那就是烘焙 Navigation Mesh (Navmesh):

  • 选择属于地图一部分的所有对象并将它们标记为静态:

  • 转到窗口 -> AI -> 导航

  • 在“烘焙”选项卡下,更改“代理半径”和“代理高度”的值(这些值应与 NavMeshAgent 中的值匹配),然后单击“烘焙”。

  • 烘焙完成后,您会注意到一个蓝色轮廓的网格,它代表可步行区域。

注意:为了防止玩家翻山越岭,请返回“烘焙”选项卡并减小“最大坡度”角度,然后重新烘焙导航网格。

好多了!

最后,返回“播放”模式并左键单击地图上的某个位置。

玩家现在应该向目标移动,同时避开障碍物:

Sharp Coder 视频播放器

提示:调整 NavMeshagent 的速度、角速度和加速度值以满足您的需求。