如果在unity中制作了一辆带有NavMeshAgent的坦克,当你要控制它掉头时,它会这样

但是我们想要这样,这也是本期教程的最终效果

国内网站我完全搜不到相关的内容,但是谷歌倒是能搜到一些。

第一个视频:

https://www.youtube.com/watch?v=SV1eE1hvuqY&t=38s

这个是使用navmeshAgent.Move()来在转弯时增加额外的移动来达到转弯时也会前进从而达到增加转弯半径的效果。但是由于navmeshAgent在启动和停止时有加速度,导致很难确定move多少。经常会有突然加速的情况而且使用这个后navmeshAgent的自动停止也会无法正常使用。可能需要禁用navmeshAgent的本身的速度并完全重写速度函数。个人觉得挺难的

第二个视频:

https://www.youtube.com/watch?v=Zn9F_1G5Gwg&list=PLvFYWuKxAmL8sNdSIlQpNxw5sFkgyRsVG&index=18

这个视频是在要掉头时在背后挖一个这样的洞来迫使tank寻找新的路径来完成转弯。这个看着效果不错,但仔细一想如果有一个士兵跟在坦克后面,坦克掉头并且挖洞士兵就会因为不在导航网格上而出错或者瞬移,所以我觉得这个也不是很行。

然后是我最后采取的方法,其实之前想过,但是刚开始觉得有点复杂就没采用,但是看到别人也提出了这个方案,我又尝试了一下做出来发现效果还可以

简单来说就是在要掉头或者转弯的时候,先根据目标点在左边或者右边来确定要往哪边转,确定后在对应方向设置一条新的转弯路径,让载具沿着转弯路径移动,直到不需要再转弯时就让载具直接向目标寻路。

这是更加细致一点的方案。比如朝右时,先通过创建路径函数获得路径点A,到达A后判断是否还需要转弯,需要就创建新的路径并得到路径点b,不需要就寻路到真正的目标点。

再寻路过程中,称pointA,pointB等这些点为临时路径点,真正的路径点为realDest;

