Unity3D提供的NavMesh系统可以方便的解决游戏的寻路问题,但是该系统有一个比较让人不理解的问题:

  NavMesh导航时会忽略Physics系统本身的碰撞,也就是说NavMeshAgent在移动的过程中不会被Collider阻挡,而是会直接走过去(但是OnTriggerEnter等触发功能正常)。

  动态碰撞的功能对很多游戏都是一个基本的需求,而根据NavMesh提供的接口,唯一可以实现阻挡功能的只有NavMeshObstacle,而NavMeshObstacle只有一种形状:圆柱体,而且up方向固定,不能调整为侧向。总结起来就是以下几点:

  (1)导航网格的行走/碰撞区域只能预烘焙;

  (2)动态碰撞体只能通过挂载NavMeshObstacle组件来实现;

  (3)碰撞体的形状只有一种——圆柱体,严格来说就是圆形,而且是正圆还不能是椭圆。

  所以说到这里,基本上可以放弃使用各种形状的Collider来制作场景阻挡物了。不过,替代方案也还是有的:如果一定要使用Unity3D提供的NavMesh来做导航,那么可以将圆作为基本元素来模拟其它形状。

  

  上图展示了通过NavMeshObjstacle来模拟立方体阻挡物,为了方便的编辑该立方体的大小,可以写一个辅助脚本来实现:

using UnityEngine;
using System.Collections;
using System.Collections.Generic; [ExecuteInEditMode]
public class MultiObstacleHelper : MonoBehaviour
{
public float Interval = 1f; // Obstacle之间的间隔
public int Num = ; // Obstacle的个数 private float curInterval = 1f;
private int curNum = ; private Transform template = null; void Awake()
{
template = gameObject.transform.Find("Obstacle");
} void Start()
{
Adjust();
} void Update()
{
if (Num <= ) Num = curNum;
Adjust();
} private void Adjust()
{
if (template == null) return;
AdjustInterval(AdjustNum());
} private bool AdjustNum()
{
if (curNum == Num) return false; if (Num > curNum)
{
for (int i = ; i < Num - curNum; ++i)
{
GameObject go = GameObject.Instantiate(template.gameObject) as GameObject;
go.transform.parent = template.parent;
go.transform.localPosition = Vector3.zero;
go.transform.localScale = Vector3.one;
go.transform.localRotation = Quaternion.identity;
}
}
else if (Num < curNum)
{
int count = curNum - Num;
List<Transform> lst = new List<Transform>();for (int i = ; i < template.parent.transform.childCount; ++i)
{
if (count <= ) break;
if (template.parent.GetChild(i) != template)
{
lst.Add(template.parent.GetChild(i));
count--;
}
}
while(lst.Count > )
{
Transform tran = lst[];
GameObject.DestroyImmediate(tran.gameObject);
lst.RemoveAt();
}
lst.Clear();
} curNum = Num;
return true;
} private void AdjustInterval(bool numChange)
{
if (numChange == false && curInterval == Interval)
return; int half = Num / ;
int index = ;
foreach (Transform tran in template.parent.gameObject.transform)
{
// 奇数个
if (Num % == )
{
Vector3 pos = tran.localPosition;
pos.x = (index - half) * Interval;
tran.localPosition = pos;
}
else
{
Vector3 pos = tran.localPosition;
pos.x = (index - half + 0.5f) * Interval;
tran.localPosition = pos;
}
index++;
} curInterval = Interval;
} }

  上述代码可以调整Obstacle的个数和间距,然后再配合调整缩放比例基本上可以做出各种尺寸的立方体。

  单向阻挡的实现,可以通过组合Trigger和NavMeshObstacle来实现一个单向阻挡的功能:

  

  实现思路是当角色进入红色Trigger区域时,将后面的阻挡物隐掉,过1秒之后再激活,这样就可以实现一个单向阻挡物的功能,实现的代码比较简单,如下面所示:

