5

服务器端Box2D入门

 3 years ago
source link: https://www.lanindex.com/%e6%9c%8d%e5%8a%a1%e5%99%a8%e7%ab%afbox2d%e5%85%a5%e9%97%a8/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

服务器端Box2D入门

2017/02/18 · Leave a comment

Box2D是一个用于游戏的2D刚体仿真库。它的核心目的是为了模拟真实的2D环境,让物体运动更加真实,交互性更好。本文主要介绍一些使用Box2D的基础知识,并且记录如何在没有图形化界面的Linux服务器上使用它。(例子就是我使用的这台:D)。

开始准备安装Box2D

github地址:https://github.com/erincatto/Box2D

$git clone https://github.com/erincatto/Box2D

完成之后因为没有图形化界面,去CMakeCache.txt中把BOX2D_BUILD_EXAMPLES设置从ON改成OFF

$cd Box2D/Box2D/Build/ && vim CMakeCache.txt

然后用cmake创建makefile,这里如果有库的缺失补全一下就可以了

$cmake ..

然后直接make会有一处编译错误,找到地方把”nullptr”改成”NULL”或者0

$make
$sudo make install
$locate Box2D

最后使用locate Box2D查看Box2D的安装情况,默认是在/usr/local/相关目录,至此安装完毕。

一些基础知识

世界(world)

虚拟化的物理时间,里面包含了各类刚体的演算。

刚体(rigid body)

最基础的单位,代表一个不会发生形变的实体,我们通常用body来指代刚体。

夹具(fixture)

个人喜欢叫它为材质,依附在刚体上,约束刚体的形状(shape),密度(density),摩擦(friction),恢复(restitution)等特性。

单位

使用米-千克-秒(MKS)单位制。

一个无重力环境的2D场景,正方形40mx40m,正方形边是厚2m的静态围墙,正方形的中心是世界中心;

有bodyA(正方形2mx2m,坐标-10.0f, 10.0f)与bodyB(正方形2mx2m,坐标10.0f, 10.0f),对A施加一个向右的力,对B施加一个向左的力;

示意图:

Box2D一

详细的释义直接附加在代码里:

