首先推荐一款好玩儿的物理益智游戏“CrayonPhysics”,中文名叫“蜡笔物理学”(当然不是做广告哈哈),游戏中我们通过手工绘制各种各样的“物体”来让一个红色的小球吃掉星星。整个游戏都是蜡笔画的风格,手绘物体的游戏体验非常棒。下面是游戏的截图:
如果你喜欢这类清新的益智游戏,可以下载玩一玩,以便对我们这个教程有更好的理解。好了,我们言归正传,开始使用Box2d来制作这种手绘蜡笔风的刚体。
为了避免篇幅过于冗长,我把教程分成了两部分,前一部分我们来制作手绘刚体的效果,后一部分我们为刚体添加上蜡笔的纹理效果。
首先,我们以cocos2d iOS withBox2d为模板创建Box2d工程(本文使用的是Box2d2.3.1版本),默认Box2d的demo工程会实现ccTouchesBegan方法,当我们点击屏幕任何地方的时候会向场景中添加盒子对象。我们将这部分代码注释掉,另外再将初始化函数中添加menu的方法也都给注释掉(如果你觉得还有什么别的代码碍事的话,一并都给注释掉就好了),留下一个空白的(或者说全黑的)场景供我们开发即可。
我们首先来实现记录绘制路径以及将绘制的路径显示在屏幕上的代码,这部分的实现方法请参考Box2d中使用开源的PRKit库来制作任意形状的多边形刚体的纹理。
接着我们利用取样取到的节点来创建刚体。
我们在HelloWorldLayer中添加下面的方法:
-(void) createPathPolygon {
CGPoint start =[pathVertexes[0] CGPointValue]; //路径起点
b2BodyDef bodyDef;
bodyDef.type =b2_dynamicBody;
bodyDef.position = [selftoVec2:start]; //以路径起点为定义物体位置
b2Body* body =world->CreateBody(&bodyDef); //创建物体
int vertexCount = [pathVertexes count];
//遍历除最后一个节点之外的所有节点
for (int i = 0; i < vertexCount - 1; i++) {
//第i个节点为线段的起点
CGPoint segStart =[pathVertexes[i] CGPointValue];
//第i+1个节点为线段的终点
CGPoint segEnd =[pathVertexes[i+1] CGPointValue];
//线段的中点
CGPoint center =ccpMidpoint(segStart, segEnd);
//线段的初始角度
float32 angle =-ccpAngleSigned(ccpSub(segEnd, segStart), ccp(1.0f, 0.0f));
//定义一个长度等于线段长度,宽度为3px的矩形多边形
b2PolygonShape* shape= new b2PolygonShape();
float32 segLength =ccpDistance(segStart, segEnd) * 0.5f + 0.5f;
shape->SetAsBox(segLength / PTM_RATIO, 3.0f / PTM_RATIO, [selftoVec2:ccpSub(center, start)], angle);
//以我们创建的矩形为形状创建fixture(我们的刚体最终就是由一系列的小矩形组合而成的
b2FixtureDeffixtureDef;
fixtureDef.density =2.0f;
fixtureDef.friction =0.3f;
fixtureDef.shape =shape;
body->CreateFixture(&fixtureDef);
}
}
定义好之后,我们在ccTouchEnded方法中添加调用:
-(void) ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event {
if ([pathVertexes count]> 1) {
[selfcreatePathPolygon];
}
[pathVertexesremoveAllObjects];
}
当定点数大于1的时候(至少要有两个顶点才能组成一条线段),沿路径创建刚体,运行效果如下:
这里我们设置的取样长度为10,如果觉得不够细腻,可以再减小取样长度,越小的取样长度得到的效果就越细腻,但是创建出来的物体也就会越复杂,资源消耗就会更多。
这里总结下大体的思路,我们在创建的时候绘制一条路径,然后在路径上相邻的节点之间创建一个矩形,将所有的矩形首尾相连就得到了绘制的刚体。
接着我们在HelloWorldLayer中再添加一个方法:
-(void) createSmallCircleAtPosition:(CGPoint) position {
b2BodyDef bodyDef;
bodyDef.type =b2_staticBody;
bodyDef.position = [selftoVec2:position];
b2Body* body =world->CreateBody(&bodyDef);
b2CircleShape shape;
shape.m_radius = 0.1f;
b2FixtureDef fixtureDef;
fixtureDef.shape =&shape;
fixtureDef.friction =0.4f;
body->CreateFixture(&fixtureDef);
}
这个方法比较简单,创建一个圆形的,半径为0.1米的静态刚体。
接着我们修改一下ccTouchEnded方法:
-(void) ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event {
if ([pathVertexes count]> 1) {
[selfcreatePathPolygon];
} else {
CGPoint location =[[CCDirector sharedDirector] convertToGL:[touch locationInView:[touch view]]];
[selfcreateSmallCircleAtPosition:location];
}
[pathVertexesremoveAllObjects];
}
即如果我们在屏幕上点击而不是绘制路径的话,那么会创建一个固定的圆形物体,再来做一下测试:
可以看到可以通过简单的组合实现钟摆效果,增加了很多的趣味性~
好了这样我们就完成了第一部分的工作,下一篇中我们来实现蜡笔纹理的制作。