博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
cocos2d-x for wp 之Box2D的应用
阅读量:5126 次
发布时间:2019-06-13

本文共 8233 字,大约阅读时间需要 27 分钟。

本文大部分内容是基于fengyun1989的博文,自己只是加深巩固而已

Box2d是一款用于2d游戏的物理引擎。在这个世界里创造出的物体都更接近于真实世界的物体。

首先,在项目添加Box2D.XNA.DLL。

新建一个页面BOX2DLayer并继承于CCLayer

重写init函数,并添加下面这个常量:

由于平时我们都是用像素来描述游戏世界的,而在box2d里是用“米”进行描述的。所以我们需要进行转化单位。设置一个常量,然后在需要的位置上用像素除以它就可以转化成相对应的“米”

public static double PTM_RATIO = 32.0;

 

接下来就是开始创造世界了。

Vector2 gravity = new Vector2(30.0f, 0.0f); bool doSleep = true; world = new World(gravity, doSleep);

首先我们需要模拟出一个重力gravity。这里用一个2维矢量模拟重力并设置了一个值doSleep,用以指明对象不参与碰撞时,是否可以“休眠”。一个休眠的对象将不会花费处理时间,直到它与其实对象发生碰撞的时候才会“醒”过来。

这里说明一下物理世界的重力向量gravity。两个参数分别表示物理世界中的X轴和Y轴方向上的重力数值。“+” “-”表示重力的方向

X轴正值表示向右,Y轴正值表示向上

 

接下来,该是为这个世界添加一些物体的时候了。

我在Android关于box2d应用中看到关于world创建一个物体的步骤:

1.创建物体皮肤 PolygonDef

2.创建物体刚体BodyDef

3.通过皮肤和刚体创建一个物体 body (body=body.createBody(BodyDef )body.createShape(PolygonDef))

 在wp里略有不同。

BodyDef ballBodyDef = new BodyDef();            ballBodyDef.type = BodyType.Dynamic;//动态类型            ballBodyDef.position=new Vector2((float)(100/PTM_RATIO),(float)(300/PTM_RATIO));            ballBodyDef.userData=ball;            body=world.CreateBody(ballBodyDef);            CircleShape circle=new CircleShape();            circle._radius=(float)(26.0/PTM_RATIO);            FixtureDef ballShapeDef=new FixtureDef();            ballShapeDef.shape=circle;            ballShapeDef.density=1.0f;//质量:0代表静态的物体,1代表运动物体            ballShapeDef.friction=0.0f;//摩擦            ballShapeDef.restitution=1.0f;//恢复力            body.CreateFixture(ballShapeDef);

首先一个BodyDef

接下来一个CircleShape

最后一个FixtureDef

相比Android的定义过程,不过是将PolygonDef换成了一个Shape,并将这个Shape付给一个Fixture,最后由这个fixture完成body的创建。

现在详细说明一下上面代码的含义:

我们指定body的类型为dynamic body。默认值是static body,那意味着那个body不能被移动也不会参与仿真。很明显,我们想让篮球参与仿真。

 设置body的user data属性为篮球精灵。你可以设置任何东西,但是,你设置成精灵会很方便,特别是当两个body碰撞的时候,你可以通过这个参数把精灵对象取出来,然后做一些逻辑处理。
这里使用了一个不同的shape类型--circle shape。
在这里,我们需要为这个fixture指定一些参数

其中,说明一下这个restitution(恢复力)。我们都知道,在物理世界是能量守恒的。而这个恢复力就是能量守恒的体现之一。如果设置为1,则物体在世界里的碰撞是完全弹性碰撞。我们也把球的摩擦力设置为0.这样可以防止球在碰撞的时候,由于摩擦损失能量,导致来回碰撞的过程中会有一点点偏差。 

 

接下来,我们必须为我们的世界设置一个围墙,免得球跳出了“屏幕”

