转载自:http://www.9ria.com/news/2011/0718/23343.html
这是用Box2D实现切割效果的第二部分了。在第一部分教程中,我们找到了切割的切入点和切出点,现在该实现真正的切割了。
切割对象,我们只需要三个步骤,马上开始吧!
首先找到激光的中心点
在这一步中,我们需要找到激光在对象内部的中心点。换句话说,如果我们认为切入点和起初点之间是激光在对象内部的部分,那么我们必须找到他们的中心点,这对我们下面实现切割过程有很大的帮助。
虽然要修改laserFired函数里面的内容,但这一点实现起来很简单,
首先,添加两个新的变量:
16行:affectedByLaser,一个b2Body数组,用来存储被激光切到的刚体。
17行:entryPoint,一个b2Vec2数组,用来存储激光的切入点。
下面我们来仔细看一下laserFired方法(第101~114行)。
现在要做的不单单只是画个圆的事情了,我们需要区分切入点和切出点,用不同的效果来绘制这两个点会对我们有所帮助,持续追踪被影响到的刚体,并找到它内部激光的中心点。
113行:创建一个名为affectedBody的b2Body变量,它表示我们再getBody方法里创建的,切被激光切割的刚体。
114行:创建一个名为fiextureIndex的变量,使用indexOf可以得到affectedBody是否包含在affectedByLaser数组中。
115行:如果fixtureIndex等于-1,表示affectedBody不在affectedByLaser数组中,所以我们可以说,它不是激光切割到的第一个刚体,很明显,我们必须处理切入点。
116~117行:将被切割的刚体和交互点分别存储到affectedByLaser和entryPoint数组中。
118行:如果fixtureIndex不是-1呢?这个表面它不是第一个affectedBody,这对我们来说,包含两种含义:它是一个已存在的切出点,它是被激光切割的刚体。
119行:绘制切入点。
120行:绘制切出点。
121行:切入点和切出点的中心点。
122行:绘制中心点
结果如下:
http://www.emanueleferonato.com/wp-content/uploads/2011/06/Laser4.swf
试着用激光切割对象。
现在刚体被激光完全切割开来,这个激光包含切入点、切出点和中心点。其他情况下,激光与刚体只有一个接触点时,我们认为它没有被切割。
切入点标示为红色、切出点黄色、中心点是橙色。
定义新的多边形顶点
在将刚体切割成两部分之前,我们要知道这个刚体有那些顶点在第一部分中,那些顶点在第二部分中。
怎么实现呢?道理很简单:假设激光是一个坐标轴,那么所有在坐标轴之上的顶点属于第一部分,所有在坐标轴之下的顶点属于第二部分,每个部分都包含切入点和切出点。
laserFired方法更新如下:
112行:rayAngle表示激光切割的角度
114行:polyVertices数组存储多边形的所有顶点,这些顶点由GetVertices()方法返回。
115行:遍历所有的顶点,并判断它们分别属于第一部分还是第二部分。
116行:worldPoint(b2Vec2变量)获得顶点的坐标,该坐标由GetWorldPoint方法返回。
117行:代码的核心部分:cutAngle是顶点以激光为坐标轴的相对角度,这个坐标轴可以由切入点和中心点组成。
121~125行:每个顶点根据它的角度分别被标示成了黑色或白色的圆圈。
现在,我们可以看到切割后产生的新顶点了:
http://www.emanueleferonato.com/wp-content/uploads/2011/06/Laser5.swf
试着切割对象,你会看到切割后的顶点被标示成了黑色和白色。
最后,切割对象!
切割对象
虽然这是最后一步了,但这一步不是最简单,甚至可以说是最难的。我们要管理被切割后的对象。
首先是一些理论。正如你在前面我们完成的效果里看到的,我们可以很轻松的区分出切割后的顶点:一个由白色的顶点和切入点、切出点组成,另一个由黑色顶点和切入点、切出点组成。
代码需要再复杂一点,因为Box2D想让多边形的顶点按顺时针方向排列。很多网站和论坛会告诉你的逆时针方向是错误的,至少对于Box2D和Flash是错误的。
所以算法应该是:白色顶点顺时针排列,再加上切入点和切出点组成一部分,另外一部分由黑色顶点顺时针排列,再加上切入点和切出点组成。注意,在白色和黑色顶点里的切入点和切出点的顺序是反向的。
下面是完整的代码:
和前面一样,laserFired方法的工作很艰难,将新生产的多边形顶点分别保存到newPolyVertices和newPolyVertices数组中,如112~113行。
117~149行:创建这两个数组保存每一个部分的顶点,是一个”不太聪明”的做法,因为我用了很多没用的变量,所以你可以按照自己的想法修改并优化这部分代码。
不管怎么样,一旦我们创建好了存储顶点的数组,第150和151行会调用createSlice方法(稍后我会解释这个方法),最后删除DestroyBody方法(152行)里切割的刚体。
现在我们来说说createSlice方法,它包含两个参数:存储顶点的数组和这个数组的长度。我在写代码时,意识到这个方法需要两个参数,而且第二个参数可以从第一个参数中获得。
然后第180行的代码用来计算激光的中心点。findCentroid方法与protected类型的ComputeCentroid方法(你可以在b2PolygonShape.as文件中找到这个方法)一样。
第181~183行:找到中心点后,需要将顶点的坐标系由Box2D中的绝对坐标系改为相对于中心点的相对坐标系。
第184~193行:用数组中的定向创建刚体,这个动作由188行的SetAsVector方法完成。
最后,因为新生成的两个刚体共用了两个顶点(切入点和切出点),而且这个两个点都是以引用的形式传递给刚体的,所以我们必须将这两个相对值转换为绝对值(第194~196行)。
全文结束!!!
http://www.emanueleferonato.com/wp-content/uploads/2011/06/Laser6.swf
最后,你可以任意的切割对象了。!
但到这里还没有完全结束,现在我们要去掉调试用的图形,然后给对象添加一些皮肤。稍后我将会向你解释如何实现。最后,请下载本文的所有源代码