Box2d中,物体可以接受力(Force)、冲量(Impulse)和扭矩(Torque)。这些物理元素都能改变物体的运动形式,并且默认都会唤醒物体,当然只是针对动态物体。
力是一个持久的效果,通过Box2d内置的积分器实现运动变化。
冲量是一个瞬时效果,能立马改变其效果。
主要函数:
body.applyLinearImpulse( Vector2 impulse, Vector2 position, boolean wakeup )
第一个参数表示冲量,包含x和y方向的大小。
第二个参数表示施加冲量的位置。
第三个参数表示是否唤醒物体。
物体碰撞时,可以检测到碰撞的过程,开始和结束,并能够通过其Contact类获取碰撞的2个物体形状,进而获取物体。
物体可以设置UserData,然后可以在render函数中获取对应的UserData,并设置对应的角度和位置就能够显示图片等元素。
关节(Joint)是物体之间连接的方式,添加关节后物体的*度会减少,运动轨迹会受到一定约束。
Box2d中有距离、旋转、滑轮、鼠标等一系列关节,这些都很方便的帮我们模拟现实。
具体示例:
package com.fxb.newtest; import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.InputAdapter;
import com.badlogic.gdx.graphics.GL10;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.BodyDef;
import com.badlogic.gdx.physics.box2d.Box2DDebugRenderer;
import com.badlogic.gdx.physics.box2d.CircleShape;
import com.badlogic.gdx.physics.box2d.Contact;
import com.badlogic.gdx.physics.box2d.ContactImpulse;
import com.badlogic.gdx.physics.box2d.ContactListener;
import com.badlogic.gdx.physics.box2d.FixtureDef;
import com.badlogic.gdx.physics.box2d.Joint;
import com.badlogic.gdx.physics.box2d.JointDef;
import com.badlogic.gdx.physics.box2d.JointDef.JointType;
import com.badlogic.gdx.physics.box2d.Manifold;
import com.badlogic.gdx.physics.box2d.PolygonShape;
import com.badlogic.gdx.physics.box2d.World;
import com.badlogic.gdx.physics.box2d.BodyDef.BodyType;
import com.badlogic.gdx.physics.box2d.joints.DistanceJointDef;
import com.badlogic.gdx.physics.box2d.joints.RevoluteJointDef;
import com.badlogic.gdx.utils.Array; public class Lib021_Box2d1 extends ApplicationAdapter{ World world;
OrthographicCamera camera;
//DebugRenderer debugRenderer;
Box2DDebugRenderer debugRenderer;
Body bodyBox, bodyCircle;
TextureRegion region;
Sprite sprite;
SpriteBatch batch;
final Array<Body> arrBody = new Array<Body>(); @Override
public void create() {
// TODO Auto-generated method stub
super.create(); camera = new OrthographicCamera();
camera.setToOrtho( false, Gdx.graphics.getWidth()/10, Gdx.graphics.getHeight()/10 );
debugRenderer = new Box2DDebugRenderer();
world = new World( new Vector2(0, -10), true ); batch = new SpriteBatch();
region = new TextureRegion( new Texture( Gdx.files.internal( "data/badlogicsmall.jpg" ) ) );
sprite = new Sprite( region );
sprite.setSize( 4, 4 ); BodyDef bodyGroundDef = new BodyDef();
bodyGroundDef.type = BodyType.StaticBody;
bodyGroundDef.position.set( 0, 2 );
Body bodyGround = world.createBody( bodyGroundDef ); PolygonShape shapeGround = new PolygonShape();
shapeGround.setAsBox( camera.viewportWidth, 1 );
bodyGround.createFixture( shapeGround, 1 );
shapeGround.dispose(); BodyDef bodyBoxDef = new BodyDef();
bodyBoxDef.type = BodyType.DynamicBody;
bodyBoxDef.position.set( 5, 60 );
bodyBox = world.createBody( bodyBoxDef );
PolygonShape shapeBox = new PolygonShape();
shapeBox.setAsBox( 2, 2 );
FixtureDef fixtureDefBox = new FixtureDef();
fixtureDefBox.friction = 0.1f;
fixtureDefBox.shape = shapeBox;
fixtureDefBox.restitution = 0.3f;
//bodyBox.createFixture( shapeBox, 1 );
bodyBox.createFixture( fixtureDefBox );
shapeBox.dispose();
//bodyBox.setUserData( sprite ); BodyDef bodyCircleDef = new BodyDef();
bodyCircleDef.type = BodyType.DynamicBody;
bodyCircleDef.position.set( 20, 30 );
bodyCircle = world.createBody( bodyCircleDef );
CircleShape shapeCircle = new CircleShape();
shapeCircle.setRadius(2);
FixtureDef fixtureDefCir = new FixtureDef();
fixtureDefCir.friction = 0.1f;
fixtureDefCir.shape = shapeCircle;
fixtureDefCir.restitution = 0.3f;
bodyCircle.createFixture( fixtureDefCir );
shapeCircle.dispose(); InputAdapter processor = new InputAdapter(){
@Override
public boolean keyDown(int keycode) {
if( keycode == Input.Keys.A ){
//bodyBox.applyForce( 2f, 0, bodyBox.getPosition().x, bodyBox.getPosition().y, true );
//bodyBox.applyForceToCenter( 2f, 2f, true );
bodyBox.applyLinearImpulse( 12f, 0, bodyBox.getPosition().x, bodyBox.getPosition().y, true );
System.out.println( "a" );
}
return super.keyDown(keycode);
}
};
Gdx.input.setInputProcessor( processor ); world.setContactListener( new ContactListener(){
@Override
public void beginContact(Contact contact) {
// TODO Auto-generated method stub
System.out.println( "begin" );
Body body1 = contact.getFixtureA().getBody();
Body body2 = contact.getFixtureB().getBody();
System.out.println( body1.getPosition().x + "," + body1.getPosition().y );
System.out.println( body2.getPosition().x + "," + body2.getPosition().y ); if( body1.getType() == BodyType.DynamicBody ){
body1.setUserData( sprite );
}
if( body2.getType() == BodyType.DynamicBody ){
body2.setUserData( sprite );
}
} @Override
public void endContact(Contact contact) {
// TODO Auto-generated method stub
System.out.println( "end" ); Body body1 = contact.getFixtureA().getBody();
Body body2 = contact.getFixtureB().getBody();
if( body1.getType() == BodyType.DynamicBody ){
body1.setUserData( null );
}
if( body2.getType() == BodyType.DynamicBody ){
body2.setUserData( null );
}
} @Override
public void preSolve(Contact contact, Manifold oldManifold) {
// TODO Auto-generated method stub
}
@Override
public void postSolve(Contact contact, ContactImpulse impulse) {
// TODO Auto-generated method stub
} }); DistanceJointDef jointDefDis = new DistanceJointDef();
jointDefDis.bodyA = bodyBox;
jointDefDis.bodyB = bodyCircle;
jointDefDis.type = JointType.DistanceJoint;
jointDefDis.length = 10;
Joint jointDis = world.createJoint( jointDefDis ); /* RevoluteJointDef jointDefRevo = new RevoluteJointDef();
//jointDefRevo.bodyA = bodyBox;
//jointDefRevo.bodyB = bodyCircle;
jointDefRevo.initialize( bodyBox, bodyCircle, bodyCircle.getWorldCenter() );
jointDefRevo.type = JointType.RevoluteJoint;
Joint jointRevo = world.createJoint( jointDefRevo );*/
} @Override
public void render() {
// TODO Auto-generated method stub
super.render();
Gdx.gl.glClear( GL10.GL_COLOR_BUFFER_BIT ); if( Gdx.input.isKeyPressed( Input.Keys.D ) ){
bodyBox.applyForce( 12f, 0, bodyBox.getPosition().x, bodyBox.getPosition().y, true );
} world.step( Gdx.graphics.getDeltaTime(), 6, 2 );
camera.update(); batch.setProjectionMatrix( camera.combined );
batch.begin(); world.getBodies( arrBody );
for( int i=0; i<arrBody.size; ++i ){
Body body = arrBody.get(i);
Sprite sprite0 = (Sprite)body.getUserData();
if( sprite0 != null ){
sprite0.setPosition( body.getPosition().x-2, body.getPosition().y-2 );
sprite0.setRotation( MathUtils.radiansToDegrees*body.getAngle() );
sprite0.draw( batch );
}
}
batch.end(); debugRenderer.render( world, camera.combined ); } @Override
public void dispose() {
// TODO Auto-generated method stub
super.dispose();
} }
运行效果:
落地后与地面发生碰撞,物体中间的图片都正常显示。
按下‘A’键后,方块物体向右移动,与圆环发生碰撞,内部UserData都设为null,没有图片显示。
添加了距离关节,两者连在了一起。
同时Box2d与stage也能够很好的结合起来一起显示,很方便。