在看插件案例时,发现了一个利用NavMeshAgent组件来限制玩家移动范围的用法。感觉挺有意思的,就先记录下来。
1.原理
其实挺简单的,就是agent在移动到边缘时,因为无法再向前了,NavMeshAgent中的Speed就会自动为零,于是把这个变量乘到实际的移动里就可以了。
2实现
具体代码如下:
using UnityEngine;
using UnityEngine.AI;
[RequireComponent(typeof(NavMeshAgent))]
public class MoveByNavi : MonoBehaviour
{
private NavMeshAgent _agent;
private Vector3 _moveDir;
/// <summary>
/// 移动方向(世界坐标)
/// </summary>
public Vector3 MoveDir
{
get { return _moveDir; }
set { _moveDir = value.normalized; Move(_moveDir); }
}
/// <summary>
/// 判断是否在移动
/// </summary>
public bool IsMove
{
get { return _agent.velocity != Vector3.zero; }
}
[HideInInspector]
public float Speed;
private void Awake()
{
_agent = GetComponent<NavMeshAgent>();
_agent.speed = 1;
}
private void Move(Vector3 movDir)
{
transform.Translate(movDir * _agent.speed * Speed);
}
#region TestInput
/// <summary>
/// just for test
/// </summary>
public float SpeedVal;
private void Update()
{
Vector3 mov = InputDirViewToWorld(Camera.main.transform);
if (mov != Vector3.zero)
{
Speed = SpeedVal * Time.deltaTime;
MoveDir = mov;
}
}
/// <summary>
/// 将用户输入方向从摄像机空间转换到世界空间
/// </summary>
/// <param name="Cam">摄像机的Transform</param>
/// <returns>返回世界空间下的方向</returns>
public Vector3 InputDirViewToWorld(Transform Cam)
{
Vector3 tempMov = Vector3.zero;
float horInput = Input.GetAxisRaw("Horizontal");
float vertInput = Input.GetAxisRaw("Vertical");
if (horInput != 0 || vertInput != 0)
{
tempMov.x = horInput;
tempMov.z = vertInput;
tempMov = Vector3.ClampMagnitude(tempMov, 1);
Quaternion temp = Cam.rotation;
Cam.eulerAngles = new Vector3(0, Cam.eulerAngles.y, 0);
tempMov = Cam.TransformDirection(tempMov);
Cam.rotation = temp;
}
return tempMov;
}
#endregion
}
后面的输入代码只是测试方便用,最主要的函数就是其中的move。
效果
适用范围
1.有靠NaviAgent移动的NPC,且玩家和NPC的移动范围一致。
2.简单场景快速实现限制移动范围。