首页 > 代码库 > libgdx学习记录21——Box2d物理引擎之碰撞Contact、冲量Impulse、关节Joint

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也能够很好的结合起来一起显示,很方便。