NavMesh系统动态碰撞的探讨
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系统动态碰撞的探讨的更多相关文章
- 动态生成navmeshi-进击的新版NavMesh系统:看我飞檐走壁
http://forum.china.unity3d.com/thread-25421-1-1.html0x00 前言 unity5.6作为Unity5最后的一个版本,的确起到了一个承上启下的作用.除 ...
- 进击的新版NavMesh系统:看我飞檐走壁
0x00 前言 unity5.6作为Unity5最后的一个版本,的确起到了一个承上启下的作用.除了上一篇文章<进击的AssetBundles和它的工具们>中提到的AssetBundles- ...
- iOS 获取真机上系统动态库文件
iOS 获取真机上所有系统库文件 系统动态库文件存放真机地址(/System/Library/Caches/com.apple.dyld/dyld_shared_cache_arm64) 在Mac\i ...
- NavMesh动态碰撞
今天遇到一个问题,就是怎样处理一些动态的障碍物. NavMesh是能够躲避静态的障碍物.NavMeshObstacle的作用就是动态添加障碍. 可是有个问题,NavMeshObstacle是圆,连椭圆 ...
- 使用JSP/Servalet技术开发新闻发布系统------动态网页开发基础
什么是动态网页? 动态网页是指在服务器端运行的程序或者网页,它们会随不同客户.不同时间,返回不同的网页. 动态网页的特点? (1).交互性:即网页会根据用户的要求和选择而动态改变和响应.采用动态网页技 ...
- win系统动态载入DLL所需要的三个函数详解(LoadLibrary,GetProcAddress,FreeLibrary)
动态载入 DLL 动态载入方式是指在编译之前并不知道将会调用哪些 DLL 函数, 完全是在运行过程中根据需要决定应调用哪些函数. 方法是:用 LoadLibrary 函数加载动态链接库到内存,用 Ge ...
- Spring Cloud微服务系统下的数据一致性探讨
我想这个问题需要根据自己的系统具体架构来分别讨论,这边拿一个车联网的系统举例. 拆除GPS这个功能接口需要分几个步骤实现(不涉及数据更新的步骤略去了): ①更改GPS设备状态(设备管理服务) ②更改工 ...
- Android6.0以上系统动态获取权限
动态权限的申请方法: 1.首先,需要在AndroidManifest.xml静态申请权限,否则无法动态申请权限: <uses-permission android:name="andr ...
- vsphere平台为win系统动态扩展磁盘
1.关闭win虚拟机 2.在vcenter管理中加大磁盘空间 3.开启win虚拟机(此时磁盘并没有加大) 4.打开cmd命令行: 进入分区管理--->查看磁盘--->选择磁盘---> ...
随机推荐
- C语言内存分布之数据段
不管我们以后是自己写代码还是读别人的代码,都应该想想这个变量默认存储的位置.在我们以后的嵌入式开发中,技巧性的代码越来越多的时候,我们可能把某一些代码放在一段.我们可以通过修改变量或者代码默认放置的段 ...
- 吐槽C++:C++ 类成员变量初始化 之 初始化带有参数的构造函数 的类成员变量。
本来我想写这样的代码: class MatchManager{ public: MatchManager() { } class OnTimerRunFuncHelper{ public: OnTim ...
- ios相关手册、图表等综合
Objective-C初学者速查表(来源:http://www.cocoachina.com/applenews/devnews/2013/1115/7362.html) iOS UIKit类图 (来 ...
- c#复制包含子目录文件夹代码
c#没有复制目录的代码,需要通过递归实现复制目录: 需要引用System.IO命名空间,实现代码如下: private static bool CopyDirectory(string SourceP ...
- mac os x用macport安装redis
一.Redis简要介绍 Redis是一个开源的使用ANSI C语言编写.支持网络.可基于内存亦可持久化的日志型.Key-Value数据库,并提供多种语言的API.从2010年3月15日起,Redis的 ...
- GOOGLE不能访问的解决方法
1VPN gate 2自 由 门 3修改Windows\System32\drivers\etc hosts (复制https://github.com/txthinking/google-hosts ...
- brew 出现 git 错误的问题分析
现象 brew update的时候出现 gitcrash 分析 在brew update 的时候看见有 git gc 的字样,提示有在gc 的动作.到/usr/local/ 目录,直接运行 git ...
- .NET Core:面向未来的开源跨平台开发技术
作为一种全新的开源和跨平台的开发平台,.NET Core 历经两年多的开发,终于在于2016年6月27日针对所有主流服务器和桌面操作系统发布 1.0 RTM 版本..NET Core 是一种通用开发平 ...
- add .json handler support in IIS 7
Sometimes we need to create JSON in a text file with extension .json, however by default IIS 7 or an ...
- iOS-Xcode上传后iTunes Connect构建版本不显示
在升级到Xcode8版本以后大多数人会碰到这个问题-开开心心开发好一款app以后上传到iTunes后台提交审核,然而iTunes Connect后台活动栏里没有出现我们上传的app,确切的说是显示一会 ...