精华内容
下载资源
问答
  • 他是一个用于2D的最流行的物理引擎库中的一个,被用到了许多语言,各种引擎中, 其中就包括咱们使用的这个LibgdxLibgdx中的Box2D实现了对于C++引擎的java包装,所以参考文档也可以直接使用C++版本的,official ...

    Box2D的是一个物理引擎库。他是一个用于2D的最流行的物理引擎库中的一个,被用到了许多语言,各种引擎中,

    其中就包括咱们使用的这个Libgdx。

    Libgdx中的Box2D实现了对于C++引擎的java包装,所以参考文档也可以直接使用C++版本的,official Box2D manual (PDF)

    想获得更多的信息可以到Box2D的官网,box2d.org 获得信息。

    这里我找到一个中文翻译的v2.0.1版本,这里要谢谢译者Aman JIANG(江超宇)。

    文档下载地址

    但是v2.0.1的版本比较老了,有一些概念都不一样了,例如2.1世界没有了包围盒,绑定形状到物体有了FixtureDef的概念,

    这里有一个v2.1.0的翻译版本

    http://blog.csdn.net/complex_ok/article/category/871440

    特别推荐Box2D教程 http://www.iforce2d.net/b2dtut/introduction

    对应中文译文 http://ohcoder.com/blog/categories/box2d-tutorials/

    创建一个世界

    物理世界,那么首先需要创造一个世界,他是物理物体,作用力的基础。但是他不会帮我们绘制物体, 需要我们使用Libgdx

    绘制的相关api来进行绘制。 也就是说我们获取物体的坐标,旋转信息什么的,然后自己绘制。 但是他在debug模式下,可以

    绘制自己的物理模拟信息,形状啦,什么的。

    可以向下面一样创建一个世界

    1. World world = new World(new Vector2(0, -10), true);  

    第一个参数是一个2维向量,0说明水平方向的重力为0, 10说明垂直方向的重力为10. 因为他是一个y轴向上的坐标系,所以负号

    代表向下。这个和opengl的世界坐标系是一致的。当然你也可以改成你想要的值, 不过要注意比例,在Box2D中 1单元=1米。

    第二个参数的意思是我们创造的世界要不要让物体休眠,休眠可以减少cpu的使用, 具体休不休眠看你的情景了。

    这里的比例最好和绘制的保持一致,也就是我们的opengl绘制。这样精灵,镜头的单位都统一。

    Debug绘制

    如果我们想开启debug绘制, 可以这样

    1. mDebugRender = new Box2DDebugRenderer(); 
    1. mDebugRender.render(mWorld, mCam.combined); 

    这里要注意一下, 当我们发布的时候要注释掉 , 我测试了一个例子, 在开启状态只有十几帧,关闭掉能够达到

    五六十帧的,还是很好性能的。

    时间步

    想要我们的物理模拟动起来, 需要我们告诉他。最好调用它的位置在reader的最后面。

    最好给他的帧率是一样的,不要使用绘制的帧率,像这样

    1. world.step(1/60f, 6, 2); 

    第一个参数是时间步,也就是我们想让世界模拟的时间。
    在大部分情况下, 这个时间步都应该是固定的, Libgdx推荐在移动手机1/45f或者1/300f.

    另外两个参数是velocityIterations,positionIterations 速度的约束求解量 和 位置的约束求解量.

    约束求解器用于解决模拟中的所有
    约束,一次一个。单个的约束会被完美的求解,然而当我们求解一个约束的时候,我们就会稍微耽误另
    一个。要得到良好的解,我们需要迭代所有约束多次。建议的  Box2D 迭代次数是 10 次。你可以按自己
    的喜好去调整这个数,但要记得它是速度与质量之间的平衡。更少的迭代会增加性能并降低精度,同样
    地,更多的迭代会减少性能但提高模拟质量。

    绘制

    推荐的做法是在step之前绘制我们的图形, 否则将会出现不同步的问题。

    如果想要debug绘制, 可以使用

    1. debugRenderer.render(world, camera.combined); 

    第一个参数是世界,第二个是镜头矩阵

    Body物体
    现在如果我们运行我们的代码,将会什么也看不到,虽然我们的世界步执行着呢, 这是因为我们没有放入

    任何物体进去。 所以, 接下来我们会放进去一些物体。

    在Box2D中, 对象叫做物体, 物体包含许多固定物fixtures,他可以固定物体的位置,方向等, 固定物可以是

    任何形状, 可以组合多个不同的固定物来组成物体。

    固定物包含形状, 密度, 摩擦力,恢复力。形状就是集合图形了, 密度是每立方米的物体的质量, 就比如保龄球

    和氢气球,密度大密度小。摩擦力就是物体接触移动产生的力,在冰上移动和在橡胶上, 摩擦力显而易见了。

    恢复力就是有多大的弹性, 石头的弹性就比较小 , 乒乓球的弹性就比较大。 当一个物体的弹性是0的时候, 当接触到

    地面就会停止,当为1的时候, 他会反弹到他原来的高度。

    物体有三种类型:Dynamic动态的,Static静态的,Kinematic介于他们之间的运动物体。

    动态物体

    动态物理可以四处移动, 他受力的作用和其他动态物体,静态物体, 运动物体的作用。

    他适合那种需要移动然后受到力的作用的物体。

    现在我们学习固定物的创建, 来构造物体

    1. // First we create a body definition
    2. BodyDef bodyDef = new BodyDef(); 
    3. // We set our body to dynamic, for something like ground which doesn't move we would set it to StaticBody
    4. bodyDef.type = BodyType.DynamicBody; 
    5. // Set our body's starting position in the world
    6. bodyDef.position.set(100, 300); 
    7. // Create our body in the world using our body definition
    8. Body body = world.createBody(bodyDef); 
    9. // Create a circle shape and set its radius to 6
    10. CircleShape circle = new CircleShape(); 
    11. circle.setRadius(6f); 
    12. // Create a fixture definition to apply our shape to
    13. FixtureDef fixtureDef = new FixtureDef(); 
    14. fixtureDef.shape = circle; 
    15. fixtureDef.density = 0.5f;  
    16. fixtureDef.friction = 0.4f; 
    17. fixtureDef.restitution = 0.6f; // Make it bounce a little bit
    18. // Create our fixture and attach it to the body
    19. Fixture fixture = body.createFixture(fixtureDef); 
    20. // Remember to dispose of any shapes after you're done with them!
    21. // BodyDef and FixtureDef don't need disposing, but shapes do.
    22. circle.dispose(); 

    现在我们创建了一个球的物体到我们的世界。运行的时候可以看到他将会下落, 但是感觉还是没多少意思,

    没有力的作用, 下面我们来加入静态物体地板。

    静态物体

    静态物体是一个不能移动, 也不受力的作用的物体。动态物体接触它, 动态物体会有力的作用的。静态物体

    让他来做为地板,墙壁等不能动的物体是非常合适的。 静态物体也消耗比较少的计算量。

    让我们来创建一个静态物体, 跟我们前面的创建动态物体的代码比较像

    1. // Create our body definition
    2. BodyDef groundBodyDef =new BodyDef();   
    3. // Set its world position
    4. groundBodyDef.position.set(new Vector2(0, 10));   
    5. // Create a body from the defintion and add it to the world
    6. Body groundBody = world.createBody(groundBodyDef);   
    7. // Create a polygon shape
    8. PolygonShape groundBox = new PolygonShape();   
    9. // Set the polygon shape as a box which is twice the size of our view port and 20 high
    10. // (setAsBox takes half-width and half-height as arguments)
    11. groundBox.setAsBox(camera.viewportWidth, 10.0f); 
    12. // Create a fixture from our polygon shape and add it to our ground body 
    13. groundBody.createFixture(groundBox, 0.0f);  
    14. // Clean up after ourselves
    15. groundBox.dispose(); 

    我们怎么样不适用FixtureDef创造一个夹具呢?如果我们只有形状和密度, createFixture有个重载方法,调用它就可以了。

    现在我们看到, 球下落到我们的地面上, 然后反弹, 最终停止在地面上, 我们也可以更改其中的值来看看有什么其他效果。

    运动物体

    Kinematic物体是一个介于在静态和动态物体之间的物体。 像静态物体,他们不受力的作用, 像动态物体,他们可以移动。

    应用的场景例如移动的平台等。

    我们可以直接的调用Kinematic物体的位置,直接更改他的位置, 但是最好的方式是设置一个速度,让Box2D自己来更改

    他的坐标。

    我们可以使用上面创建动态和静态物体的方式一样来创建这个物体, 一旦我们创建好, 我们可以像下面一样来控制他

    1. // Move upwards at a rate of 1 meter per second
    2. kinematicBody.setLinearVelocity(0.0f, 1.0f); 

    好了, 运行程序, 我们发现, 我们的物体在朝着一个固定的方向移动, 当我们的小球遇到咱们这个方块的时候,由于力

    的作用,朝右方向移动了,但是它与静态物体地板接触的时候, 并没有受到力的作用, 当然地板也没有力的作用。

    冲量与力

    冲量和力用来移动物体, 但是不会改变重力和碰撞检测。

    力是一个逐渐改变物体速度的过程, 比如火箭的升起,是有一个力的驱动,逐渐改变火箭的速度, 慢慢升起的,越来

    越快。

    冲量就不同了,可以瞬间改变物体速度,比如吃豆人游戏,角色都是在一个恒定的速度移动,改变也是瞬间的。

    首先我们需要一个动态的物体,就使用上面那个吧。

    应用力

    力是单位是牛顿。 如果力没有作用在质量的中心,那么将会产生一个扭矩, 产生一个带有夹角的速度。

    1. // Apply a force of 1 meter per second on the X-axis at pos.x/pos.y of the body slowly moving it right
    2. dynamicBody.applyForce(1.0f, 0.0f, pos.x, pos.y, true); 
    3. // If we always want to apply force at the center of the body, use the following
    4. dynamicBody.applyForceToCenter(1.0f, 0.0f, true); 

    应用冲量
    冲量就像一个特殊的力,只是冲量可以立即改变物体的速度。 同样的, 如果冲量没有作用在物体的中间, 也将会产生

    一个扭矩, 产生一个带有夹角的速度。冲量的单位是 牛顿每秒 或者 kg-m/s.

    1. // Immediately set the X-velocity to 1 meter per second causing the body to move right quickly
    2. dynamicBody.applyLinearImpulse(1.0f, 0, pos.x, pos.y, true); 

    有一点要注意一下,应用力和冲量会唤醒物体, 有时候这不是我们想要的, 比如, 你想作用一个稳定的力,想让物体在睡眠中执行,

    这种情况下, 我们可以这样

    1. // Apply impulse but don't wake the body
    2. dynamicBody.applyLinearImpulse(0.8f, 0, pos.x, pos.y, false); 

    Joints关节

    占位

    Fixture Shapes形状

    占位

    Sprites and Bodies 精灵与物体

    最简单的方式管理精灵语物体的是使用Box2D的用户数据,我们可以使用用户数据改变游戏对象的位置坐标, 旋转等信息。

    设置用户信息也比较简单,可以这样

    1. body.setUserData(Object); 

    这个用户数据可以是任何java对象, 一个比较好的方式是建立一个游戏对象然后放入用户数据,这样以后可以使用。

    Fixtures夹具也可以设置用户数据,和上面一样。

    想更新我们的角色或精灵的信息, 可以遍历所有的世界物体,取出对应的用户数据,然后更新信息, 示例

    1. Iterator<Body> bi = world.getBodies(); 
    2. while (bi.hasNext()){ 
    3.     Body b = bi.next(); 
    4. // Get the bodies user data - in this example, our user
    5. // data is an instance of the Entity class
    6.     Entity e = (Entity) b.getUserData(); 
    7. if (e != null) { 
    8. // Update the entities/sprites position and angle
    9.         e.setPosition(b.getPosition().x, b.getPosition().y); 
    10. // We need to convert our angle from radians to degrees
    11.         e.setRotation(MathUtils.radiansToDegrees * b.getAngle()); 
    12.     } 

    绘制部分还是和以前一样的。 没有什么改动。

    Sensors传感器
    传感器是当物体间碰撞,而又不产生自动响应。 比如, 我们想知道两个物体重叠的事件。

    这里需要设置'isSensor'为true。像这样

    1. //At the definition of the Fixture
    2. fixtureDef.isSensor = true; 

    想监听它,需要实现ContactListener接口,在对应方法中实现自己的逻辑。

    传感器接口

    传感器接口监听fixture夹具的碰撞,方法包含一个传感对象, 传感对象包含了两个物体的有关信息, 当物体重叠的时候

    调用beginContact ,当物体分开的时候调用endContact

    1. public class ListenerClass implements ContactListener { 
    2. @Override
    3. public void endContact(Contact contact) { 
    4.             } 
    5. @Override
    6. public void beginContact(Contact contact) { 
    7.             } 
    8.         }; 

    有时候, 我们需要得到游戏对象的信息, 怎么办呢?其实这个在我们需要在设置用户数据的时候, 把我们的游戏对象信息设置

    到body或者fixture中, 然后取出来, 做逻辑,比如,减血或其他。

    好了, Box2D的简单的了解,就到这了。 想深入学习,可以到他的官网查看。

    展开全文
  • libgdx游戏引擎

    2012-02-12 16:51:08
    libgdx游戏引擎,一款具有出色物理模拟的引擎,使用jni编写
  • 前言 相比Ios UiKit原生支持物理引擎,Android确实麻烦的不要不要。 为什么用 libgdx ...libgdx物理引擎其实是封装的native版本box2D,在满足性能需求的同时,避免了开发JNI的烦恼,对于java程序员来说目...

    前言

    相比Ios UiKit原生支持物理引擎,Android确实麻烦的不要不要。

    为什么用 libgdx

    • Android上最方便的方案是jbox2D,缺点是在java层实现,物理多了之后性能很卡。笔者近期没有测试,11年左右在里程碑1上使用的时候那是巨卡无比。
    • libgdx的物理引擎其实是封装的native版本box2D,在满足性能需求的同时,避免了开发JNI的烦恼,对于java程序员来说目前是最便捷的方案。

    使用libgdx-box2d

    STEP1: build.gradle中添加依赖

    dependencies {
    
        configurations { natives }
    
        implementation "com.badlogicgames.gdx:gdx-box2d:$box2dVersion"
        natives "com.badlogicgames.gdx:gdx-box2d-platform:$box2dVersion:natives-armeabi"
        natives "com.badlogicgames.gdx:gdx-box2d-platform:$box2dVersion:natives-armeabi-v7a"
        natives "com.badlogicgames.gdx:gdx-box2d-platform:$box2dVersion:natives-arm64-v8a"
    }
    
    task copyAndroidNatives() {
        file("libs/armeabi/").mkdirs();
        file("libs/armeabi-v7a/").mkdirs();
        file("libs/arm64-v8a/").mkdirs();
    
        configurations.natives.files.each { jar ->
            def outputDir = null
            if(jar.name.endsWith("natives-arm64-v8a.jar")) outputDir = file("libs/arm64-v8a")
            if(jar.name.endsWith("natives-armeabi-v7a.jar")) outputDir = file("libs/armeabi-v7a")
            if(jar.name.endsWith("natives-armeabi.jar")) outputDir = file("libs/armeabi")
            if(outputDir != null) {
                copy {
                    from zipTree(jar)
                    into outputDir
                    include "*.so"
                }
            }
        }
    }
    
    

    STEP2: 渲染层实现

    • libgdx本身是个游戏引擎,提供基于openGLES的渲染引擎,但是对于大多数APPer来说使用成本略高。这里我们通过实现一个自定义view,并通过Canvas#draw()的方式进行渲染。

    • 2.1 初始化box2D

        private void setupBox2D() {
            Box2D.init();
            //第一个参数为x、y两个方向的重力值,(0,0)点在左上y轴重力用10
            mWorld = new World(new Vector2(0, 10), true);
        }
    
    
    
    • 2.2 在组件四周添加静态刚体
        private void createTopAndBottomBounds() {
            BodyDef bodyDef = new BodyDef();
            bodyDef.type = BodyDef.BodyType.StaticBody;
    
            PolygonShape box = new PolygonShape();
            float boxWidth = pixelsToMeters(mWidth);
            float boxHeight = pixelsToMeters(mRatio);
            box.setAsBox(boxWidth, boxHeight);
    
            FixtureDef fixtureDef = new FixtureDef();
            fixtureDef.shape = box;
            fixtureDef.density = 0.5f;
            fixtureDef.friction = 0.3f;
            fixtureDef.restitution = 0.5f;
    
            bodyDef.position.set(0, -boxHeight * .5f);
            Body topBody = mWorld.createBody(bodyDef);
            topBody.createFixture(fixtureDef);
    
            bodyDef.position.set(0, pixelsToMeters(mHeight) + boxHeight * .5f);
            Body bottomBody = mWorld.createBody(bodyDef);
            bottomBody.createFixture(fixtureDef);
        }
    
        private void createLeftAndRightBounds() {
            float boxWidth = pixelsToMeters(mRatio);
            float boxHeight = pixelsToMeters(mHeight);
    
            BodyDef bodyDef = new BodyDef();
            bodyDef.type = BodyDef.BodyType.StaticBody;
    
            PolygonShape box = new PolygonShape();
            box.setAsBox(boxWidth, boxHeight);
            FixtureDef fixtureDef = new FixtureDef();
            fixtureDef.shape = box;
            fixtureDef.density = 0.5f;
            fixtureDef.friction = 0.3f;
            fixtureDef.restitution = 0.5f;
    
            bodyDef.position.set(-boxWidth * .5f, boxHeight);
            Body leftBody = mWorld.createBody(bodyDef);
            leftBody.createFixture(fixtureDef);
    
    
            bodyDef.position.set(pixelsToMeters(mWidth) + boxWidth * .5f, 0);
            Body rightBody = mWorld.createBody(bodyDef);
            rightBody.createFixture(fixtureDef);
        }
    
    
    • 2.3 添加一个动态刚体,从(0,0)点下落
        public void addGiftBody() {
            // First we create a body definition
            BodyDef bodyDef = new BodyDef();
            // We set our body to dynamic, for something like ground which doesn't move we would set it to StaticBody
            bodyDef.type = BodyDef.BodyType.DynamicBody;
            // Set our body's starting position in the world
    
            bodyDef.position.set(pixelsToMeters(3), pixelsToMeters(3));
    
            bodyDef.linearVelocity.set((float) Math.random(), (float) Math.random() * 100);
    
            // Create our body in the world using our body definition
            Body body = mWorld.createBody(bodyDef);
            //TODO 随机
            Bitmap bitmap = mBitmaps[0];
            GiftInfo giftInfo = new GiftInfo(bitmap);
            body.setUserData(giftInfo);
            body.setFixedRotation(false);
    
            PolygonShape box = new PolygonShape();
            float boxWidth = pixelsToMeters(pixelsToMeters(bitmap.getWidth()));
            float boxHeight = pixelsToMeters(pixelsToMeters(bitmap.getHeight()));
            box.setAsBox(boxWidth, boxHeight);
    
            // Create a fixture definition to apply our shape to
            FixtureDef fixtureDef = new FixtureDef();
            fixtureDef.shape = box;
            fixtureDef.density = 1.5f;
            fixtureDef.friction = 0.4f;
            fixtureDef.restitution = .6f; // Make it bounce a little bit
    
            // Create our fixture and attach it to the body
            Fixture fixture = body.createFixture(fixtureDef);
    
            mBodyList.add(body);
    
            box.dispose();
        }
    

    2.4 渲染、更新物体坐标、以此循环

    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            drawGift(canvas);
            long time = System.currentTimeMillis() - mLastRenderTime;
            mLastRenderTime = time;
            doPhysicsStep(time);
            postInvalidate();
        }
        
        
        private void drawGift(Canvas canvas) {
            int size = mBodyList.size();
            for (int i = 0; i < size; i++) {
                Body body = mBodyList.get(i);
                GiftInfo giftInfo = (GiftInfo) body.getUserData();
                Bitmap bitmap = giftInfo.getBitmap();
    
                canvas.drawBitmap(bitmap, metersToPixels(mBodyList.get(i).getPosition().x) - bitmap.getWidth() * .5f,
                        metersToPixels(mBodyList.get(i).getPosition().y) - bitmap.getHeight() * .5f, mPaint);
            }
        }
        
        private void doPhysicsStep(float deltaTime) {
            // fixed time step
            // max frame time to avoid spiral of death (on slow devices)
            float frameTime = Math.min(deltaTime, 0.25f);
            mAccumulator += frameTime;
            while (mAccumulator >= Constants.TIME_STEP) {
                mWorld.step(Constants.TIME_STEP, Constants.VELOCITY_ITERATIONS, Constants.POSITION_ITERATIONS);
                mAccumulator -= Constants.TIME_STEP;
            }
        }
    
    

    结尾

    • 希望能够通过这个简单例子帮助大家使用libgdx-box2d,先水一波。
    展开全文
  • 文章翻译并修改自原文David Saltares。博主经验丰富,他的很多关于Libgdx的文章都值得一读,再此特...这篇文章涉及了处理物理引擎中的时间增量的不同方法。这个问题很复杂,但是不可否认它对游戏行为和表现的影响。

    文章翻译并修改自原文David Saltares。博主经验丰富,他的很多关于Libgdx的文章都值得一读,再此特作推荐。

    Fix your Timestep是Glenn Fiedler所写的一篇关于处理物理模拟的文章。这篇文章是2006年的,但是其中大部分内容在今天仍然具有启发性。

    这篇文章涉及了处理物理引擎中的时间增量的不同方法。这个问题很复杂,但是不可否认它对游戏行为和表现的影响。

    我认为将这些内容迁移到使用Box2D物理引擎的Libgdx应用中是非常好的点子。这些也可以应用到Bullet中,它是另外一款优秀的物理引擎,而且迁移的改动非常小。


    简单却错误的方法

    将时间步长设定为1/60每秒,这是非常常见而且简单的方法。它可以让物理模拟稳定运行,但是当游戏运行FPS降到60以下时,物理引擎的表现会非常糟。而这在移动设备上非常常见。

    最合乎逻辑的方案是计算现在时点在最后一帧后经过的时间,并传递给物理引擎。这样做显然会让每一帧的表现不同,整个物理引擎会表现的很不稳定。不同设备之间的表现会由于设备自身的不同(比如内存、运算器)产生变化。很明显,这不是我们期待的方案。


    固定的时间步长

    如果物理引擎以一个固定的步长,如1/60秒去运行,那么有些设备可能会运行的过快并达到120FPS。而同时有些设备可能运行过于缓慢,达到30FPS,那么物理引擎每两帧才前进一次。

    如果游戏以50FPS运行,会出现什么情况
    

    我们需要一个累加器来保存时间,然后尽可能的保持物理引擎和渲染一致。当这一帧时间过多时,我们可以将多余时间保留给下一帧。

    public class SionGame extends ApplicationListener {
        private World world;
        private double accumulator;
        private double currentTime;
        private float step = 1.0f / 60.0f;
        public void render() {
            double newTime = TimeUtils.millis() / 1000.0;
            double frameTime = Math.min(newTime - currentTime, 0.25);
            float deltaTime = (float)frameTime;
            currentTime = newTime;
            while (accumulator >=  step) {
                world.step(step, velIterations, posIterations);
                accumulator -= step;
            }
    }
    其中step是固定的时间步长,而accumulator是剩余的时间。

    追加处理

    因为accumulator中保存了剩余的时间,但是它又不足驱动物理引擎一次。这样就会出现一种视觉上的延迟或者卡顿,因为你的渲染所经历的时间比物理时间经历的时间长。

    我们可以在这两个物理状态间追加一次实体的变化来减缓这种延迟。而追加的依据就是我们剩余的时间。

    public class SionGame extends ApplicationListener {
        private World world;
        private double accumulator;
        private double currentTime;
        private float step = 1.0f / 60.0f;
        public void render() {
            double newTime = TimeUtils.millis() / 1000.0;
            double frameTime = Math.min(newTime - currentTime, 0.25);
            float deltaTime = (float)frameTime;
            currentTime = newTime;
            while (accumulator >= step) {
                world.step(step, velIterations, posIterations);
                accumulator -= step;
                entityManager.update();
            }
            entityManager.interpolate(accumulator / step);
    }
    其中的Entityanager是一个专门的类。它承担为维持游戏实体集合的任务,并通过 update()来更新物理世界,通过 interpolate()方法来追加变化。

    public void interpolate(float alpha) {
        for (Entity entity : entities) {
            Transform transform = entity.getBody().getTransform();
            Vector2 bodyPosition = transform.getPosition();
            Vector2 position = entity.getPosition();
            float angle = entity.getAngle();
            float bodyAngle = transform.getRotation();
            position.x = bodyPosition.x * alpha + position.x * (1.0f - alpha);
            position.y = bodyPosition.y * alpha + position.x * (1.0f - alpha);
            entity.setAngle(bodyAngle * alpha + angle * (1.0f - alpha));
        }
    }

    更详细的追加可以参考 SionCore


    实例

    Libgdx社区的成员Just4phil提供了一个本文阐述的方法的实例。详见参考部分。


    参考

    fix your timestep
    Download demo jar
    Game Screen
    sioncore

    展开全文
  • 本系列文章使用的Libgdx版本均为0.99版本 ...Libgdx游戏开发交流群 323876830 ...他是一个用于2D的最流行的物理引擎库中的一个,被用到了许多语言,各种引擎中, 其中就包括咱们使用的这个Li


    转载自:http://blog.csdn.net/wu928320442/article/details/17285405

    本系列文章使用的Libgdx版本均为0.99版本

    Libgdx游戏开发交流群 323876830

     

    Box2D的是一个物理引擎库。他是一个用于2D的最流行的物理引擎库中的一个,被用到了许多语言,各种引擎中,

    其中就包括咱们使用的这个Libgdx。

    Libgdx中的Box2D实现了对于C++引擎的Java包装,所以参考文档也可以直接使用C++版本的,official Box2D manual (PDF)

    想获得更多的信息可以到Box2D的官网,box2d.org 获得信息。

    这里我找到一个中文翻译的v2.0.1版本,这里要谢谢译者Aman JIANG(江超宇)。

    文档下载地址

    但是v2.0.1的版本比较老了,有一些概念都不一样了,例如2.1世界没有了包围盒,绑定形状到物体有了FixtureDef的概念,

    这里有一个v2.1.0的翻译版本

    http://blog.csdn.net/complex_ok/article/category/871440

    特别推荐Box2D教程 http://www.iforce2d.net/b2dtut/introduction

    对应中文译文 http://ohcoder.com/blog/categories/box2d-tutorials/

     

    创建一个世界

    物理世界,那么首先需要创造一个世界,他是物理物体,作用力的基础。但是他不会帮我们绘制物体, 需要我们使用Libgdx

    绘制的相关api来进行绘制。 也就是说我们获取物体的坐标,旋转信息什么的,然后自己绘制。 但是他在debug模式下,可以

    绘制自己的物理模拟信息,形状啦,什么的。

     

    可以向下面一样创建一个世界

    1. World world = new World(new Vector2(0, -10), true);   

    第一个参数是一个2维向量,0说明水平方向的重力为0, 10说明垂直方向的重力为10. 因为他是一个y轴向上的坐标系,所以负号

    代表向下。这个和opengl的世界坐标系是一致的。当然你也可以改成你想要的值, 不过要注意比例,在Box2D中 1单元=1米。

    第二个参数的意思是我们创造的世界要不要让物体休眠,休眠可以减少cpu的使用, 具体休不休眠看你的情景了。

     

    这里的比例最好和绘制的保持一致,也就是我们的opengl绘制。这样精灵,镜头的单位都统一。

     

    Debug绘制

    如果我们想开启debug绘制, 可以这样

    1. mDebugRender = new Box2DDebugRenderer();  
    1. mDebugRender.render(mWorld, mCam.combined);  

    这里要注意一下, 当我们发布的时候要注释掉 , 我测试了一个例子, 在开启状态只有十几帧,关闭掉能够达到

    五六十帧的,还是很好性能的。

     

    时间步

    想要我们的物理模拟动起来, 需要我们告诉他。最好调用它的位置在reader的最后面。

    最好给他的帧率是一样的,不要使用绘制的帧率,像这样

    1. world.step(1/60f, 62);  

    第一个参数是时间步,也就是我们想让世界模拟的时间。
    在大部分情况下, 这个时间步都应该是固定的, Libgdx推荐在移动手机1/45f或者1/300f.

    另外两个参数是velocityIterations,positionIterations 速度的约束求解量 和 位置的约束求解量.

    约束求解器用于解决模拟中的所有
    约束,一次一个。单个的约束会被完美的求解,然而当我们求解一个约束的时候,我们就会稍微耽误另
    一个。要得到良好的解,我们需要迭代所有约束多次。建议的  Box2D 迭代次数是 10 次。你可以按自己
    的喜好去调整这个数,但要记得它是速度与质量之间的平衡。更少的迭代会增加性能并降低精度,同样
    地,更多的迭代会减少性能但提高模拟质量。

     

    绘制

    推荐的做法是在step之前绘制我们的图形, 否则将会出现不同步的问题。

    如果想要debug绘制, 可以使用

    1. debugRenderer.render(world, camera.combined);  

    第一个参数是世界,第二个是镜头矩阵

     

    Body物体
    现在如果我们运行我们的代码,将会什么也看不到,虽然我们的世界步执行着呢, 这是因为我们没有放入

    任何物体进去。 所以, 接下来我们会放进去一些物体。

    在Box2D中, 对象叫做物体, 物体包含许多固定物fixtures,他可以固定物体的位置,方向等, 固定物可以是

    任何形状, 可以组合多个不同的固定物来组成物体。

    固定物包含形状, 密度, 摩擦力,恢复力。形状就是集合图形了, 密度是每立方米的物体的质量, 就比如保龄球

    和氢气球,密度大密度小。摩擦力就是物体接触移动产生的力,在冰上移动和在橡胶上, 摩擦力显而易见了。

    恢复力就是有多大的弹性, 石头的弹性就比较小 , 乒乓球的弹性就比较大。 当一个物体的弹性是0的时候, 当接触到

    地面就会停止,当为1的时候, 他会反弹到他原来的高度。

    物体有三种类型:Dynamic动态的,Static静态的,Kinematic介于他们之间的运动物体。

     

    动态物体

    动态物理可以四处移动, 他受力的作用和其他动态物体,静态物体, 运动物体的作用。

    他适合那种需要移动然后受到力的作用的物体。

    现在我们学习固定物的创建, 来构造物体

    1. // First we create a body definition  
    2. BodyDef bodyDef = new BodyDef();  
    3. // We set our body to dynamic, for something like ground which doesn't move we would set it to StaticBody  
    4. bodyDef.type = BodyType.DynamicBody;  
    5. // Set our body's starting position in the world  
    6. bodyDef.position.set(100300);  
    7.   
    8. // Create our body in the world using our body definition  
    9. Body body = world.createBody(bodyDef);  
    10.   
    11. // Create a circle shape and set its radius to 6  
    12. CircleShape circle = new CircleShape();  
    13. circle.setRadius(6f);  
    14.   
    15. // Create a fixture definition to apply our shape to  
    16. FixtureDef fixtureDef = new FixtureDef();  
    17. fixtureDef.shape = circle;  
    18. fixtureDef.density = 0.5f;   
    19. fixtureDef.friction = 0.4f;  
    20. fixtureDef.restitution = 0.6f; // Make it bounce a little bit  
    21.   
    22. // Create our fixture and attach it to the body  
    23. Fixture fixture = body.createFixture(fixtureDef);  
    24.   
    25. // Remember to dispose of any shapes after you're done with them!  
    26. // BodyDef and FixtureDef don't need disposing, but shapes do.  
    27. circle.dispose();  

    现在我们创建了一个球的物体到我们的世界。运行的时候可以看到他将会下落, 但是感觉还是没多少意思,

    没有力的作用, 下面我们来加入静态物体地板。

     

    静态物体

    静态物体是一个不能移动, 也不受力的作用的物体。动态物体接触它, 动态物体会有力的作用的。静态物体

    让他来做为地板,墙壁等不能动的物体是非常合适的。 静态物体也消耗比较少的计算量。

    让我们来创建一个静态物体, 跟我们前面的创建动态物体的代码比较像

    1. // Create our body definition  
    2. BodyDef groundBodyDef =new BodyDef();    
    3. // Set its world position  
    4. groundBodyDef.position.set(new Vector2(010));    
    5.   
    6. // Create a body from the defintion and add it to the world  
    7. Body groundBody = world.createBody(groundBodyDef);    
    8.   
    9. // Create a polygon shape  
    10. PolygonShape groundBox = new PolygonShape();    
    11. // Set the polygon shape as a box which is twice the size of our view port and 20 high  
    12. // (setAsBox takes half-width and half-height as arguments)  
    13. groundBox.setAsBox(camera.viewportWidth, 10.0f);  
    14. // Create a fixture from our polygon shape and add it to our ground body    
    15. groundBody.createFixture(groundBox, 0.0f);   
    16. // Clean up after ourselves  
    17. groundBox.dispose();  

    我们怎么样不适用FixtureDef创造一个夹具呢?如果我们只有形状和密度, createFixture有个重载方法,调用它就可以了。

    现在我们看到, 球下落到我们的地面上, 然后反弹, 最终停止在地面上, 我们也可以更改其中的值来看看有什么其他效果。

     

    运动物体


    Kinematic物体是一个介于在静态和动态物体之间的物体。 像静态物体,他们不受力的作用, 像动态物体,他们可以移动。

    应用的场景例如移动的平台等。

    我们可以直接的调用Kinematic物体的位置,直接更改他的位置, 但是最好的方式是设置一个速度,让Box2D自己来更改

    他的坐标。

    我们可以使用上面创建动态和静态物体的方式一样来创建这个物体, 一旦我们创建好, 我们可以像下面一样来控制他

    1. // Move upwards at a rate of 1 meter per second  
    2. kinematicBody.setLinearVelocity(0.0f, 1.0f);  

    好了, 运行程序, 我们发现, 我们的物体在朝着一个固定的方向移动, 当我们的小球遇到咱们这个方块的时候,由于力

    的作用,朝右方向移动了,但是它与静态物体地板接触的时候, 并没有受到力的作用, 当然地板也没有力的作用。

     

    冲量与力

    冲量和力用来移动物体, 但是不会改变重力和碰撞检测。

    力是一个逐渐改变物体速度的过程, 比如火箭的升起,是有一个力的驱动,逐渐改变火箭的速度, 慢慢升起的,越来

    越快。

    冲量就不同了,可以瞬间改变物体速度,比如吃豆人游戏,角色都是在一个恒定的速度移动,改变也是瞬间的。

    首先我们需要一个动态的物体,就使用上面那个吧。

     

    应用力

    力是单位是牛顿。 如果力没有作用在质量的中心,那么将会产生一个扭矩, 产生一个带有夹角的速度。

    1. // Apply a force of 1 meter per second on the X-axis at pos.x/pos.y of the body slowly moving it right  
    2. dynamicBody.applyForce(1.0f, 0.0f, pos.x, pos.y, true);  
    3.   
    4. // If we always want to apply force at the center of the body, use the following  
    5. dynamicBody.applyForceToCenter(1.0f, 0.0f, true);  


    应用冲量
    冲量就像一个特殊的力,只是冲量可以立即改变物体的速度。 同样的, 如果冲量没有作用在物体的中间, 也将会产生

    一个扭矩, 产生一个带有夹角的速度。冲量的单位是 牛顿每秒 或者 kg-m/s.

    1. // Immediately set the X-velocity to 1 meter per second causing the body to move right quickly  
    2. dynamicBody.applyLinearImpulse(1.0f, 0, pos.x, pos.y, true);  


    有一点要注意一下,应用力和冲量会唤醒物体, 有时候这不是我们想要的, 比如, 你想作用一个稳定的力,想让物体在睡眠中执行,

    这种情况下, 我们可以这样

    1. // Apply impulse but don't wake the body  
    2. dynamicBody.applyLinearImpulse(0.8f, 0, pos.x, pos.y, false);  


    Joints关节

    占位

     

    Fixture Shapes形状

    占位

     

    Sprites and Bodies 精灵与物体

    最简单的方式管理精灵语物体的是使用Box2D的用户数据,我们可以使用用户数据改变游戏对象的位置坐标, 旋转等信息。

    设置用户信息也比较简单,可以这样

    1. body.setUserData(Object);  

    这个用户数据可以是任何java对象, 一个比较好的方式是建立一个游戏对象然后放入用户数据,这样以后可以使用。

    Fixtures夹具也可以设置用户数据,和上面一样。

    想更新我们的角色或精灵的信息, 可以遍历所有的世界物体,取出对应的用户数据,然后更新信息, 示例

    1. Iterator<Body> bi = world.getBodies();  
    2.                  
    3. while (bi.hasNext()){  
    4.     Body b = bi.next();  
    5.   
    6.     // Get the bodies user data - in this example, our user   
    7.     // data is an instance of the Entity class  
    8.     Entity e = (Entity) b.getUserData();  
    9.   
    10.     if (e != null) {  
    11.         // Update the entities/sprites position and angle  
    12.         e.setPosition(b.getPosition().x, b.getPosition().y);  
    13.         // We need to convert our angle from radians to degrees  
    14.         e.setRotation(MathUtils.radiansToDegrees * b.getAngle());  
    15.     }  
    16. }  


    绘制部分还是和以前一样的。 没有什么改动。

     

    Sensors传感器
    传感器是当物体间碰撞,而又不产生自动响应。 比如, 我们想知道两个物体重叠的事件。

    这里需要设置'isSensor'为true。像这样

    1. //At the definition of the Fixture  
    2. fixtureDef.isSensor = true;  

    想监听它,需要实现ContactListener接口,在对应方法中实现自己的逻辑。

     

    传感器接口

    传感器接口监听fixture夹具的碰撞,方法包含一个传感对象, 传感对象包含了两个物体的有关信息, 当物体重叠的时候

    调用beginContact ,当物体分开的时候调用endContact

    1. public class ListenerClass implements ContactListener {  
    2.               
    3.       @Override  
    4.             public void endContact(Contact contact) {  
    5.                   
    6.             }  
    7.               
    8.             @Override  
    9.             public void beginContact(Contact contact) {  
    10.                   
    11.             }  
    12.         };  


    有时候, 我们需要得到游戏对象的信息, 怎么办呢?其实这个在我们需要在设置用户数据的时候, 把我们的游戏对象信息设置

    到body或者fixture中, 然后取出来, 做逻辑,比如,减血或其他。

     

    好了, Box2D的简单的了解,就到这了。 想深入学习,可以到他的官网查看。

     

    项目下载地址

     

    截屏

     

    转载请链接原文地址 http://blog.csdn.net/wu928320442/article/details/17285405


    展开全文
  • 博主在大学里学的专业就是软件开发与游戏设计,所以对于游戏这个行业一直都有着浓厚的兴趣,却因为 ... 最开始研究过一段时间的AndEngine游戏引擎,但是它的性能让我实在是不敢恭维,而且还有一些bug待完
  • 留心的朋友会发现,...LibGdx是一款基于OpenGL ES技术开发的Android游戏引擎,支持Android平台下的2D游戏开发,物理引擎采用Box2D实现 LibGdx是一个跨平台的2D/3D的游戏开发框架,它由Java/C/C++语言编写而成。它基
  • libgdx封装了Box2D物理引擎,通过这个引擎能够模拟物理现实,使设计出的游戏更具有真实感。 libgdx中,Box2d程序的大概过程: 1. 创建物理世界world,并设置重力加速度。 2. 创建正交相机,并设置其宽高。Box2d中...
  • 博主思来想去,觉得还是想把这个教程写的再细一点,让读者能够更清楚的了解LibGDX这个游戏引擎整体的架 构,所以也就总结出了这样一篇文章。   一、模块概述   作为游戏开发人员,我们需要一系列的系统组件是...
  • Libgdx引擎介绍

    2012-11-13 22:21:23
    Libgdx是一个跨平台(Windows,Linux,Android)的游戏开发框架,它主要是用Java写的,其中也参杂了一些C/C++代码,这些代码是为了处理一些对性能要求很高的操作,比如物理引擎或者音频处理。作为用户,你只需要关注...
  • 前言相比Ios UiKit原生支持物理引擎,Android确实麻烦的不要不要。...libgdx物理引擎其实是封装的native版本box2D,在满足性能需求的同时,避免了开发JNI的烦恼,对于java程序员来说目前是最便捷的方...
  • box2d 2.1的关节有9个类型, DistanceJoint 距离 FrictionJoint 摩擦 GearJoint 齿轮 LineJoint 线 MouseJoint 鼠标 PrismaticJoint 棱镜 PulleyJoint 滑轮 RevoluteJoint 旋转 ... ...
  •   本讲源代码下载: ...edu.nju.wsj.libgdx.rar(3.78 MB, 下载次数: 131) 2012-7-20 11:11 上传 点击文件名下载附件 下载积分: 下载豆 -2 复制代码 我们在第十讲中给大家介绍了Action
  • 这里只是为了对box2d物理引擎进行下简单的了解。如果想做物理类的游戏就有必要深入研究下了。 修改下我们上篇的代码,这里我把包名变化了下。 资源加载那块感觉还是很麻烦,干脆独立出来好了,新建一个专门负责加载...
  • 看了前面的几讲,相信大家都已经对这款游戏有了一定的了解,今天我们就来完成最后的工作:主人公的控制、碰撞检测, 主场景的移动。 1.主人公: 和添加platform一样,在World中添加Bob并初始化: ...
  • 这些物理元素都能改变物体的运动形式,并且默认都会唤醒物体,当然只是针对动态物体。 力是一个持久的效果,通过Box2d内置的积分器实现运动变化。 冲量是一个瞬时效果,能立马改变其效果。 主要函数: body....
  • LibGdx

    千次阅读 2019-03-04 01:42:26
    LibGdx分享 跨平台平台的游戏开发探究 复制代码 1.libgdx是什么 libgdx是一款跨平台可视化的游戏开发框架,它当前支持Windows,Linux,MacOs,Android,Blackberry,IOS和html5等. 复制代码 libgdx可以用java,Kotlin,Scala...
  • libgdx是一款基于OpenGL ES技术开发的Android游戏引擎,支持Android平台下的2D游戏开发,物理引擎采用Box2D实现。单就性能角度来说,堪称是一款非常强大的 Android游戏引擎,但缺陷在于精灵类等相关组件在使用上不够...
  • 游戏引擎libgdx简介

    2013-05-22 21:49:49
    Libgdx是什么 Libgdx是一个跨平台的游戏开发框架,作者之一就是写beginng android game的mario.它主要是用Java写的,部分性能要求比较高的地方用的是C/C++,它在android游戏开发和桌面游戏开发之上做了一个统一 接口...
  • Libgdx和jpct3D游戏引擎介绍

    千次阅读 2014-04-13 07:07:24
    Libgdx是一款基于OpenGL ES技术开发的Android游戏引擎,支持Android平台下的2D游戏开发,物理引擎采用Box2D实现。单就性能角度来说,堪称是一款非常强大的 Android游戏引擎, 缺点:(1)精灵类等相关组件在使用...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 847
精华内容 338
关键字:

libgdx物理引擎