libgdx学习记录21——Box2d物理引擎之碰撞Contact、冲量Impulse、关节Joint
Box2d中,物体可以接受力(Force)、冲量(Impulse)和扭矩(Torque)。这些物理元素都能改变物体的运动形式,并且默认都会唤醒物体,当然只是针对动态物体。
力是一个持久的效果,通过Box2d内置的积分器实现运动变化。
冲量是一个瞬时效果,能立马改变其效果。
主要函数:
body.applyLinearImpulse( Vector2 impulse, Vector2 position, boolean wakeup )
第一个参数表示冲量,包含x和y方向的大小。
第二个参数表示施加冲量的位置。
第三个参数表示是否唤醒物体。
物体碰撞时,可以检测到碰撞的过程,开始和结束,并能够通过其Contact类获取碰撞的2个物体形状,进而获取物体。
物体可以设置UserData,然后可以在render函数中获取对应的UserData,并设置对应的角度和位置就能够显示图片等元素。
关节(Joint)是物体之间连接的方式,添加关节后物体的自由度会减少,运动轨迹会受到一定约束。
Box2d中有距离、旋转、滑轮、鼠标等一系列关节,这些都很方便的帮我们模拟现实。
具体示例:
1 package com.fxb.newtest; 2 3 import com.badlogic.gdx.ApplicationAdapter; 4 import com.badlogic.gdx.Gdx; 5 import com.badlogic.gdx.Input; 6 import com.badlogic.gdx.InputAdapter; 7 import com.badlogic.gdx.graphics.GL10; 8 import com.badlogic.gdx.graphics.OrthographicCamera; 9 import com.badlogic.gdx.graphics.Texture; 10 import com.badlogic.gdx.graphics.g2d.Sprite; 11 import com.badlogic.gdx.graphics.g2d.SpriteBatch; 12 import com.badlogic.gdx.graphics.g2d.TextureRegion; 13 import com.badlogic.gdx.math.MathUtils; 14 import com.badlogic.gdx.math.Vector2; 15 import com.badlogic.gdx.physics.box2d.Body; 16 import com.badlogic.gdx.physics.box2d.BodyDef; 17 import com.badlogic.gdx.physics.box2d.Box2DDebugRenderer; 18 import com.badlogic.gdx.physics.box2d.CircleShape; 19 import com.badlogic.gdx.physics.box2d.Contact; 20 import com.badlogic.gdx.physics.box2d.ContactImpulse; 21 import com.badlogic.gdx.physics.box2d.ContactListener; 22 import com.badlogic.gdx.physics.box2d.FixtureDef; 23 import com.badlogic.gdx.physics.box2d.Joint; 24 import com.badlogic.gdx.physics.box2d.JointDef; 25 import com.badlogic.gdx.physics.box2d.JointDef.JointType; 26 import com.badlogic.gdx.physics.box2d.Manifold; 27 import com.badlogic.gdx.physics.box2d.PolygonShape; 28 import com.badlogic.gdx.physics.box2d.World; 29 import com.badlogic.gdx.physics.box2d.BodyDef.BodyType; 30 import com.badlogic.gdx.physics.box2d.joints.DistanceJointDef; 31 import com.badlogic.gdx.physics.box2d.joints.RevoluteJointDef; 32 import com.badlogic.gdx.utils.Array; 33 34 public class Lib021_Box2d1 extends ApplicationAdapter{ 35 36 World world; 37 OrthographicCamera camera; 38 //DebugRenderer debugRenderer; 39 Box2DDebugRenderer debugRenderer; 40 Body bodyBox, bodyCircle; 41 TextureRegion region; 42 Sprite sprite; 43 SpriteBatch batch; 44 final Array<Body> arrBody = new Array<Body>(); 45 46 @Override 47 public void create() { 48 // TODO Auto-generated method stub 49 super.create(); 50 51 camera = new OrthographicCamera(); 52 camera.setToOrtho( false, Gdx.graphics.getWidth()/10, Gdx.graphics.getHeight()/10 ); 53 debugRenderer = new Box2DDebugRenderer(); 54 world = new World( new Vector2(0, -10), true ); 55 56 batch = new SpriteBatch(); 57 region = new TextureRegion( new Texture( Gdx.files.internal( "data/badlogicsmall.jpg" ) ) ); 58 sprite = new Sprite( region ); 59 sprite.setSize( 4, 4 ); 60 61 62 BodyDef bodyGroundDef = new BodyDef(); 63 bodyGroundDef.type = BodyType.StaticBody; 64 bodyGroundDef.position.set( 0, 2 ); 65 Body bodyGround = world.createBody( bodyGroundDef ); 66 67 PolygonShape shapeGround = new PolygonShape(); 68 shapeGround.setAsBox( camera.viewportWidth, 1 ); 69 bodyGround.createFixture( shapeGround, 1 ); 70 shapeGround.dispose(); 71 72 73 BodyDef bodyBoxDef = new BodyDef(); 74 bodyBoxDef.type = BodyType.DynamicBody; 75 bodyBoxDef.position.set( 5, 60 ); 76 bodyBox = world.createBody( bodyBoxDef ); 77 PolygonShape shapeBox = new PolygonShape(); 78 shapeBox.setAsBox( 2, 2 ); 79 FixtureDef fixtureDefBox = new FixtureDef(); 80 fixtureDefBox.friction = 0.1f; 81 fixtureDefBox.shape = shapeBox; 82 fixtureDefBox.restitution = 0.3f; 83 //bodyBox.createFixture( shapeBox, 1 ); 84 bodyBox.createFixture( fixtureDefBox ); 85 shapeBox.dispose(); 86 //bodyBox.setUserData( sprite ); 87 88 BodyDef bodyCircleDef = new BodyDef(); 89 bodyCircleDef.type = BodyType.DynamicBody; 90 bodyCircleDef.position.set( 20, 30 ); 91 bodyCircle = world.createBody( bodyCircleDef ); 92 CircleShape shapeCircle = new CircleShape(); 93 shapeCircle.setRadius(2); 94 FixtureDef fixtureDefCir = new FixtureDef(); 95 fixtureDefCir.friction = 0.1f; 96 fixtureDefCir.shape = shapeCircle; 97 fixtureDefCir.restitution = 0.3f; 98 bodyCircle.createFixture( fixtureDefCir ); 99 shapeCircle.dispose(); 100 101 InputAdapter processor = new InputAdapter(){ 102 @Override 103 public boolean keyDown(int keycode) { 104 if( keycode == Input.Keys.A ){ 105 //bodyBox.applyForce( 2f, 0, bodyBox.getPosition().x, bodyBox.getPosition().y, true ); 106 //bodyBox.applyForceToCenter( 2f, 2f, true ); 107 bodyBox.applyLinearImpulse( 12f, 0, bodyBox.getPosition().x, bodyBox.getPosition().y, true ); 108 System.out.println( "a" ); 109 } 110 return super.keyDown(keycode); 111 } 112 }; 113 Gdx.input.setInputProcessor( processor ); 114 115 116 world.setContactListener( new ContactListener(){ 117 @Override 118 public void beginContact(Contact contact) { 119 // TODO Auto-generated method stub 120 System.out.println( "begin" ); 121 Body body1 = contact.getFixtureA().getBody(); 122 Body body2 = contact.getFixtureB().getBody(); 123 System.out.println( body1.getPosition().x + "," + body1.getPosition().y ); 124 System.out.println( body2.getPosition().x + "," + body2.getPosition().y ); 125 126 if( body1.getType() == BodyType.DynamicBody ){ 127 body1.setUserData( sprite ); 128 } 129 if( body2.getType() == BodyType.DynamicBody ){ 130 body2.setUserData( sprite ); 131 } 132 } 133 134 @Override 135 public void endContact(Contact contact) { 136 // TODO Auto-generated method stub 137 System.out.println( "end" ); 138 139 Body body1 = contact.getFixtureA().getBody(); 140 Body body2 = contact.getFixtureB().getBody(); 141 if( body1.getType() == BodyType.DynamicBody ){ 142 body1.setUserData( null ); 143 } 144 if( body2.getType() == BodyType.DynamicBody ){ 145 body2.setUserData( null ); 146 } 147 } 148 149 @Override 150 public void preSolve(Contact contact, Manifold oldManifold) { 151 // TODO Auto-generated method stub 152 } 153 @Override 154 public void postSolve(Contact contact, ContactImpulse impulse) { 155 // TODO Auto-generated method stub 156 } 157 158 }); 159 160 161 DistanceJointDef jointDefDis = new DistanceJointDef(); 162 jointDefDis.bodyA = bodyBox; 163 jointDefDis.bodyB = bodyCircle; 164 jointDefDis.type = JointType.DistanceJoint; 165 jointDefDis.length = 10; 166 Joint jointDis = world.createJoint( jointDefDis ); 167 168 169 /* RevoluteJointDef jointDefRevo = new RevoluteJointDef(); 170 //jointDefRevo.bodyA = bodyBox; 171 //jointDefRevo.bodyB = bodyCircle; 172 jointDefRevo.initialize( bodyBox, bodyCircle, bodyCircle.getWorldCenter() ); 173 jointDefRevo.type = JointType.RevoluteJoint; 174 Joint jointRevo = world.createJoint( jointDefRevo );*/ 175 } 176 177 @Override 178 public void render() { 179 // TODO Auto-generated method stub 180 super.render(); 181 Gdx.gl.glClear( GL10.GL_COLOR_BUFFER_BIT ); 182 183 184 if( Gdx.input.isKeyPressed( Input.Keys.D ) ){ 185 bodyBox.applyForce( 12f, 0, bodyBox.getPosition().x, bodyBox.getPosition().y, true ); 186 } 187 188 world.step( Gdx.graphics.getDeltaTime(), 6, 2 ); 189 camera.update(); 190 191 batch.setProjectionMatrix( camera.combined ); 192 batch.begin(); 193 194 world.getBodies( arrBody ); 195 for( int i=0; i<arrBody.size; ++i ){ 196 Body body = arrBody.get(i); 197 Sprite sprite0 = (Sprite)body.getUserData(); 198 if( sprite0 != null ){ 199 sprite0.setPosition( body.getPosition().x-2, body.getPosition().y-2 ); 200 sprite0.setRotation( MathUtils.radiansToDegrees*body.getAngle() ); 201 sprite0.draw( batch ); 202 } 203 } 204 batch.end(); 205 206 debugRenderer.render( world, camera.combined ); 207 208 } 209 210 @Override 211 public void dispose() { 212 // TODO Auto-generated method stub 213 super.dispose(); 214 } 215 216 }
运行效果:
落地后与地面发生碰撞,物体中间的图片都正常显示。
按下‘A’键后,方块物体向右移动,与圆环发生碰撞,内部UserData都设为null,没有图片显示。
添加了距离关节,两者连在了一起。
同时Box2d与stage也能够很好的结合起来一起显示,很方便。