//file:myBox2D.cpp
#include <stdint.h>;
#include <stdio.h>;
#include <Box2D/Box2D.h>;
int32_t main()
{
//创建世界
b2Vec2 gravity(0.0f, -0.0f);  //无重力,若要设置自然重力为(0.0f, -9.8f)
b2World world(gravity);
world.SetAllowSleeping(false);  //静止的物理也会参与碰撞检测
//构建一个边长40m正方形
//创建下面围墙
b2BodyDef wall;
b2PolygonShape wallBox;
wall.type = b2_staticBody;
wall.position.Set(0.0f, -1.0f);
b2Body *wallDown = world.CreateBody(&wall);
//下面围墙的形状
wallBox.SetAsBox(20.0f, 1.0f);
//设置材质
wallDown->CreateFixture(&wallBox, 0.0f);
//创建上面围墙
wall.position.Set(0.0f, 21.0f);
b2Body *wallUp = world.CreateBody(&wall);
//上面围墙的形状
wallBox.SetAsBox(20.0f, 1.0f);
//设置材质
wallUp->CreateFixture(&wallBox, 0.0f);
//创建左面的围墙
wall.position.Set(-21.0f, 20.0f);
b2Body *wallLeft = world.CreateBody(&wall);
//左面围墙的形状
wallBox.SetAsBox(1.0f, 20.0f);
wallLeft->CreateFixture(&wallBox, 0.0f);
//创建右面的围墙
wall.position.Set(21.0f, 20.0f);
b2Body *wallRight = world.CreateBody(&wall);
//右面围墙的形状
wallBox.SetAsBox(1.0f, 20.0f);
wallRight->CreateFixture(&wallBox, 0.0f);
//创建二个动态的body
b2BodyDef bodyDefA;
bodyDefA.type = b2_dynamicBody;
bodyDefA.position.Set(-10.0f, 10.0f);
b2Body *bodyA = world.CreateBody(&bodyDefA);
b2BodyDef bodyDefB;
bodyDefB.type = b2_dynamicBody;
bodyDefB.position.Set(10.0f, 10.0f);
b2Body *bodyB = world.CreateBody(&bodyDefB);
//为这个动态bodyA设置形状
b2PolygonShape dynamicBox;
dynamicBox.SetAsBox(1.0f, 1.0f);
//为这个动态body设置材质
b2FixtureDef fixtureDef;
fixtureDef.shape = &dynamicBox;
fixtureDef.density = 1.0f; //密度
fixtureDef.friction = 0.3f; //摩擦系数
fixtureDef.restitution = 1.0f; //恢复系数
bodyA->CreateFixture(&fixtureDef);
bodyB->CreateFixture(&fixtureDef);
//施加一点力
bodyA->ApplyLinearImpulse(b2Vec2(10, 0), bodyA->GetWorldCenter(), true);
bodyB->ApplyLinearImpulse(b2Vec2(-10, 0), bodyB->GetWorldCenter(), true);
//迭代的时间间隔,这里是1秒60次
float32 timeStep = 1.0f / 60.0f;
int32 velocityIterations = 6; //碰撞时速度迭代
int32 positionIterations = 2; //碰撞时位置迭代
for (int32 i = 0; i < 600; ++i) {
world.Step(timeStep, velocityIterations, positionIterations);
b2Vec2 positionA = bodyA->GetPosition();
float32 angleA = bodyA->GetAngle();
printf("A %4.2f %4.2f %4.2f\n", positionA.x, positionA.y, angleA);
b2Vec2 positionB = bodyB->GetPosition();
float32 angleB = bodyB->GetAngle();
printf("B %4.2f %4.2f %4.2f\n", positionB.x, positionB.y, angleB);
for (b2Contact* c = world.GetContactList(); c; c = c->GetNext()) {
b2Body *A = c->GetFixtureA()->GetBody();
b2Body *B = c->GetFixtureB()->GetBody();
b2Vec2 positionA = A->GetPosition();
float32 angleA = A->GetAngle();
b2Vec2 positionB = B->GetPosition();
float32 angleB = B->GetAngle();
printf("b2Contact A:%4.2f %4.2f %4.2f|B:%4.2f %4.2f %4.2f\n",
positionA.x, positionA.y, angleA, positionB.x, positionB.y, angleB);
}
}
return 0;
}

编译后可查看效果

$g++ -o test myBox2D.cpp -lBox2D
$./test

关于代码的一些解释

b2BadyDef的type类型:

b2_staticBody:静态物理,质量无穷大,不会因为碰撞移动;不会和其它static或kinematic物体相互碰撞,例如上面样例的围墙;

b2_kinematicBody:可以行动的、质量无穷大的;

b2_dynamicBody:可以受力运动,也可以根据用户指令固定移动;拥有完整的fixtures各种特性;

关于fixtures:

形状(shape),密度(density),摩擦(friction)从字面意思就比较好理解了,说一下恢复(restitution):

官方文档给的释义:恢复可以使对象弹起。恢复的值通常设置在0到1之间。想象一个小球掉落到桌子上,值为0表示着小球不会弹起, 这称为非弹性碰撞。值为1表示小球的速度跟原来一样,只是方向相反,这称为完全弹性碰撞。

若2个均有restitution的刚体碰撞,那么取最大的restitution作为最终计算值。

关于施加力:

ApplyForce:增加力;

ApplyLinearImpulse:增加冲量;具体怎么换算为速度未知,同等单位下,相同时间比ApplyForce运动的更远;

ApplyTorque:角力矩;

ApplyAngularImpulse:角动量;

SetTransform:瞬移物体;

关于迭代:

时间迭代:可以抽象成帧的概念,比如我们需要一秒60帧那么就是float32 timeStep = 1.0f / 60.0f;

碰撞时速度、碰撞时位置迭代:核心是用来检测碰撞物体的相对位置,以及碰撞后的位移;如果值太小,会出现一个物理运动另外一个物理“内部”再碰撞;值越高就越接近真实物理,当然运算负载也越大;

个人觉得Box2D在接口设计上面非常合理,迭代逻辑与业务的主逻辑契合比较紧密(基于帧的概念),看后续有没有机会继续深入使用,若有使用还会更新进阶篇。

(全文结束)

转载文章请注明出处:漫漫路 - lanindex.com

Leave a Comment Cancel reply

Your email address will not be published.

在此浏览器中保存我的名字、电邮和网站。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK