Box2d源码分析(刚体)
概述中知道了什么是世界,如何模拟世界重力,以及时间步和另外两个参数的使用,以及意义。世界的存在,有了物体才可以更加的完美。
刚体就是世界中的物体,可以仿真各种物体,对世界中物体的操作基本 就是对刚体的操作。
1.刚体定义
2.创建并加入到世界中
3.刚体的形状
4.显示出刚体的调试视图
刚体
a rigid Body,一般的看到的万物的形状都可以看作是刚体,刚体也是学习的核心,可以用来模拟所有的物体,它可以模拟出碰撞、反弹、运动轨迹等各种物体现象模拟和数据都是基于刚体实现的,所以属性比较多,位置、速度、质量、反弹系数等。
创建刚体
创建刚体,不仅仅是创建一个刚体,还需要创建bodyDef和fixtureDef,共同创建出来。
- b2BodyDef:创建需要的信息
- b2Body:创建刚体
-
b2FixtureDef:创建刚体的信息。
对于刚体来说,包含的信息比较多以及自身的特性,所以需要创建一个b2BodyDef和b2FixtureDef。所以需要创建这两个,并成功的设置相关的属性。
image.png
image.png
上面只是刚体自身属性和外部属性,我们仍然使用Body来创建。
创建代码
BodyDef bodyDef = new BodyDef();
bodyDef.type = this.type;
bodyDef.position.set(getX(Align.center),getY(Align.center));
this.body = Constant.world.createBody(bodyDef);
if (shape == null){
PolygonShape polygonShape = new PolygonShape();
polygonShape.setAsBox(getWidth()/2 , getHeight()/2);
shape = polygonShape;
}
FixtureDef fixtureDef = new FixtureDef();
fixtureDef.shape = shape;
if (categoryBits != -1){
fixtureDef.filter.categoryBits = categoryBits;
}
if (maskBits != -1) {
fixtureDef.filter.maskBits = (short) maskBits;
}
fixtureDef.density = 100;
body.createFixture(fixtureDef);
shape.dispose();
body.setUserData(this);
源码分析世界创建body的过程。
long bodyAddr =
jniCreateBody(addr,
def.type.getValue(),
def.position.x,
def.position.y,
def.angle,
def.linearVelocity.x,
def.linearVelocity.y,
def.angularVelocity,
def.linearDamping,
def.angularDamping,
def.allowSleep,
def.awake,
def.fixedRotation,
def.bullet,
def.active,
def.gravityScale);
Body body = freeBodies.obtain();
body.reset(bodyAddr);
this.bodies.put(body.addr, body);
return body;
reset方法
protected void reset (long addr) {
this.addr = addr;
this.userData = null;
for (int i = 0; i < fixtures.size; i++)
this.world.freeFixtures.free(fixtures.get(i));
fixtures.clear();
this.joints.clear();
}
}
创建body,body有fixturedef和joints以及userData.;将他们清掉。
这个创建和c++创建有一些区别,等下面补充的时候在加。
夹具
fixture的使用,夹具是一个固定设施,用来定义一些属性,材料本身的特性,比如摩擦力、密度、质量等。它可以设置刚体的形状,如果没有形状是不可以进行碰撞模拟的。
一般的常见图形有园和矩形,还有一些简单的 。对于fixtureDef只是短暂停的存储,它里面有属性fixture,我没让你创建的时候也是将数据在复制到fixture。并且fixtrue必须依附在刚体上才可以有作用,比如你的躯体脱离了你这个人,只是一个行尸走肉,并没有什么用户,一个刚体可以包含不止一个。
比如一个人,头部的硬度和肚子的硬度反弹系数不同,我们就需要创建两个。也就说刚体创建之后可以对其在增加fixture,实现形状的组合
FixtureDef fixtureDef = new FixtureDef();
fixtureDef.shape = shape;
if (categoryBits != -1){
fixtureDef.filter.categoryBits = categoryBits;
}
if (maskBits != -1) {
fixtureDef.filter.maskBits = (short) maskBits;
}
fixtureDef.density = 100;
body.createFixture(fixtureDef);
源码实现
public final Fixture createFixture(FixtureDef def) {
assert (m_world.isLocked() == false);
if (m_world.isLocked() == true) {
return null;
}
Fixture fixture = new Fixture();
fixture.create(this, def);
if ((m_flags & e_activeFlag) == e_activeFlag) {
BroadPhase broadPhase = m_world.m_contactManager.m_broadPhase;
fixture.createProxies(broadPhase, m_xf);
}
fixture.m_next = m_fixtureList;
m_fixtureList = fixture;
++m_fixtureCount;
fixture.m_body = this;
// Adjust mass properties if needed.
if (fixture.m_density > 0.0f) {
resetMassData();
}
// Let the world know we have a new fixture. This will cause new contacts
// to be created at the beginning of the next time step.
m_world.m_flags |= World.NEW_FIXTURE;
return fixture;
}
创建一个 fixture,然后将创建好的fixtureDef传入 进行初始化,然后将其加入到清单中,最后将fixture设置给body对象,将fixture回传。这个时候图形就没有什么作用了,可以进行清楚操作。
如何理解bodydef和fixturedef
BodyDef:在创建之前将刚体的属性准备好, 创建的时候将属性值传递给内部的私有属性。数据传递之后,他就没有啥用处了,可以继续使用,重新修改,让下一个继续使用。所以无法使用bodydef来修改属性。需要修改可以通过下面的方法
body.setActive(xxx);
body.getTransform().setPosition();
image.png
bodyDef对应body中的属性修改。对于fixture也是一样的。
image.png
我们创建之后需要可以使用上面的方法对属性进行修改。
形状
刚体的形状,在世界模拟中,根据形状进行碰撞模拟。我们也了解到刚体的形状可以根据多个fixture进行组合而成,也就是说它们可以加入多个fixture.
圆形
圆形创建就很简单了,只有一个参数半径就可以了,默认值是0,这里创建的单位都是米,他和像素的转换关系为 30px = 1m;将创建的图形传给你夹具就是我们创建出刚体的形状。
矩形
创建矩形可以使用PolygonShape创建它是一个多边形的类,他没有什么构造函数,但是可以调用相应的函数来返回相应的形状。,比如矩形可使用setAsBox创建。
sexAsBox的使用以刚体的中心坐标位置为中心点的矩形,及就是宽和高都是i相对于刚体坐标位置对称的,需要传入两个参数宽和高。这里是半宽实际的宽和高是传入的二倍。并且像素和宽高的对应关系
需要进行转换,比如创建一个60x100的矩形,需要传入的参数是30/30 50/30;
回顾一下
创建def,创建body,创建fixture 创建图形 添加fixture.
看到效果
打开调试视图,box2d是一个引擎,我们并不可以看到,需要我们打开调试试图,否则就一无所有。
我们可以使用step进行模拟,在模拟之后调用调试视图得到显示的状态