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. iOS开发---集成ShareSDK实现第三方登录、分享、关注等功能。

    (1)官方下载ShareSDK IOS 2.9.6,地址:http://sharesdk.mob.com/Download (2)根据实际情况,引入相关的库,参考官方文档. (3)在项目的AppDel ...

  2. iOS-App生命周期

    iOS APP 生命周期   官方文档: https://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneO ...

  3. Leetcode 232 Implement Queue using Stacks STL

    本题用两个栈实现队列,用栈的基本操作去实现队列的所有基本操作push(),pop(),peek()以及empty() sa作为输入栈,sb作为输出栈,将sa输入元素的反转过来放到sb中 push与sa ...

  4. C#:WebBrowser中伪造referer,为何对流量统计器无效?

    使用webbrowser伪造referer的方法:webBrowser1.Navigate(url, "_self", null, "Referer:http://www ...

  5. 奇怪吸引子---Thomas

    奇怪吸引子是混沌学的重要组成理论,用于演化过程的终极状态,具有如下特征:终极性.稳定性.吸引性.吸引子是一个数学概念,描写运动的收敛类型.它是指这样的一个集合,当时间趋于无穷大时,在任何一个有界集上出 ...

  6. Ios开发之sqlite

    Sqlite是ios数据存储的一个重要手段,今天我们就一块来看一下,怎样使用sqlite将数据存储到沙盒中去. 第一步:导入一个框架libsqlite3.0.dylib 选中TARGETS在Gener ...

  7. DropDownList 获取不了选择的值 这种错误

    有时候做项目的时候 发现DropDownList 获取不了选择的值 这个原因很可能是 你初始化DropDownList的时候 没有进行 ispostback的判断 导致提交的时候 又初始化了一次... ...

  8. .NET Actor Model Implementations Differ in Approach

    Last week Vaughn Vernon, author of Implementing Domain-Driven Design, published Dotsero, a .NET Acto ...

  9. Porter/Duff,图片加遮罩setColorFilter

    同步发表于http://avenwu.net/2015/02/03/porterduff Fork on github https://github.com/avenwu/support 经常会遇到给 ...

  10. 修改eclipse启动时eclipse使用的jre

    eclipse在启动的时候,和环境变量中的jdk不兼容,可以单独制定eclipse运行的jre. 方法: 在eclipse的配置文件里增加-vm参数即可. 打开eclipse目录下的eclipse.i ...