Nape反射的激光

Nape的刚体切割的教程中,我们曾经使用用rayCast()这个函数,不过只是用它来查找被切割的刚体,用法上也简单的一笔带过,今天我们来深入了解一下Nape中的rayCast()函数,并用它来实现射线反射的效果。

rayCast()是Space对象的一个方法,透过它的构造函数可以看的出,在使用之前,我们至少要有一个射线Ray对象,所以我们先来认识一下Ray。

     function rayCast(
                    ray : Ray,
                    inner : Boolean = false,
                    filter : InteractionFilter = null
              ):RayResult

射线Ray类在nape.geom包下,它的构造函数如下:

 
       public function Ray(
              origin:Vec2,
              direction:Vec2
       )

各个参数说明如下:

  • origin:射线的起始点,一个Vec2对象
  • direction:射线的方向,同样是一个Vec2对象

构造函数中没有定义射线的长度,这时长度默认是无限大的。之后就可以将Ray对象传递给rayCast(),发射一条射线了。

rayCast()执行完之后,会讲检测到与之发生碰撞的形状、碰撞面法向量、碰撞位置等信息保存到一个RayResult对象中并返回。

RayResult包含的属性和对应的碰撞信息说明如下:

  • distance:Number类型。碰撞点与射线起始点origin之间的距离。
  • normal:Vec2类型。碰撞面垂直的法向量,本章将根据normal的方向取射线的对称方向,实现射线的反射。
  • shape:Shape类型。与射线发生碰撞的形状,可以时Shape类的子类circle或polygon

通过下面的示意图,我们可以更清楚的认识这些属性所代表的意义。图中红色箭头表示射线,黑色的圆形是与之发生碰撞的形状。橙色背景的文本是rayCast的输入,即ray的属性;绿色背景的文本时rayCast的输出,即RayResult的属性。

NapeRaycast

遗憾的是RayResult没有为我们提供碰撞点的坐标,不过Ray提供了一个非常好用的方法at。通过调用Ray.at(distance),可以获得射线方向上距离起始点distance距离的坐标。那么碰撞点的坐标就可以通过下面的代码轻松获取了。

   collidePoint = ray.at(rayResult.distance);

接着以这个点为起点,以原始射线相对normal的对称方向为新的方向,重新绘制一条射线,就实现了射线反射的效果了。

NapeRayReflect

关于对称方向的计算,都是一对向量公式,我已经单独写到LDMath.symmetric()函数中,如果你想了解原理,请参考我之前在9ria天地会发布的教程 http://bbs.9ria.com/thread-67614-1-1.html

在Flash中编译后的效果如下图所示(点击图像查看动态效果),射线以舞台中心为起始点,点击舞台任意位置,改变射线方向,射线会经过5次反射后停止下来。按下空格键,可以重新随机创建刚体。

NapeRaySym

代码部分重点在createRays()中,具体如下:

private function createRays():void
{
	var rayNum:int = 6;
	pointList  = [];
	normalList = [];
	//初次投射射线,从舞台中心到鼠标方向。
	direction = mousePoint.sub(rayStartPoint);
	ray= new Ray(rayStartPoint,direction);
	rayResult = space.rayCast(ray);
	
	//将射线碰撞起始点和方向分别保存到pointList和normalList中。
	pointList.push(rayStartPoint);
	normalList.push(rayResult.normal.mul(30));
	
	//拷贝原始坐标,在接下里的循环遍历中使用
	var tempPoint:Vec2 =rayStartPoint.copy();
	var tempDirection:Vec2 = direction.copy();
	while(--rayNum>0){
		//计算碰撞点,并保存到temPoint中
		tempPoint = ray.at(rayResult.distance);
		//调用LDMath.symmetric(),计算tempDirection相对于rayResult.normal对称的向量
		tempDirection = LDMath.symmetric(tempDirection,rayResult.normal);
		
		//以对称向量tempDirection为方向,碰撞点tempPoint为起始点,重新创建射线ray,并进行投射
		ray = new Ray(tempPoint,tempDirection);
		rayResult = space.rayCast(ray);
		//保存新的碰撞信息
		pointList.push(tempPoint);
		normalList.push(rayResult.normal.mul(30));
	}
}

代码中以及进行了详细的备注,我就不再赘述了,其他不尽之处,欢迎跟帖讨论。点击下载完整源文件

联系作者

公众号:拉小登 | 微博:拉登Dony | B站:拉小登Excel

16 Replies to “Nape反射的激光”

  1. 哈哈,感谢登叔~其实有时候出于热情,自己也想写一个物理引擎,可是光说碰撞检测这一块儿就已经把我给难倒了,不知道大叔能不能写一篇与碰撞检测有关的文章?

  2. 拉登大叔,一直不理解body.totalImpulse()的用法能不能详细讲一下,想算一下碰撞受到了多少力不知道怎么来

  3. 记得之前你问过我这个问题,不好意思,忘记了,一直也没有回复你。totalImpulse()函数用来计算碰撞过程中,body受到的总的冲量大小,如果参数中的body不为null,则只计算这个两个刚体之间的冲量大小。可以根据返回值大小,实现刚体超出耐受力,被击碎的效果。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注