using UnityEngine;
using System.Collections; #if UNITY_EDITOR
using UnityEditor;
#endif public class SinglePassTrigger : MonoBehaviour
{
[HideInInspector]
public Transform Object = null;
public Transform Collider = null;
public float PassTime = 1f; void Start()
{
Object = transform.parent.transform.Find("Object");
Collider = transform.parent.transform.Find("Collider");
} protected virtual void OnTriggerEnter(Collider other)
{
StopCoroutine("LetPassCoroutine");
StartCoroutine("LetPassCoroutine");
} protected virtual void OnTriggerExit(Collider other)
{ } IEnumerator LetPassCoroutine()
{
SetPassState(true);
float startTime = Time.time;
while(Time.time < startTime + PassTime)
{
yield return null;
}
SetPassState(false);
} private void SetPassState(bool value)
{
if (Collider == null) return; Collider.gameObject.SetActive(!value);
} #if UNITY_EDITOR
void OnDrawGizmos()
{
// 设置旋转矩阵
Matrix4x4 rotationMatrix = Matrix4x4.TRS(Vector3.zero, transform.rotation, Vector3.one);
Gizmos.matrix = transform.localToWorldMatrix;
// 在Local坐标原点绘制标准尺寸的对象
Gizmos.color = new Color(1f, 0f, 0f, 0.8f);
Gizmos.DrawCube(Vector3.zero, Vector3.one);
Gizmos.color = Color.black;
Gizmos.DrawWireCube(Vector3.zero, Vector3.one);
Gizmos.DrawIcon(transform.position + Vector3.up, "ban.png");
}
#endif }

>>>>>>经测试,上述方案并不是很好用,会碰到以下几个问题:

(1)角色在Obstacle周围挤来挤去,行为很诡异;

(2)通过不断地靠近Obstacle,当遇到卡顿的时候,角色会穿透阻挡物;

(3)Obstacle虽然可以设置Cave属性,也就是动态切割导航面,但由于一些原因,动态切割的效果非常差,尤其是在一些不平的地面部分更是如此。

基于这些思考,推荐使用如下新的方法来做阻挡效果:

  通过NavMesh的Layer来实现:

  通过动态改变NavMeshAgent所能使用的层(NavMeshWalkable),来实现双向和单向阻挡的效果,经验证这种方案表现效果比较好,只是在场景制作时就必须确定不同层区域的划分。

  上述方案再配合一些魔法墙之类的特效,总体来说表现效果还是不错的,不过代码逻辑一定要清晰。

NavMesh系统动态碰撞的探讨的更多相关文章

  1. 动态生成navmeshi-进击的新版NavMesh系统:看我飞檐走壁

    http://forum.china.unity3d.com/thread-25421-1-1.html0x00 前言 unity5.6作为Unity5最后的一个版本,的确起到了一个承上启下的作用.除 ...

  2. 进击的新版NavMesh系统:看我飞檐走壁

    0x00 前言 unity5.6作为Unity5最后的一个版本,的确起到了一个承上启下的作用.除了上一篇文章<进击的AssetBundles和它的工具们>中提到的AssetBundles- ...

  3. iOS 获取真机上系统动态库文件

    iOS 获取真机上所有系统库文件 系统动态库文件存放真机地址(/System/Library/Caches/com.apple.dyld/dyld_shared_cache_arm64) 在Mac\i ...

  4. NavMesh动态碰撞

    今天遇到一个问题,就是怎样处理一些动态的障碍物. NavMesh是能够躲避静态的障碍物.NavMeshObstacle的作用就是动态添加障碍. 可是有个问题,NavMeshObstacle是圆,连椭圆 ...

  5. 使用JSP/Servalet技术开发新闻发布系统------动态网页开发基础

    什么是动态网页? 动态网页是指在服务器端运行的程序或者网页,它们会随不同客户.不同时间,返回不同的网页. 动态网页的特点? (1).交互性:即网页会根据用户的要求和选择而动态改变和响应.采用动态网页技 ...

  6. win系统动态载入DLL所需要的三个函数详解(LoadLibrary,GetProcAddress,FreeLibrary)

    动态载入 DLL 动态载入方式是指在编译之前并不知道将会调用哪些 DLL 函数, 完全是在运行过程中根据需要决定应调用哪些函数. 方法是:用 LoadLibrary 函数加载动态链接库到内存,用 Ge ...

  7. Spring Cloud微服务系统下的数据一致性探讨

    我想这个问题需要根据自己的系统具体架构来分别讨论,这边拿一个车联网的系统举例. 拆除GPS这个功能接口需要分几个步骤实现(不涉及数据更新的步骤略去了): ①更改GPS设备状态(设备管理服务) ②更改工 ...

  8. Android6.0以上系统动态获取权限

    动态权限的申请方法: 1.首先,需要在AndroidManifest.xml静态申请权限,否则无法动态申请权限: <uses-permission android:name="andr ...

  9. vsphere平台为win系统动态扩展磁盘

    1.关闭win虚拟机 2.在vcenter管理中加大磁盘空间 3.开启win虚拟机(此时磁盘并没有加大) 4.打开cmd命令行: 进入分区管理--->查看磁盘--->选择磁盘---> ...

随机推荐

  1. OpenGL学习进程(11)第八课:颜色绘制的详解

        本节是OpenGL学习的第八个课时,下面将详细介绍OpenGL的颜色模式,颜色混合以及抗锯齿.     (1)颜色模式: OpenGL支持两种颜色模式:一种是RGBA,一种是颜色索引模式. R ...

  2. PHP实现微信公众账号开发

    1.首先需要一个可以外网访问的接口url. 我这里是申请的新浪免费云服务器,http://xxxxx.applinzi.com/wx.php,具体自己可以去新浪云中心申请地址为:http://www. ...

  3. LoadRunner 如何将英文的字符串转换成UTF-8格式的字符串?

    7.48  如何手动转换字符串编码 1.问题提出 如何将英文的字符串转换成UTF-8格式的字符串? 2.问题解答 可以使用lr_convert_string_encoding函数将字符串从一种编码手动 ...

  4. 用Word收集网页中的内容,用文档结构图整理

    如何用Word保存网页中的内容 网页中的内容,用什么保存好? 用笔记类软件是个不错的选择,还可以用 Word 保存,这样方便用“文档结构图”来整理网页. 如图:网页收集后用文档结构图进行整理. (图一 ...

  5. linux部署war包方案

    batch.sh内容: su - -c" 使用管理员权限 service tomcat6 stop; 停止tomca6t服务 mkdir /home/jnfwzFtp/bushubackup ...

  6. assertThat用法

    一般匹配符1.assertThat( testedNumber, allOf( greaterThan(8), lessThan(16) ) ); 注释: allOf匹配符表明如果接下来的所有条件必须 ...

  7. 常用js代码

    common-function-lib.js /*产生随机颜色*/ function randomColor() { var rand = Math.floor(Math.random() * 0xF ...

  8. 进入做Mvc项目的时候 返现某个文件夹下面css js png等静态文件都访问不了

    原来是我在该文件夹下面添加了一个web.config 里面 静止了所有的文件 直接访问 <system.web>    <httpHandlers>      <add ...

  9. 文件系统管理 之 实例解说 fdisk 使用方法

    一.fdisk 的介绍: fdisk - Partition table manipulator for Linux ,译成中文的意思是磁盘分区表操作工具:本人译的不太好,也没有看中文文档:其实就是分 ...

  10. 【转】安装OpenSSL缺失Microsoft Visual C++ 2008 Redistributables的解决方案

    from: http://www.cnblogs.com/luguo3000/p/3539815.html 在安装OpenSSL的时候通常会提示以下错误: "The Win32 OpenSS ...