深入探讨Box2D中ghost collision问题解决方案

在使用Box2D引擎时,我们必须牢记它只能对物理世界进行近似的仿真。这其中最根本的原因是帧速受限,而且在pix<->meter换算以及其它乘除法的约算上,会衍生出大量的边界问题。在box2d官方的FAQ页上可以看到这样一条提示:What are the biggest mistakes made by new users?  Expecting Box2D to give pixel perfect results.  这句话应当引起我们相当的注意。

对于“高速刚体穿越碰撞块”以及本文将讨论的“ghost collision”问题,目前还没有一个100%完美的解决方案。有时我真为这种bug感到抓狂,但是细想一下,如果要我自己去设计这样一套引擎,未必能做得更好。

ghost collision问题如下图所示:

A块和B块代表固定的地面,蓝色块代表正在移动中的人物。虽然我们把A块和B块放在了一个水平面上,但仍有相当的机率使得当Hero在水平方向上移动时,卡在A、B块的交界处。一个典型的情境是:你在一个超级玛丽类的平台游戏中使用了贴片地图(TMX),在TMX中又设了一个地面层或是平台层之类的。你在场景初始化时遍历这个平台层的每一个Tile,对它赋一个polyshape的body,然后我们的玛丽奥大叔走着走着,就卡住不动了,仿佛面前有一堵隐形的墙一样。

究其根本原因,我们可以仔细思索一下“What are the biggest mistakes made by new users?  Expecting Box2D to give pixel perfect results. ”这句话中包含的信息量。事实上,box2d并不能保证在任何一帧中,Hero一定是处在AB水平面之上的。此时Hero与B的碰撞可以分为以下两种情形:

情形1                                          情形2

把hero与B的相交部分四边形高设为Δy, 宽设为Δx。如果如情形1所示,Δy < Δx,则碰撞后的应力向量是在y轴方向的,反之则在x轴上。我们可以想到,Δy始终都是在一个比较小值范围内波动的,但是 Δx的波动范围则直接与hero的移动速度相关。由于hero的移速一般是要比Δy大很多的,在一帧内所形成的Δx’也会是一个相对较大的值,因此大部分情况下我们遇到的是情形1。

为解决这个问题,有了这样一些解决方案:

1.将A、B拼合成一个polyshape

将A、B简单的拼合成一个polyshaper后,自然消除了Hero <-> B之间的碰撞。当然了,这里的拼合必然不是手动拼合,而是用代码实现的相邻块自动拼合。这样的做的麻烦在于:1.拼合算法本身要花点功夫。2.对于不规则图形束手无策。polyshape的默认的最大顶点数为8,不规则图形会轻易超出这个界限。

另一个问题是,拼合将消除A、B块自身的特性,使得他们在一次碰撞检测中变得难以分辨。例如:

对于这样一个情境,如果把所有5个tile拼合成一个polyshape,当我们的hero顶到了问号上或者是顶到了砖块上,将会触发同一个碰撞回调。这时想要区分到底是哪一个被撞到了,除了全局坐标外,几无它法。如果把polyshaper换成edge chain,同样无法解决内部区分这个问题。

2.消除过于分明的棱角

如果我们把hero原来的90度棱角全部做一个钝化处理,也能缓解完全卡住的现象。因为这样一来,至少不会出现一个完全是水平方向上的碰撞反馈。然而问题没这么简单,此方案副作用是我们的英雄在平地上走着走着,会莫名其妙地小跳一下,仿佛被小石头绊了一个踉跄似的。有人说把A、B的棱角消除后能解决此问题,我试过后仍觉无用。

3.使用Edge Shape作为每一个Tile的body形状

如果我们用上、下、左、右四个edge shape代替原来的那个polyshape,我们会发现这个问题会奇迹般的得到解决。网上大家都说使用edge shape可以在绝大多数情况下解决这个问题,但是还没有谁说得清楚这是为什么。其实在非常苛刻的情况下,edge shape同样会使hero完全卡住,这一点,可以参见iforce2d兄的一个演示视频http://www.youtube.com/watch?v=oP7ZLeyc9HU
如果想要用edge shape完美的解决卡顿,可以使用ghost vertices,这一点见iforce 2d的教程https://www.iforce2d.net/b2dtut/ghost-vertices

尽管edge shape 配合ghost vertices完美解决了人物的卡死,但这又连带出两个衍生问题:

1)多次碰撞

由于原本的1个shape现在由4个shape组成,而box2d中的碰撞是以fixture为单位而非body进行检测的,所以现在如果Hero从A的上表面完整的滑过去,会分别与左边、上边、右边进行三次碰撞回调。在某些情况下,我们会非常不愿意收到这种针对同一个body的重复碰撞回调。一个取巧的方法是把左边和右边的长度分别缩小几个小像点,如下图所示.

这样可以初步解决人物在仅在表面滑动时产生的多次碰撞。如果hero不仅仅是在表面滑动的话,这种削减左、右边的方法就不再适用,需要您根据具体情境来想办法了。

2)Hero被锁死在edge shape内部

在poly shape的方案中,由于polyshape是完全致密的,所以绝无可能在碰撞完毕后,hero被A块完全包络住。但是当我们采用了edge shape的方案后,由于中间部分完全是空心的,在一些特殊的情况下可能导致hero完全被锁死在A的内部空间中。这时,我们就需要开动聪明的脑瓜子,针对具体情况想点新办法了。

Over。

参考文献:

