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

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

相关推荐
闪电麦坤955 小时前
C#:base 关键字
开发语言·c#
mingupup7 小时前
C#连接小智服务器并将音频解码播放过程记录
c#
爱吃奶酪的松鼠丶9 小时前
.net GRPC服务搭建,跨进程调用。C#应用和Python应用之间的通信。
python·c#·.net
牙膏上的小苏打233313 小时前
Unity Surround开关后导致获取主显示器分辨率错误
unity·主屏幕
勘察加熊人14 小时前
forms实现俄罗斯方块
c#
Unity大海15 小时前
诠视科技Unity SDK开发环境配置、项目设置、apk打包。
科技·unity·游戏引擎
艾妮艾妮18 小时前
C语言常见3种排序
java·c语言·开发语言·c++·算法·c#·排序算法
小码编匠18 小时前
.NET 验证码生成神器基于 SkiaSharp 的高性能方案
后端·c#·.net
专注VB编程开发20年19 小时前
Aspose.words,Aspose.cells,vb.net,c#加载许可证,生成操作选择:嵌入的资源
c#·word·.net·vb.net
andy552019 小时前
.NET 使用 WMQ 连接Queue 发送 message 实例
xml·c#·wmq·c# 连接wmq·发送消息到wmq