【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向量之间的点积。这样做的目的是为了获取角色当前移动方向与期望移动方向之间的相似程度,从而在动画中正确地表现出角色的横向移动状态。

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

相关推荐
IT技术分享社区7 分钟前
C#实战:使用腾讯云识别服务轻松提取火车票信息
开发语言·c#·云计算·腾讯云·共识算法
Sitarrrr1 小时前
【Unity】ScriptableObject的应用和3D物体跟随鼠标移动:鼠标放置物体在场景中
3d·unity
极梦网络无忧1 小时前
Unity中IK动画与布偶死亡动画切换的实现
unity·游戏引擎·lucene
△曉風殘月〆7 小时前
WPF MVVM入门系列教程(二、依赖属性)
c#·wpf·mvvm
逐·風9 小时前
unity关于自定义渲染、内存管理、性能调优、复杂物理模拟、并行计算以及插件开发
前端·unity·c#
_oP_i10 小时前
Unity Addressables 系统处理 WebGL 打包本地资源的一种高效方式
unity·游戏引擎·webgl
m0_6569747412 小时前
C#中的集合类及其使用
开发语言·c#
九鼎科技-Leo12 小时前
了解 .NET 运行时与 .NET 框架:基础概念与相互关系
windows·c#·.net
九鼎科技-Leo15 小时前
什么是 ASP.NET Core?与 ASP.NET MVC 有什么区别?
windows·后端·c#·asp.net·mvc·.net
.net开发15 小时前
WPF怎么通过RestSharp向后端发请求
前端·c#·.net·wpf