【Unity实战】NavMeshAgent实现Strafe固定朝向移动

众所周知,NavMeshAgent一旦设定了destination,它就会直奔目标。但是在一些场景中,比如NPC是个射手,除了瞄准玩家,也需要走位。如果不加以处理,我们恐怕会遇见瞄准IK和朝向...难以言表的表现,直接上图吧。

下文我就以我的测试项目为例去讲这个事情。

准备工作

在开始之前,确保你已经熟悉Unity引擎的基本操作和NavMesh的设置。另外,需要在角色身上添加NavMeshAgent组件,并保证角色所在的场景已经设置好了NavMesh。

在我这个项目里,使用了官方的第三人称控制器package和Mirror Networking,可以上Asset Store去找。我们NavMeshAgent除了修改position和rotation,还要把velocity转换成输入的x、y,模拟玩家输入,确保原Controller脚本的move函数正常进行,并且能够更新动画,这样改的量能少一些。

其次需要注意的是,动画机也有改动,动画机参数多了两个float,分别代表纵轴和横轴的输入。与此同时,还加入了一套平移用的动画StateMachine。

至于怎么实现ThirdPersonController的Move函数如何实现固定朝向,这里就不进行赘述。

实现Strafe移动

首先,我们需要在StarterAssetsInput的脚本中添加一个方法来处理NavMeshAgent的移动操作。要激活这套逻辑,**需要确保该角色处于瞄准的状态下,而且我们需要保证agent无论怎么移动都要始终面向目标。**下面是一个示例代码:

csharp 复制代码
/// <summary>
/// NavMeshAgent操作移动
/// </summary>
[ServerCallback]
private void OnNavMeshAgentInput()
{
	if (!netIdentity.isServer) return;
	if (!_teamIdentifier || !_teamIdentifier.IsBot) return;
	if (!_agent || !_agent.enabled) return;

	if (aim)
	{
		if(_agent.remainingDistance > _agent.stoppingDistance)
		{
			Vector3 targetDirection = _agent.destination - transform.position;
			Vector3 desiredVelocity = targetDirection.normalized;
			_agent.velocity = desiredVelocity;
		}
	}

	MoveInput(new Vector2(_agent.velocity.x, _agent.velocity.z));

	// TODO: 跳跃、下蹲、跑步

	// 根据角色速度判断是否要切换到跑步状态
	// 跑步已改到Behavior Designer实现
	// sprint = _agent.velocity.magnitude > 3f; // 假设速度大于5时切换到跑步状态
}

上面的代码中,我们通过计算目标方向和期望速度来实现Strafe移动效果。当角色处于移动状态时,设置NavMeshAgent的速度为期望速度,从而实现横向移动。

然而没有完事,人的确固定朝向移动了,但是腿出了毛病,前进变后退,左右却在前进后退时播放。这个是因为velocity的x和z与正常玩家的输入的xy值是有出入的,我们需要特殊处理。

接着,我们需要更新动画控制器来反映角色的移动状态。下面是更新动画控制器的代码片段:

csharp 复制代码
// update animator if using character
if (_hasAnimator)
{
	_animator.SetFloat(_animIDSpeed, _animationBlend);
	_animator.SetFloat(_animIDMotionSpeed, inputMagnitude);
	if (!_agent || !_agent.enabled)
	{
		_animator.SetFloat(_animIDHorizontal, _speed * _input.move.x);
		_animator.SetFloat(_animIDVertical, _speed * _input.move.y);
	}
	else
	{
		_animator.SetFloat(_animIDVertical, Vector3.Dot(transform.forward, _agent.desiredVelocity), 0.1f, Time.deltaTime);
		_animator.SetFloat(_animIDHorizontal, Vector3.Dot(transform.right, _agent.desiredVelocity), 0.1f, Time.deltaTime);
	}
}

在上面的代码片段中,我们使用了Vector3.Dot方法来计算两个向量之间的点积。点积是一种向量运算,用于衡量两个向量之间的相似程度。具体来说,点积计算的是两个向量之间的夹角的余弦值乘以两个向量的长度之积。

在动画控制器中,我们使用Vector3.Dot方法来计算角色的前方向和NavMeshAgent的desiredVelocity向量之间的点积。这样做的目的是为了获取角色当前移动方向与期望移动方向之间的相似程度,从而在动画中正确地表现出角色的横向移动状态。

可能不是很完美,但希望能有所启发,至少在更新这个动画机参数这块。

相关推荐
zwm26988881532 分钟前
hd 3#负一西送风,能远程启不能远程停
c#
Ai-_Man38 分钟前
Meta Muse还是不可以导出左侧所有对话,只能点进去单条内容导出,方法不对吗?
开发语言·人工智能·ai·小程序·c#·1024程序员节
小贺儿开发7 小时前
《长征 · 征途》Unity 三维互动沙盘
科技·3d·unity·1024程序员节·地形·互动·沙盘
上班摸鱼下班游戏8 小时前
Unity 仿生智能算法 从蚁群算法 开始
算法·unity·游戏引擎
2401_885885049 小时前
国际语音C#接口怎么写?.NET环境下实现国际语音验证码批量下发
开发语言·c#·.net
Wanda121411 小时前
机器人与机电一体化3D数字孪生机器-Day6
unity·机器人·数字孪生·1024程序员节
淡海水16 小时前
07-03-源码-.NET Core GC标记与扫描
unity·c#·.netcore·gc
波力海苔夹心脆67516 小时前
C# string 字符串方法大全:判空、查找、截取、分割、替换一篇讲透
经验分享·c#·.net·字符串·string·入门教程
上班摸鱼下班游戏1 天前
从零开始玩转 DOTween
unity·游戏引擎
阿松爱学习1 天前
【Unity开发】Unity长截图功能实现
unity·c#·游戏引擎