美文网首页
在Android上使用libgdx-box2d物理引擎

在Android上使用libgdx-box2d物理引擎

作者: Answer67 | 来源:发表于2019-04-10 13:36 被阅读0次

    前言

    相比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,先水一波。

    相关文章

      网友评论

          本文标题:在Android上使用libgdx-box2d物理引擎

          本文链接:https://www.haomeiwen.com/subject/brcniqtx.html