http://www.box2d.org/manual.html

https://www.iforce2d.net/b2dtut/ghost-vertices

http://www.cocos2d-iphone.org/forum/topic/31787

时间: 2024-09-20 00:44:46

深入探讨Box2D中ghost collision问题解决方案的相关文章

简述SharePoint 2010中的沙盒解决方案

当程序员使用Visual Studio 2010为SharePoint 2010创建应用程序时,可以创建两种类型的解决方案,服务器场解决方案和沙盒解决方案.比如,打开Visual Studio 2010,新建一个空白SharePoint项目,你看到的第一个界面就是如下这个对话框. 服务器场解决方案(或简称为场解决方案)和SharePoint 2007一样,是一种被完全信任的解决方案.场解决方案可以包含能放到解决方案包里面的所有SharePoint组件和元素,比如应用程序页.可视化Web部件等等.

我在哪里可以配置windows azure中可用的缓存解决方案?

问题描述 我在哪里可以配置windows azure中可用的缓存解决方案? 我在哪里可以配置windows azure中可用的缓存解决方案,对于老的azure管理控制台, 解决方案 Hi 你指的是Microsoft的Azure 还是中国版的Azure? Best RegardsJambor 解决方案二: Hi 在中国版的Azure中,我们暂时可以通过使用Azure caching来作为我们的缓存解决方案,这篇文章:http://www.windowsazure.cn/zh-cn/develop/

电子商务中的网上支付解决方案

电子商务中的网上支付解决方案 一.引言 随着中小企业对电子商务应用程度的深入,越来越多的企业希望在自己的网站上能与顾客实现在线交易,而网上支付问题则是在线交易中的关键问题.对于中小企业而言,可以通过哪些方法低成本.高效率地解决网上支付问题呢?本文提出了网上支付问题的两种主要解决方案:网上银行模式和第三方支付平台模式,同时分析了网上支付中存在的主要问题及应对策略. 二.网上支付概述 网上支付是指以金融电子化网络为基础,以商用电子化工具和各类交易卡为媒介,采用现代计算机技术和和通信技术作为手段,通过

gc-关于Android中完全退出的解决方案

问题描述 关于Android中完全退出的解决方案 一般的做法是像这样 http://www.oschina.net/question/157182_59222 用一个链表去记录Activity.在退出的时候一一finish掉. 可是这样的话,每一个加进去的Acitivity在GC的时候都有可达的GC root,就是那个链表,导致Acitivity无法释放. 当Acitivity里的资源占用内存较大,存在OOM的问题. 有没有两全的解决方案呢? 解决方案 如果有图片等占用资源大的,就应该考虑用完就

探讨Ajax中有关readyState(状态值)和status(状态码)的问题_AJAX相关

先看下面一段代码,然后给大家详细介绍,Ajax中有关readyState(状态值)和status(状态码)的问题,具体内容如下所示: var getXmlHttpRequest = function () { try{ //主流浏览器提供了XMLHttpRequest对象 return new XMLHttpRequest(); }catch(e){ //低版本的IE浏览器没有提供XMLHttpRequest对象,IE6以下 //所以必须使用IE浏览器的特定实现ActiveXObject ret

iOS中关于模块化开发解决方案(纯干货)_IOS

关于iOS模块化开发解决方案网上也有一些介绍,但真正落实在在具体的实例却很少看到,计划编写系统文章来介绍关于我对模块化解决方案的理解,里面会有包含到一些关于解耦.路由.封装.私有Pod管理等内容:并编写的一个实例项目放在git进行开源[jiaModuleDemo],里面现在已经放着一些封装的功能模块:会不断的进行更新,假如你感兴趣可以Star一下,项目也不断的更新完善优化:如果你有更好的方案或者说好的建议可以lssues,我会在短时间进行更新并修改相应的问题: 一:项目中存在的问题 1:当公司里

探讨Ajax中有关readyState(状态值)和status(状态码)的问题

先看下面一段代码,然后给大家详细介绍,Ajax中有关readyState(状态值)和status(状态码)的问题,具体内容如下所示: var getXmlHttpRequest = function () { try{ //主流浏览器提供了XMLHttpRequest对象 return new XMLHttpRequest(); }catch(e){ //低版本的IE浏览器没有提供XMLHttpRequest对象,IE6以下 //所以必须使用IE浏览器的特定实现ActiveXObject ret

通过案例深入探讨PHP中的内存管理问题

问题  内存管理对于长期运行的程序,例如服务器守护程序,是相当重要的影响:因此,理解PHP是如何分配与释放内存的对于创建这类程序极为重要.本文将重点探讨PHP的内存管理问题. 一. 内存 在PHP中,填充一个字符串变量相当简单,这只需要一个语句"<?php $str = 'hello world '; ?>"即可,并且该字符串能够被自由地修改.拷贝和移动.而在C语言中,尽管你能够编写例如"char *str = "hello world ";&

深入探讨PHP中的内存管理问题

摘要 内存管理对于长期运行的程序,例如服务器守护程序,是相当重要的影响:因此,理解PHP是如何分配与释放内存的对于创建这类程序极为重要.本文将重点探讨PHP的内存管理问题. 一. 内存 在PHP中,填充一个字符串变量相当简单,这只需要一个语句"<?php $str = 'hello world '; ?>"即可,并且该字符串能够被自由地修改.拷贝和移动.而在C语言中,尽管你能够编写例如"char *str = "hello world ";&q