注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

风的驿站

一徐清风,半指烛光,觥筹已净,只余茶香。残卷一章,妙趣非常,忽闻帘响,愿闻其详?

 
 
 

日志

 
 
关于我

喜欢写生 编程 音乐 设计 喜欢把自己的想法变成实实在在的东西 喜欢安静的做一些事情 CSDN博客:http://blog.csdn.net/qwertyupoiuytr

网易考拉推荐

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

2014-08-10 11:11:39|  分类: Box2D |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

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

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

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

#import "Box2D.h"

 

class MyRayCastCallback : 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();

};

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

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

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

#import "Box2D.h"

 

@interface RayCastResult : NSObject

 

-(id)initWithFixture:(b2Fixture*) fixture

                point:(b2Vec2) point

               normal:(b2Vec2) normal

             fraction:(float32) fraction;

 

@property b2Fixture* fixture;

@property b2Vec2 point;

@property b2Vec2 normal;

@property float32 fraction;

 

@end

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

类的定义(实现)如下:

#import "RayCastResult.h"

 

@implementation RayCastResult

 

@synthesize fixture;

@synthesize point;

@synthesize normal;

@synthesize fraction;

 

-(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;

}

 

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

    if (resultFlag) {

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

    } else {

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

    }

    return 1;

}

 

void MyRayCastCallback::ClearResults() {

    [results removeAllObjects];

    [endResults removeAllObjects];

}

 

void MyRayCastCallback::ResetFlag() {

    resultFlag = !resultFlag;

}

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

 

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

MyRayCastCallback rayCastCallback;

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

-(void)doRayCast {

    rayCastCallback.ClearResults();

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

    rayCastCallback.ResetFlag();

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

    rayCastCallback.ResetFlag();

}

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

正常情况下,我们希望在每次拖拽出切割线并松开后来执行射线投射的计算,因此应该在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);

    }

}

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

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

-(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个多边形):

【原创】Box2D中切割刚体效果的实现一览(二) - 远行的风 - 风的驿站

 

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

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

  评论这张
 
阅读(75)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017