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的属性。
遗憾的是RayResult没有为我们提供碰撞点的坐标,不过Ray提供了一个非常好用的方法at。通过调用Ray.at(distance),可以获得射线方向上距离起始点distance距离的坐标。那么碰撞点的坐标就可以通过下面的代码轻松获取了。
collidePoint = ray.at(rayResult.distance);
接着以这个点为起点,以原始射线相对normal的对称方向为新的方向,重新绘制一条射线,就实现了射线反射的效果了。
关于对称方向的计算,都是一对向量公式,我已经单独写到LDMath.symmetric()函数中,如果你想了解原理,请参考我之前在9ria天地会发布的教程 http://bbs.9ria.com/thread-67614-1-1.html
在Flash中编译后的效果如下图所示(点击图像查看动态效果),射线以舞台中心为起始点,点击舞台任意位置,改变射线方向,射线会经过5次反射后停止下来。按下空格键,可以重新随机创建刚体。
代码部分重点在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)); } }
代码中以及进行了详细的备注,我就不再赘述了,其他不尽之处,欢迎跟帖讨论。点击下载完整源文件!
联系作者
可惜Nape没有js版本,不知道拉登大叔有没有把Nape移植到其他版本的愿望?
我Nape的官方论坛上提问了,问作者有没有意向发布HTML5版的Nape,还没有得到回复呢!
哈哈,感谢登叔~其实有时候出于热情,自己也想写一个物理引擎,可是光说碰撞检测这一块儿就已经把我给难倒了,不知道大叔能不能写一篇与碰撞检测有关的文章?
推荐你看《advanced game design with flash》里面详细的讲解了圆对圆,圆对多边形,圆对线段等各种情形的碰撞原理!
1111111111111111111111111111111111
22222222222222222222
拉登大叔,一直不理解body.totalImpulse()的用法能不能详细讲一下,想算一下碰撞受到了多少力不知道怎么来
记得之前你问过我这个问题,不好意思,忘记了,一直也没有回复你。totalImpulse()函数用来计算碰撞过程中,body受到的总的冲量大小,如果参数中的body不为null,则只计算这个两个刚体之间的冲量大小。可以根据返回值大小,实现刚体超出耐受力,被击碎的效果。
回头我写篇教程说明一下,额,估计得到月底了…
但是为什么返回的是一个三维向量,z用来表示什么?
没试过,我也不是很确定,我猜应该是扭力
支持下!大叔
谢谢支持,我也努力写出更多更好的教程给大家!
拉登兄,怎么用最后两点计算一条延长的射线啊,我想用鼠标点击一下就能切开那条射线内的刚体。
Nape入门老师啊,教程很棒!
入门老师,教程很棒呀!!!