using System;
using BattleScene.Scripts;
using BehaviorDesigner.Runtime.Tasks.Unity.UnityNavMeshAgent;
using UnityEngine;
using UnityEngine.AI;namespace DefaultNamespace
{public class NavMeshVehicleMovement : MonoBehaviour{private NavMeshAgent navMeshAgent;private Animator animator;public bool overrideMovementCtrl;public bool moveByAnim;public bool isTurnRound;private bool hasSetTurnRoundDes = false;public float turnRadius = 4;public int turnDegreeStepValue = 120;//每次寻找路径点时的转弯角度public int turnAngleThreshold = 90;//大于这个角度就开始转弯public void Start(){navMeshAgent = GetComponent<NavMeshAgent>();animator = GetComponent<Animator>();}private Vector3 realDest;//点击的真正路径点private Vector3 d1;//临时路径点public void Update(){if (overrideMovementCtrl == false || navMeshAgent.enabled == false || HasArrived() ||navMeshAgent.isStopped)return;Vector3 targetDir = navMeshAgent.destination - transform.position;if (Vector3.Angle(targetDir, transform.forward) > turnAngleThreshold && isTurnRound == false)//如果在背后   {realDest = navMeshAgent.destination;//在转弯开始时确定真正路径点,但是在转弯过程中如果玩家设定了新的目标点则会通过SetRealDest()函数更新真正目标点.isTurnRound = true;//只执行一次并开始转弯 navMeshAgent.autoBraking = false;//这是自动刹车的变量,不关闭的话就会有走一步停一步的感觉 }if (isTurnRound){if (hasSetTurnRoundDes == false) //d1为第一个临时路径点{d1 = FindTurnPoint(realDest);BattleFxManager.Instance.SpawnFxAtPosInPhotonByFxType(BattleFxType.DestionMark,d1,Vector3.forward);// 显示路径点标志hasSetTurnRoundDes = true;navMeshAgent.SetDestination(d1);}if (Vector3.Distance(transform.position, d1) <= navMeshAgent.stoppingDistance*1.2f)//到达临时路径点后寻找下一个临时路径点{if (Vector3.Angle(realDest - transform.position, transform.forward) > turnAngleThreshold)//注意对比角度是和真正路径点对比{d1 = FindTurnPoint(realDest);BattleFxManager.Instance.SpawnFxAtPosInPhotonByFxType(BattleFxType.DestionMark,d1,Vector3.forward);navMeshAgent.SetDestination(d1);}}if (Vector3.Angle(realDest - transform.position, transform.forward) < turnAngleThreshold)//当角度小于90度时,结束转弯 {navMeshAgent.SetDestination(realDest);hasSetTurnRoundDes = false;isTurnRound = false;navMeshAgent.autoBraking = true;}}Vector3 FindTurnPoint(Vector3 realDest)//Find temporary turn point;{Vector3 direction = realDest - transform.position;var cross = Vector3.Cross(transform.forward, direction); //通过叉积来判断目标地点在左边还是右边来决定超哪边旋转Vector3 targetPos;NavMeshHit navMeshHit;if (cross.y < 0) //在左边,{targetPos = transform.position - transform.right * turnRadius -transform.right * (turnRadius * Mathf.Cos((180 - turnDegreeStepValue) * Mathf.Deg2Rad)) +transform.forward * (turnRadius * Mathf.Sin((180 - turnDegreeStepValue) * Mathf.Deg2Rad));}else //在右边{targetPos = transform.position + transform.right * turnRadius +transform.right * (turnRadius * Mathf.Cos(turnDegreeStepValue * Mathf.Deg2Rad)) +transform.forward * (turnRadius * Mathf.Sin(turnDegreeStepValue * Mathf.Deg2Rad));}//使用SamplePosition来保证找到的路径点再导航网格上, SamplePosition的半径不应太大,否则可能因为障碍物找到较远的位置导致奇怪的寻路路径if (NavMesh.SamplePosition(targetPos, out navMeshHit, 2f, -1)){targetPos = navMeshHit.position; //找到在导航网格上的点}else //如果导航网格没有合适的目的地便直接朝realDest前进{targetPos = this.realDest;}return targetPos;}}public void SetRealDest(Vector3 pos)//the real destination is the position you clicked;{realDest = pos;}private bool HasArrived(){float remainingDistance;if (navMeshAgent.pathPending){remainingDistance = float.PositiveInfinity;}else{remainingDistance = navMeshAgent.remainingDistance;}return remainingDistance <= navMeshAgent.stoppingDistance;}}
}

需要注意的是,因为是通过SetDestination来设置新的路径点,所以在转弯过程中不能使用SetDestination来设置新的目标地点,否则半圆路径会被打断,也就失去了效果。在我的代码中转弯开始时会记录真正的目标点,在转弯结束后会继续向真正的目标点寻路。

要在转弯过程中设置新的目标地点应该通过设置记录的目标点变量而不是直接导航,通过SetRealDestPos函数来设置记录的目标地点,在转弯结束后,就会朝着新设置的目标点导航。

相关的伪代码

public virtual void SetTargetPos(Vector3 pos, bool showMark = true)
{if (navMeshVehicleMovement && navMeshVehicleMovement.isTurnRound){navMeshVehicleMovement.SetRealDest(pos);}else{navMeshAgent.SetDestination(pos);}
}

如果你有疑问或者你有更好的思路请评论。

如果这篇博客有帮助到你,建议点一个赞。

【Unity3d教程】如何让NavMesh上的载具和车辆能像现实一样优雅地掉头和转向相关推荐

  1. GTA5内置html菜单源码,《GTA5》稀有车收集教程 二十七:全配件载具合集

    本期带大家来获取那些远古版本的稀有车(已绝迹多年,现如今才浮出水面),获取代价极其高昂,囊中羞涩的朋友请量力而行 前期的准备内容: 1.一台培罗 PR4或者欧斯洛 R88(前者更贵一点) 2.足够的现 ...

  2. Unity3D教程:简单的碰撞检测

    需求:当立方体Cube碰到地面Plane的时候,输出碰撞物体的名称,则表述检测到立方体碰撞了地面. 1.搭建一个简单的场景. 在新的工程中选择File->new Scene创建新的场景.然后在该 ...

  3. unity3d用sever还是php,unity3d教程

    对unitye3d的学者来讲,学习Unity3D教程,必须经过Photon服务器入门,那么小编下面为大家分享讲解教程的内容. 首先去PhotonServer SDK下载服务器端SDK.解压出来是四个文 ...

  4. Unity3D教程:Unity3D自带寻路教程

    1.新建一个Cube 设置大小(10,0.5,10),重命名"plane":在plane上新建3个cube改名 "obstacle":新建一个sphere,和一 ...

  5. Unity3D的坑系列:动态加载dll

    Unity3D的坑系列:动态加载dll 我现在参与的项目是做MMO手游,目标平台是Android和iOS,iOS平台不能动态加载dll(什么原因找乔布斯去),可以直接忽略,而在Android平台是可以 ...

  6. Unity3D教程宝典之Web服务器篇:(第二讲)从服务器下载图片

    转载自风宇冲Unity3D教程学院                                     从Web服务器下载图片 上一讲风宇冲介绍了wamp服务器及安装.这回介绍如何从服务器下载内容 ...

  7. (转)【风宇冲】Unity3D教程宝典之AssetBundles:第一讲

    自:http://blog.sina.com.cn/s/blog_471132920101gz8z.html 原创文章如需转载请注明:转载自风宇冲Unity3D教程学院 AssetBundles第一讲 ...

  8. php 实现自动加载更多,$.ajax+php实战教程之下拉时自动加载更多文章原理分析二...

    摘要: 继上一篇<$.ajax+php实战教程之下拉时自动加载更多文章原理分析>文章进行进一步讲解,完善之前的代码及引入ajax和php相关内容...... 上次留下的问题不知道看官们有没 ...

  9. keras构建卷积神经网络_通过此简单教程学习在网络上构建卷积神经网络

    keras构建卷积神经网络 by John David Chibuk 约翰·大卫·奇布克(John David Chibuk) 通过此简单教程学习在网络上构建卷积神经网络 (Learn to buil ...

最新文章

  1. 使用Python,Opencv绘制调色板及圆形来模拟霓虹的渐变效果
  2. 这有一份 Git 日常使用清单,你需要吗?
  3. DrugBank数据库
  4. 使用NeMo快速入门NLP、实现机器翻译任务,英伟达专家实战讲解,内附代码
  5. 网络推广专员带大家了解网站优化中长尾词的特征与优势!
  6. 通过C#和Xamarin或JavaScript和基于VS的Cordova工具,VS平台上的开发者可以
  7. python语言程序设计王恺答案在哪找_Python语言程序设计
  8. Java IO: RandomAccessFile
  9. nginx 调用dll_使用DLL中的资源
  10. ​iPhone 12全线跌破发行价;三星扩大众包定位网络;Fedora 33发布|极客头条
  11. hausaufgabe--python 11-List slice
  12. 20190820 On Java8 第十章 接口
  13. mysql 利用延迟关联优化查询(select * from your_table order by id desc limit 2000000,20)
  14. python自动发微信朋友圈不带图片_python itchat实现微信自动检测违规涉黄图片
  15. 内存笔记之DIMM与DDR
  16. 《pr2019》怎么加字幕
  17. noi国家集训队论文分类
  18. kafka集群Error creating broker listeners
  19. 如何快速三个月成为一个领域的高手的四个方法
  20. arping 的特殊用法

热门文章

  1. 苏宁视频云直播客户端的优化方案
  2. 解析code4app上自定义AlerView(开源学习)
  3. 皮肤检测与克服光线影响的连通域寻找
  4. 百度地图自定义坐标标记和mouseover/mouseout闪烁问题解决
  5. c语言人脸口罩检测,使用ModelArts 0代码实现人脸口罩检测
  6. 如何关闭win7的ps/2兼容鼠标(触屏版)
  7. 基础平台项目之设计方案
  8. 基于C#+VisualStudio winform 图书管理系统
  9. 深入理解MyBatis一级缓存和二级缓存【超详细源码解析】
  10. 开发的浏览器颠覆微软,引爆了一场互联网大战