Box2d弹性物体的制作

news/2024/7/20 10:15:34 标签: IOS, box2d, 程序设计


这次我们来使用Box2d框架制作具有一定弹性的物体。这里我们说的弹性物体,不是指物体碰撞到其他物体后反弹的这种特性,而是指物体的外形在受到外力作用的时候会发生形变,比如我们小时候玩儿的弹力球。那么这里就有一个有意思的地方,我们知道在Box2d中,所有的物体都是“刚体”,刚体就是不会发生弹性形变的物体,那么不是矛盾了么?所以这里我们所得具有弹性的物体,实际上并不是一个物体,而是一系列刚体组成的一个物体。

好了,不多说废话了,下面就开始制作。

我们先看一下运行的效果截图:


我们要制作的就是这种具有一定弹性的环形物体(或者说球状物体)。

原理比较简单,我们可以看到,图中的环形物体实际上是由很多个小的梯形连接组成的,相邻的两个梯形物体通过关节进行连接,如下图所示:


相邻的两个梯形物体具有两个相邻的顶点,这两个顶点都使用具有固定作用的关节进行连接才能使两个物体形成一定的弹力效果,假如上图中我们去掉上面或者下面的关节,那么只有一个关节存在的时候,可以想象整个环形物体就会像下面这样松垮掉:


说道“具有固定作用的关节”,我指的就是能够将两个关节上的两个点固定在一起的关节,例如b2RevoluteJoint,b2WeldJoint,b2DistanceJoint。我们利用相邻的物体要脱离关节的约束时关节产生的反作用力,来体现出弹性的效果。

既然上面的三种约束都有固定的作用,我们分别试一下看看有什么效果。首先来看b2DistanceJoint的效果:


截图中我们看到下落的时候还好(其实在运行的时候,下落过程每个梯形物体都会发生剧烈抖动,感觉整个环要散开的样子),下落到地面后,就坍塌在了一起。这个现象其实比较容易理解,虽然b2DistanceJoint限制了两个相邻的梯形的相邻顶点的距离,但是并没有对彼此有任何自由度(旋转,平移)的限制,因此在发生抖动的时候,就没有任何规律最后塌陷在一起的时候,两边的梯形同时也产生了折叠的效果(折叠之后依然满足距离的限制)。

接着我们再来看b2WeldJoint:


可以看到效果要比b2DistanceJoint好很多,之后在碰撞的过程中,相邻的梯形之间会产生微小的毛边。尽管b2WeldJoint限制了物体的两个自由度,但是由于受力仍然会导致焊接有一些脱落。

最后的b2RevoluteJoint的效果就和我们最开始的截图一样,在收到剧烈碰撞的时候,当整个环被压得比较扁的时候,两侧的相邻梯形会有折叠的效果,但是很快就会恢复:


 

比较三种效果,我更倾向于使用b2RevoluteJoint,当环的段数越多的时候,最后一种的效果越平滑。

下面我们给出具体的代码实现。

Box2d的版本是2.3.1,关于创建工程等初始化的步骤这里就不再提了(之前的Box2d的博文中反复提过了),我们在HelloWorldLayer中添加下面的方法:

