教你使用Box2d制作用蜡笔手绘物体的效果(一)

103 篇文章 0 订阅
53 篇文章 0 订阅


首先推荐一款好玩儿的物理益智游戏“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];

}

即如果我们在屏幕上点击而不是绘制路径的话,那么会创建一个固定的圆形物体,再来做一下测试:


可以看到可以通过简单的组合实现钟摆效果,增加了很多的趣味性~

好了这样我们就完成了第一部分的工作,下一篇中我们来实现蜡笔纹理的制作。


  • 84
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Box2D-js是Box2D物理引擎的JavaScript端口,可以在Vue中使用。你需要先安装Box2D-js库。你可以通过npm安装,使用以下命令: ``` npm install box2d-js ``` 然后在Vue组件中使用Box2D-js,你需要引入Box2D-js库并创建Box2D世界。以下是一个简单的示例: ```html <template> <div> <canvas ref="canvas" width="800" height="600"></canvas> </div> </template> <script> import { b2Vec2, b2World, b2BodyDef, b2BodyType, b2PolygonShape, b2FixtureDef } from 'box2d-js' export default { mounted() { const canvas = this.$refs.canvas const ctx = canvas.getContext('2d') // 创建Box2D世界 const gravity = new b2Vec2(0, 10) const world = new b2World(gravity) // 创建地面刚体 const groundBodyDef = new b2BodyDef() groundBodyDef.position.Set(400 / 30, 550 / 30) const groundBody = world.CreateBody(groundBodyDef) const groundShape = new b2PolygonShape() groundShape.SetAsBox(400 / 30, 10 / 30) const groundFixtureDef = new b2FixtureDef() groundFixtureDef.shape = groundShape groundFixtureDef.density = 0 groundFixtureDef.friction = 0.5 groundFixtureDef.restitution = 0.2 groundBody.CreateFixture(groundFixtureDef) // 创建方块刚体 const boxBodyDef = new b2BodyDef() boxBodyDef.type = b2BodyType.b2_dynamicBody boxBodyDef.position.Set(200 / 30, 50 / 30) const boxBody = world.CreateBody(boxBodyDef) const boxShape = new b2PolygonShape() boxShape.SetAsBox(50 / 30, 50 / 30) const boxFixtureDef = new b2FixtureDef() boxFixtureDef.shape = boxShape boxFixtureDef.density = 1 boxFixtureDef.friction = 0.5 boxFixtureDef.restitution = 0.2 boxBody.CreateFixture(boxFixtureDef) // 模拟世界 setInterval(() => { world.Step(1 / 60, 10, 10) ctx.clearRect(0, 0, canvas.width, canvas.height) // 绘制地面 ctx.beginPath() ctx.moveTo(0, 550) ctx.lineTo(800, 550) ctx.stroke() // 绘制方块 ctx.save() ctx.translate(boxBody.GetPosition().x * 30, boxBody.GetPosition().y * 30) ctx.rotate(boxBody.GetAngle()) ctx.fillRect(-50, -50, 100, 100) ctx.restore() }, 1000 / 60) } } </script> ``` 这个示例创建了一个Box2D世界并在Canvas上绘制了一个方块和地面。你可以根据自己的需求修改这个示例。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值