Box2D中切割刚体效果的实现一览(二)



我们继续来实现切割效果。

我们现在有了切割线和多边形,可以利用Box2d的射线投射(RayCast)来检测切割线和多边形的交点(入射点)。在Box2d中通过定义b2RayCastCallback的子类来获取射线投射的结果,关于Box2d中的射线投射的使用,可以参考Box2Dv2.3.0 用户指南(第十章)

我们创建b2RayCastCallback的子类MyRayCastCallback,声明如下:

#import"Box2D.h"

 

classMyRayCastCallback : public b2RayCastCallback {

public:

   NSMutableArray* results;

   NSMutableArray* endResults;

   BOOL resultFlag;

   

   MyRayCastCallback();

   

   float32 ReportFixture(b2Fixture *fixture, const b2Vec2 &point, const b2Vec2&normal, float32 fraction);

   

   void ClearResults();

   void ResetFlag();

};

成员中定义了两个数组成员,results和endResults,原因是Box2d中射线投射得到的是线段射入多边形的第一个入射点,而实际上我们需要两个切点,因此我们的思路是做两次射线投射,第一次从lineStartSave到lineEndSave,第二次相反。从而得到两组入射点,分别记录在results和endResults两个数组中。

resultFlag用来区分两次投射。方法ResetFlag用于反置resultFlagClearResults方法用来清空投射结果。ReportFixture方法用来记录投射结果。

接着我们定义一个类RayCastResult来表示每一个投射的结果,声明如下:

#import"Box2D.h"

 

@interfaceRayCastResult : NSObject

 

-(id)initWithFixture:(b2Fixture*)fixture

               point:(b2Vec2) point

              normal:(b2Vec2) normal

            fraction:(float32) fraction;

 

@propertyb2Fixture* fixture;

@propertyb2Vec2 point;

@propertyb2Vec2 normal;

@propertyfloat32 fraction;

 

@end

类中定义了4个属性,分别对应投射得到的装置,入射点,法线和比例系数。

类的定义(实现)如下:

#import"RayCastResult.h"

 

@implementationRayCastResult

 

@synthesizefixture;

@synthesizepoint;

@synthesizenormal;

@synthesizefraction;

 

-(id)initWithFixture:(b2Fixture*)fixt point:(b2Vec2)p normal:(b2Vec2)n fraction:(float32)f {

   if (self = [super init]) {

       self.fixture = fixt;

       self.point = p;

       self.normal = n;

       self.fraction = f;

   }

   

   return self;

}

 

@end

没有太多需要说明的,定义了一个构造函数用来初始化所有属性。

接着我们来看MyRayCastCallback类的定义:

#import"MyRayCastCallback.h"

#import"RayCastResult.h"

 

MyRayCastCallback::MyRayCastCallback(){

   results = [[NSMutableArray alloc] init];

   endResults = [[NSMutableArray alloc] init];

   resultFlag = true;

}

 

float32MyRayCastCallback::ReportFixture(b2Fixture *fixture, const b2Vec2 &point,const b2Vec2 &normal, float32 fraction) {

   if (resultFlag) {

       [results addObject:[[RayCastResult alloc] initWithFixture:fixture point:pointnormal:normal fraction:fraction]];

   } else {

       [endResults addObject:[[RayCastResult alloc] initWithFixture:fixturepoint:point normal:normal fraction:fraction]];

   }

   return 1;

}

 

voidMyRayCastCallback::ClearResults() {

   [results removeAllObjects];

   [endResults removeAllObjects];

}

 

voidMyRayCastCallback::ResetFlag() {

   resultFlag = !resultFlag;

}

ReportFixture方法中通过对resultFlag的判断来确定结果应该存放到results中还是endResults中,方法返回1,这样当切割线跨过多个多边形的时候,能够捕获到所有的切点。其他的方法没有太多复杂的逻辑,不做说明了。

 

接着我们在HelloWorldLayer中添加一个成员:

MyRayCastCallbackrayCastCallback;

然后定义下面的方法来表示一次RayCast的执行:

-(void)doRayCast{

   rayCastCallback.ClearResults();

   world->RayCast(&rayCastCallback, [self toVec:lineStartSave], [selftoVec:lineEndSave]);

   rayCastCallback.ResetFlag();

   world->RayCast(&rayCastCallback, [self toVec:lineEndSave], [selftoVec:lineStartSave]);

   rayCastCallback.ResetFlag();

}

首先清空结果,然后执行第一次RayCast,反置resultFlag,然后执行第二次RayCast得到反向的切点,再次反置resultFlag。执行完这个方法后,所有的切点都储存在rayCastCallback的results和endResults中了。

正常情况下,我们希望在每次拖拽出切割线并松开后来执行射线投射的计算,因此应该在ccTouchEnded方法中添加doRayCast的调用。但是这里我们希望更加直观地看到切点的效果,所以我们在ccTouchMoved方法中添加调用,这样当切割线随着触点的移动,会实时地计算所有切点。接着我们在draw方法中添加下面的代码,在每个切点上绘制一个圆形来直观地表现其位置:

if([rayCastCallback.results count] > 0) {

   for (RayCastResult* result in rayCastCallback.results) {

       CGPoint point = [self toCGPoint:result.point];

       ccDrawCircle(point, 3, 0, 10, YES);

   }

   ccDrawColor4F(255, 0, 0, 255);

   for (RayCastResult* result in rayCastCallback.endResults) {

       CGPoint point = [self toCGPoint:result.point];

       ccDrawCircle(point, 3, 0, 10, YES);

   }

}

这里正向和反向投射得到的切点我们用不同的颜色来绘制,反向的切点用红色(255,0,0),正向的用白色。使用ccDrawCircle方法来绘制圆形。

由于Box2d中使用的长度单位不是像素,因此我们实现了两个b2Vec2和CGPoint之间转换的函数来方便调用:

-(b2Vec2)toVec:(CGPoint)p {

   b2Vec2 result(p.x / (float32)PTM_RATIO, p.y / (float32)PTM_RATIO);

   return result;

}

 

-(CGPoint)toCGPoint:(b2Vec2)vec {

   return CGPointMake(vec.x * (float32)PTM_RATIO, vec.y * (float32)PTM_RATIO);

}

实现后得到的运行效果(我们添加了3个多边形):


 

先到这里,最后一篇中我们来完成刚体的切割效果的制作。


阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qwertyupoiuytr/article/details/53998020
文章标签: IOS box2d 刚体 切割
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