-(void)createSoftObject:(int) edgeCount center:(CGPoint) center {

   //物体的中心点

   b2Vec2 centerVec = [self toVec2:center];

   

   //根据多边形的边数来计算每一条边对应的圆心角的大小

   //然后我们根据圆心角的正弦和余弦来计算这一圈物体的顶点坐标

   float angleBase = 360.0f / edgeCount;

   

   //相邻的两个物体之间需要创建关节,因此用previousBody来记录前一个物体

   b2Body* previousBody = nil;

   //最后要把第一个物体和最后一个物体用关节连接,因此要保存第一个物体

   b2Body* firstBody = nil;

   //环的外半径

   float r1 = 60;

   //环的内半径

   float r2 = r1 - 5;

   

   for (int i = 0; i < edgeCount; i++) {

       //计算第i个梯形物体的4个顶点的坐标

       b2Vec2* vertexes = [selfcalculateVertexesWithIndex:i angleBase:angleBase edgeCount:edgeCountradiusOutside:r1 radiusInside:r2];

       //两个用来创建关节的顶点的世界坐标

       b2Vec2 revoluteJointPoint(centerVec.x +vertexes[0].x, centerVec.y + vertexes[0].y);

       b2Vec2 revoluteJointPoint1(centerVec.x+ vertexes[1].x, centerVec.y + vertexes[1].y);

       

       //定义物体

       b2BodyDef bodyDef;

       bodyDef.position = [selftoVec2:center];

       bodyDef.type = b2_dynamicBody;

       b2Body* body =world->CreateBody(&bodyDef);

       

       //创建形状

       b2PolygonShape* shape = newb2PolygonShape();

       shape->Set(vertexes, 4);

       

       //创建fixture

       b2FixtureDef fixtureDef;

       fixtureDef.density = 1;

       fixtureDef.friction = 0.3f;

       fixtureDef.shape = shape;

       body->CreateFixture(&fixtureDef);

       

       //如果前一个物体为nil,则说明是第一个物体,将其记录,如果不为nil,则将当前物体与之相连

       if (previousBody != nil) {

           [selfcreateRevoluteJoint:previousBody anotherBody:bodyjointPoint:revoluteJointPoint];

           [selfcreateRevoluteJoint:previousBody anotherBody:bodyjointPoint:revoluteJointPoint1];

       } else {

           firstBody = body;

       }

       

       previousBody = body;

   }

   

   //最后将第一个物体与最后一个物体连接起来

   b2Vec2* vertexes = [selfcalculateVertexesWithIndex:0 angleBase:angleBase edgeCount:edgeCountradiusOutside:r1 radiusInside:r2];

   b2Vec2 revoluteJointPoint(centerVec.x +vertexes[0].x, centerVec.y + vertexes[0].y);

   b2Vec2 revoluteJointPoint1(centerVec.x +vertexes[1].x, centerVec.y + vertexes[1].y);

   [self createRevoluteJoint:previousBodyanotherBody:firstBody jointPoint:revoluteJointPoint];

   [self createRevoluteJoint:previousBodyanotherBody:firstBody jointPoint:revoluteJointPoint1];

}

上面的方法用来创建环形物体,算法很简单,通过内半径,外半径以及圆心角来计算每个梯形物体的4各点的坐标,然后创建物体和关节,方法中已经做了详细的注释。上面的方法中涉及到的两个方法如下:

-(b2Vec2*)calculateVertexesWithIndex:(int) index

                           angleBase:(float)angleBase

                           edgeCount:(int)edgeCount

                       radiusOutside:(float)r1

                        radiusInside:(float)r2 {

   b2Vec2* vertexes = new b2Vec2[4];

   float angle1 =CC_DEGREES_TO_RADIANS(angleBase * index);

   float angle2 =CC_DEGREES_TO_RADIANS(angleBase * ((index+1)%edgeCount));

   

   float x1 = sinf(angle1) * r1;

   float y1 = cosf(angle1) * r1;

   vertexes[0] = [self toVec2:ccp(x1, y1)];

   

   float x2 = sinf(angle1) * r2;

   float y2 = cosf(angle1) * r2;

   vertexes[1] = [self toVec2:ccp(x2, y2)];

   

   float x3 = sinf(angle2) * r2;

   float y3 = cosf(angle2) * r2;

   vertexes[2] = [self toVec2:ccp(x3, y3)];

   

   float x4 = sinf(angle2) * r1;

   float y4 = cosf(angle2) * r1;

   vertexes[3] = [self toVec2:ccp(x4, y4)];

   

   return vertexes;

}

 

-(void)createRevoluteJoint:(b2Body*) body1 anotherBody:(b2Body*) body2jointPoint:(b2Vec2) jointPoint {

   b2RevoluteJointDef jointDef;

   jointDef.Initialize(body1, body2,jointPoint);

   world->CreateJoint(&jointDef);

}

最后在这些代码都添加好之后,我们利用默认的addNewSpriteAtPosition方法,将其清空,替换为下面的代码即可:

[selfcreateSoftObject:32 center:p];

编译,运行,当我们点击屏幕的时候,就能以点击的位置为中心创建具有弹性的环状物体了。

注:还有一个bug尚未解决,就是环形物体之间有可能出现穿插的现象,如果有感兴趣的朋友欢迎一起研究~~



http://www.niftyadmin.cn/n/878457.html

相关文章

空投-更好用的文件传输方案

空投-更好用的文件传输方案 推荐过不少跨设备传输文件的解决方案&#xff0c;主要是 Web 平台&#xff08;经常来博客的朋友都知道我是一个 Web Yes 党&#xff09;&#xff0c;今天也不例外&#xff0c;推荐一个好看又好用的文件传输平台-空投。 空投AirPortal 空投是由网友…

python的链表操作_使用python实现链表操作

使用python实现链表操作发布时间&#xff1a;2020-08-25 23:24:34来源&#xff1a;脚本之家阅读&#xff1a;107一、概念梳理链表是计算机科学里面应用应用最广泛的数据结构之一。它是最简单的数据结构之一&#xff0c;同时也是比较高阶的数据结构(例如棧、环形缓冲和队列)简单…

使用Box2d实现物体在液体中的漂浮效果(一)

&#xfeff;&#xfeff;今天我们来学习使用Box2d物理引擎制作物体在液体中的漂浮效果&#xff0c;没有新的技术&#xff0c;只是综合运用了以前博文中介绍过的技术。 注&#xff1a;如果使用Box2d flash的版本&#xff0c;可以直接使用buoyancycontroller来实现本文制作的效…

免费好用的文字转语音工具

自媒体可能是现在最火的东西&#xff0c;自媒体中最火的又是短视频&#xff0c;各家短视频平台都有简单好用的剪辑软件方便新手能轻松上手&#xff0c;但是语音这块的话却没有很好的解决办法&#xff0c;大部分需要真人出声或是拙劣的 AI 配音&#xff0c;但是像我这种普通话不…

使用Box2d实现物体在液体中的漂浮效果(二)

&#xfeff;&#xfeff;我们继续来制作物体在液体中的漂浮效果。 我们来考虑物体和液体的三种位置关系&#xff1a; 1. 物体完全离开液体 2. 物体一部分浸入液体 3. 物体完全浸入液体。 针对这三种位置关系&#xff0c;我们有下面三种结论&#xff1a; 1. …

当前可用的喜马拉雅专辑下载器

之前分享过不少下载喜马拉雅音频或专辑的工具&#xff0c;但是都一一失效了&#xff0c;找和分享都赶不上失效的快&#xff0c;索性就停了一段时间。但是老用车机和手机听歌也不是那么回事&#xff0c;多多少少还是想听点故事评书什么的&#xff0c;所以今天就又花了点时间&…

连接池配置_HikariCP被号称为性能最好的Java数据库连接池,如何配置使用?

公众号关注 “GitHub今日热榜”设为 “星标”&#xff0c;带你挖掘更多开发神器&#xff01;HiKariCP是数据库连接池的一个后起之秀&#xff0c;号称性能最好&#xff0c;可以完美地PK掉其他连接池。为何要使用HiKariCP&#xff1f;这要先从BoneCP说起&#xff1a;什么&#xf…

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

&#xfeff;&#xfeff;首先推荐一款好玩儿的物理益智游戏“CrayonPhysics”&#xff0c;中文名叫“蜡笔物理学”&#xff08;当然不是做广告哈哈&#xff09;&#xff0c;游戏中我们通过手工绘制各种各样的“物体”来让一个红色的小球吃掉星星。整个游戏都是蜡笔画的风格&am…