View Code
BodyDef groundBodyDef = new BodyDef();            groundBodyDef.position = new Vector2(0, 0);            Body groundBody = world.CreateBody(groundBodyDef);            PolygonShape groundBox = new PolygonShape();//凸多边形            FixtureDef boxShapeDef = new FixtureDef();            boxShapeDef.shape = groundBox;            groundBox.SetAsEdge(new Vector2(0, 0), new Vector2((float)(winSize.width / PTM_RATIO), 0));            groundBody.CreateFixture(boxShapeDef);            groundBox.SetAsEdge(new Vector2(0, 0), new Vector2(0, (float)(winSize.height / PTM_RATIO)));            groundBody.CreateFixture(boxShapeDef);            groundBox.SetAsEdge(new Vector2(0, (float)(winSize.height / PTM_RATIO)),                 new Vector2((float)(winSize.width / PTM_RATIO), (float)(winSize.height / PTM_RATIO)));            groundBody.CreateFixture(boxShapeDef);            groundBox.SetAsEdge(new Vector2((float)(winSize.width / PTM_RATIO), (float)(winSize.height / PTM_RATIO)),                new Vector2((float)(winSize.width / PTM_RATIO), 0));            groundBody.CreateFixture(boxShapeDef);

详细解释一下上面的代码:

首先创建一个body定义结构体,并且指定它应该放在左下角。

然后,使用world对象来创建body对象。(注意,这里一定要使用world对象来创建,不能直接new,因为world对象会做一些内存管理操作。)
 接着,为屏幕的每一个边界创建一个多边形shape。这些“shape”仅仅是一些线段。注意,我们把像素转换成了“meter”。通过除以之前定义的比率来实现的。
 再创建一个fixture定义,指定shape为polygon shape。
 再使用body对象来为每一个shape创建一个fixture对象。
注意:一个body对象可以包含许许多多的fixture对象。

在完成上面之后。我们只是定义了物理世界,还没开始进行物理模拟。所以还要对world设置物理模拟:

world.Step(dt, 10, 10);

此函数表示让物理世界开始进行物理模拟,后两个参数含义分别是“速度迭代次数”和“位置迭代次数”。设置他们的范围在8-10之间。

这里的数字越小,精度越小,但是效率更高。数字越大,仿真越精确,但同时耗时更多。8一般是个折中数值。

 

这里要注意,因为物理世界模拟具有持续性,所以应该将设置放在线程中,不断让物理世界进行模拟。

在init()里添加一个this.schedule(tick)。这里的tick就是一个“线程”

在tick里除了添加物理模拟之外,我们要使我们的小球精灵匹配物理仿真。因此,我们遍历world对象里面的所有body,然后看body的user data属性是否为空,如果不为空,就可以强制转换成精灵对象。接下来,就可以根据body的位置来更新精灵的位置了。

View Code
for (Body b = world.GetBodyList(); b != null; b = b.GetNext())            {                if (b.GetUserData() != null)                {                    CCSprite ballData = (CCSprite)b.GetUserData();                    ballData.position = new CCPoint((float)(b.GetPosition().X * PTM_RATIO),                    (float)(b.GetPosition().Y * PTM_RATIO));                    ballData.rotation = -1 * MathHelper.ToDegrees(b.GetAngle());                }            }

最后在AppDelegate.cs里面的applicationDidFinishLaunching修改场景入口就可以看到效果了。

附上所有代码:

View Code
1 class BOX2DLayer:CCLayer 2     { 3         //定义了一个“像素/米”的比率。当你在cocos2d里面指定一个body在哪个位置时,你使用的单位要是米 4         public static double PTM_RATIO = 32.0; 5  6         World world; 7         Body body; 8         CCSprite ball; 9 10         public override bool init()11         {12             if (!base.init())13                 return false;14             //获取窗口大小15             CCSize winSize = CCDirector.sharedDirector().getWinSize();16 17             CCLabelTTF title = CCLabelTTF.labelWithString("Boxing", "Arial", 24);18             title.position = new CCPoint(winSize.width / 2, winSize.height / 2 - 50);19             this.addChild(title, 1);20 21             ball = CCSprite.spriteWithFile("images/ball");22             ball.position = new CCPoint(0, 300);23             this.addChild(ball);24 25             26          Vector2 gravity = new Vector2(30.0f, 0.0f);27             bool doSleep = true;28             world = new World(gravity, doSleep);29 30             BodyDef groundBodyDef = new BodyDef();31             groundBodyDef.position = new Vector2(0, 0);32             Body groundBody = world.CreateBody(groundBodyDef);33             PolygonShape groundBox = new PolygonShape();//凸多边形34             FixtureDef boxShapeDef = new FixtureDef();35             boxShapeDef.shape = groundBox;36             groundBox.SetAsEdge(new Vector2(0, 0), new Vector2((float)(winSize.width / PTM_RATIO), 0));37             groundBody.CreateFixture(boxShapeDef);38             groundBox.SetAsEdge(new Vector2(0, 0), new Vector2(0, (float)(winSize.height / PTM_RATIO)));39             groundBody.CreateFixture(boxShapeDef);40             groundBox.SetAsEdge(new Vector2(0, (float)(winSize.height / PTM_RATIO)), 41                 new Vector2((float)(winSize.width / PTM_RATIO), (float)(winSize.height / PTM_RATIO)));42             groundBody.CreateFixture(boxShapeDef);43             groundBox.SetAsEdge(new Vector2((float)(winSize.width / PTM_RATIO), (float)(winSize.height / PTM_RATIO)),44                 new Vector2((float)(winSize.width / PTM_RATIO), 0));45             groundBody.CreateFixture(boxShapeDef);46 47             BodyDef ballBodyDef = new BodyDef();48             ballBodyDef.type = BodyType.Dynamic;//动态类型49          ballBodyDef.position=new Vector2((float)(100/PTM_RATIO),(float)(300/PTM_RATIO));50             ballBodyDef.userData=ball;51 52             body=world.CreateBody(ballBodyDef);53             CircleShape circle=new CircleShape();54             circle._radius=(float)(26.0/PTM_RATIO);55 56             FixtureDef ballShapeDef=new FixtureDef();57             ballShapeDef.shape=circle;58             ballShapeDef.density=1.0f;//质量:0代表静态的物体,1代表运动物体59          ballShapeDef.friction=0.0f;//摩擦60          ballShapeDef.restitution=1.0f;//恢复力61          body.CreateFixture(ballShapeDef);62 63             64             this.schedule(tick);65             return true;66         }67 68         void tick(float dt)69         {70             world.Step(dt, 10, 10);71 72             for (Body b = world.GetBodyList(); b != null; b = b.GetNext())73             {74                 if (b.GetUserData() != null)75                 {76                     CCSprite ballData = (CCSprite)b.GetUserData();77                     ballData.position = new CCPoint((float)(b.GetPosition().X * PTM_RATIO),78                     (float)(b.GetPosition().Y * PTM_RATIO));79                     ballData.rotation = -1 * MathHelper.ToDegrees(b.GetAngle());80                 }81             }82         }83 84         public static new CCLayer node()85         {86             BOX2DLayer layer = new BOX2DLayer();87             if (layer.init())88             {89                 return layer;90             }91             else92                 layer = null;93             return layer;94         }95 96     }

 

 

 

 

转载于:https://www.cnblogs.com/dieaz5/archive/2013/03/23/2977723.html

你可能感兴趣的文章
用户空间与内核空间,进程上下文与中断上下文[总结]
查看>>
JAVA开发环境搭建
查看>>
Visual Studio基于CMake配置opencv1.0.0、opencv2.2
查看>>
SDN第四次作业
查看>>
django迁移数据库错误
查看>>
Data truncation: Out of range value for column 'Quality' at row 1
查看>>
字符串处理
查看>>
HtmlUnitDriver 网页内容动态抓取
查看>>
ad logon hour
查看>>
罗马数字与阿拉伯数字转换
查看>>
Eclipse 反编译之 JadClipse
查看>>
距离公式汇总以及Python实现
查看>>
Linux内核态、用户态简介与IntelCPU特权级别--Ring0-3
查看>>
第23月第24天 git命令 .git-credentials git rm --cached git stash clear
查看>>
java SE :标准输入/输出
查看>>
[ JAVA编程 ] double类型计算精度丢失问题及解决方法
查看>>
好玩的-记最近玩的几个经典ipad ios游戏
查看>>
PyQt5--EventSender
查看>>
Sql Server 中由数字转换为指定长度的字符串
查看>>
tmux的简单快捷键
查看>>