【游客模式】——注册会员,加入11RIA 闪客社区吧!一起见证Flash的再次辉煌……
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
转载:9RIA游戏开发者社区(天地会)
作者:ladeng6666(拉登大叔)
作者博客:http://www.ladeng6666.com/blog/
【Box2D系列教程-导航帖】—拉登大叔出品(总贴)
之前在学习emanueleferonato的Box2D刚体切割时,文中提到了Raycast函数,但是并没有对其Callback回调函数返回值进行讲解。看过API之后有了一个大概的了解,每个返回值的作用时这样的:
0:立即停止Raycast的查找
1:Raycast持续查找,直到达到线段的终点
fraction:查找最近的碰撞刚体
前两个返回值都调试成功,正如API中所说的,callback返回值为0时,Raycast只找到了1个碰撞点。返回值为1时,Raycast把线段上所有的碰撞点都标示了出来。但是当返回值为fraction,Raycast并没有按照期望的那样找到最近的碰撞点,而是找出了多个,而且没有规律的点。在下面的示例中,Raycast找到的刚体被标示成了蓝色,同时交互点也用蓝色的圆圈表示。按下空格键,查看不同返回值的效果,你会发现返回值为fraction时,虽然查找结果大部分都时离鼠标最近的刚体,但是还是有一部分与红线发生重叠的刚体未被标示出来。点击图片查看Flash。
后来比对了C++版Box2D的源代码之后,发现了Flash版Box2D的代码有些问题,具体在collision.b2DynamicTree.as中,按照C++版源码修改了它的Raycast()函数的部分代码如下:
[Actionscript3] 纯文本查看 复制代码 public function RayCast(callback:Function, input:b2RayCastInput):void
{
if (m_root == null)
return;
var p1:b2Vec2 = input.p1;
var p2:b2Vec2 = input.p2;
var r:b2Vec2 = b2Math.SubtractVV(p1, p2);
//b2Settings.b2Assert(r.LengthSquared() > 0.0);
r.Normalize();
// v is perpendicular to the segment
var v:b2Vec2 = b2Math.CrossFV(1.0, r);
var abs_v:b2Vec2 = b2Math.AbsV(v);
var maxFraction:Number = input.maxFraction;
// Build a bounding box for the segment
var segmentAABB:b2AABB = new b2AABB();
var tX:Number;
var tY:Number;
{
tX = p1.x + maxFraction * (p2.x - p1.x);
tY = p1.y + maxFraction * (p2.y - p1.y);
segmentAABB.lowerBound.x = Math.min(p1.x, tX);
segmentAABB.lowerBound.y = Math.min(p1.y, tY);
segmentAABB.upperBound.x = Math.max(p1.x, tX);
segmentAABB.upperBound.y = Math.max(p1.y, tY);
}
var stack:Vector.<b2DynamicTreeNode> = new Vector.<b2DynamicTreeNode>();
var count:int = 0;
stack[count++] = m_root;
while (count > 0)
{
var node:b2DynamicTreeNode = stack[--count];
if (node.aabb.TestOverlap(segmentAABB) == false)
{
continue;
}
// Separating axis for segment (Gino, p80)
// |dot(v, p1 - c)| > dot(|v|,h)
var c:b2Vec2 = node.aabb.GetCenter();
var h:b2Vec2 = node.aabb.GetExtents();
var separation:Number = Math.abs(v.x * (p1.x - c.x) + v.y * (p1.y - c.y))
- abs_v.x * h.x - abs_v.y * h.y;
if (separation > 0.0)
continue;
if (node.IsLeaf())
{
var subInput:b2RayCastInput = new b2RayCastInput();
subInput.p1 = input.p1;
subInput.p2 = input.p2;
//================================
// udpate by ladeng6666 2014-08-01
subInput.maxFraction = maxFraction;
var value:Number = callback(subInput, node);
if (value == 0.0)
return;
//Update the segment bounding box
if(value > 0){
maxFraction = value;
//================================
tX = p1.x + maxFraction * (p2.x - p1.x);
tY = p1.y + maxFraction * (p2.y - p1.y);
segmentAABB.lowerBound.x = Math.min(p1.x, tX);
segmentAABB.lowerBound.y = Math.min(p1.y, tY);
segmentAABB.upperBound.x = Math.max(p1.x, tX);
segmentAABB.upperBound.y = Math.max(p1.y, tY);
}
}
else
{
// No stack limit, so no assert
stack[count++] = node.child1;
stack[count++] = node.child2;
}
}
}
修改之后再调试,当Raycast的Callback函数返回值为fraction,距离最近的刚体和碰撞点都被准确的标示出来了。在下面的示例中,按下空格键,查看修改后的效果。点击图片查看Flash。
下载:
Raycast.zip
(588.57 KB, 下载次数: 0)
|