11RIA 闪客社区 - 最赞 Animate Flash 论坛

搜索
查看: 2208|回复: 0
上一主题 下一主题

[2D 物理引擎] 【9RIA—ladeng6666】—【Box2D系列教程 新番】

[复制链接] TA的其它主题
发表于 2018-2-6 14:56:10 | 显示全部楼层 |阅读模式

【游客模式】——注册会员,加入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。

DemoRaycast_original.png
后来比对了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。
DemoRaycast.png


下载:
Raycast.zip (588.57 KB, 下载次数: 0)
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

站长推荐 上一条 /1 下一条

感谢所有支持论坛的朋友:下面展示最新的5位赞助和充值的朋友……更多赞助和充值朋友的信息,请查看:永远的感谢名单

SGlW(66139)、 anghuo(841)、 whdsyes(255)、 longxia(60904)、 囫囵吞澡(58054)

下面展示总排行榜的前3名(T1-T3)和今年排行榜的前3名的朋友(C1-C3)……更多信息,请查看:总排行榜今年排行榜

T1. fhqu1462(969)、 T2. lwlpluto(14232)、 T3. 1367926921(962)  |  C1. anghuo(147)、 C2. fdisker(27945)、 C3. 囫囵吞澡(58054)



快速回复 返回顶部 返回列表