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. MyEclipse使用总结——设置MyEclipse使用的Tomcat服务器 设置JDK

    一.设置使用的Tomcat服务器 如果不想使用MyEclipse自带的tomcat服务器版本,那么可以在MyEclipse中设置我们自己安装好的tomcat服务器 设置步骤如下: Window→Pre ...

  2. python爬虫抓取数据

    URL管理器实现方式:1. 内存python内存待爬取URL集合:set()已爬取URL集合:set() 2. 关系数据库MySQLurls(url, is_crawled) 3. 缓存数据库(高性能 ...

  3. shell 时间统计脚本

    #!/bin/sh #Today=`date +%Y%m%d` YEAR=`echo $|cut -c -` MONTH=`echo $|cut -c -` DAY=`echo $|cut -c -` ...

  4. Vue.js:轻量高效的前端组件化方案(转载)

    摘要:Vue.js通过简洁的API提供高效的数据绑定和灵活的组件系统.在前端纷繁复杂的生态中,Vue.js有幸受到一定程度的关注,目前在GitHub上已经有5000+的star.本文将从各方面对Vue ...

  5. WordPress安装使用问题记录

    本文记录在使用WordPress过程中的问题和解决. 安装 比较顺利没有问题,具体如下(CentOS 6.5,DO的CentOS7 image里默认的yum源没有mysql-serve比较奇怪r): ...

  6. 转:电子取证中AVI文件的文件雕复

    电子取证中AVI文件的文件雕复 收藏本文 分享 1引言在电子取证工作中,恢复数字设备中被删除的数据是极为重要的工作之一,恢复数据又分依赖系统元信息的传统数据恢复技术和不依赖系统元信息的文件雕刻.文件雕 ...

  7. SQL获取本周销售总数

    select sum("NUMBER") as WEEK_NUMBER, COMPANY_CODE, PROJECT_CODE from D_VISIT WHERE "D ...

  8. IE11新文档模式Edge介绍与评估,及在WebBrowser应用中的使用。

    浏览器模式与文档模式概念是怎么来的? 1.浏览器模式与文档模式概念起源 为了解决兼容性的问题,在IE浏览器(IE8, IE9, IE10)中,引入了浏览器模式和文档模式两个概念,浏览网页时可以通过按F ...

  9. leveldb - 并发写入处理

    在并发写入的时候,leveldb巧妙地利用一个时间窗口做batch写入,这部分代码值得一读: Status DBImpl::Write(const WriteOptions& options, ...

  10. jqPlot插件绘制柱状图

    每天都在这里看别人写的东西,确发现自己好久没写文章了,可能是因为确实很忙,或许这也是在给自己找的一种借口. 不过这也是我人生中加入得第一个创业公司,来到这里才知道创业公司其实真的很辛苦,产品的萌芽才开 ...