zoukankan      html  css  js  c++  java
  • [libgdx游戏开发教程]使用Libgdx进行游戏开发(6)-添加主角和道具

    如前所述,我们的主角是兔子头。接下来我们实现它。

    首先对AbstractGameObject添加变量并初始化:

    public Vector2 velocity;
    public Vector2 terminalVelocity;
    public Vector2 friction;
    public Vector2 acceleration;
    public Rectangle bounds;

    分别是速度,极限速度,摩擦力,加速度和边界。

    然后我们需要加点物理仿真:

    protected void updateMotionX(float deltaTime) {
            if (velocity.x != 0) {
                // Apply friction
                if (velocity.x > 0) {
                    velocity.x = Math.max(velocity.x - friction.x * deltaTime, 0);
                } else {
                    velocity.x = Math.min(velocity.x + friction.x * deltaTime, 0);
                }
            }
            // Apply acceleration
            velocity.x += acceleration.x * deltaTime;
            // Make sure the object's velocity does not exceed the
            // positive or negative terminal velocity
            velocity.x = MathUtils.clamp(velocity.x, -terminalVelocity.x,
                    terminalVelocity.x);
        }
    
        protected void updateMotionY(float deltaTime) {
            if (velocity.y != 0) {
                // Apply friction
                if (velocity.y > 0) {
                    velocity.y = Math.max(velocity.y - friction.y * deltaTime, 0);
                } else {
                    velocity.y = Math.min(velocity.y + friction.y * deltaTime, 0);
                }
            }
            // Apply acceleration
            velocity.y += acceleration.y * deltaTime;
            // Make sure the object's velocity does not exceed the
            // positive or negative terminal velocity
            velocity.y = MathUtils.clamp(velocity.y, -terminalVelocity.y,
                    terminalVelocity.y);
        }

    然后在update里调用:

    updateMotionX(deltaTime);
    updateMotionY(deltaTime);
    // Move to new position
    position.x += velocity.x * deltaTime;
    position.y += velocity.y * deltaTime;

    这样所有的子类都拥有了这些物理特性。

    添加金币:

    package com.packtpub.libgdx.canyonbunny.game.objects;
    
    import com.badlogic.gdx.graphics.g2d.SpriteBatch;
    import com.badlogic.gdx.graphics.g2d.TextureRegion;
    import com.packtpub.libgdx.canyonbunny.game.Assets;
    
    public class GoldCoin extends AbstractGameObject {
        private TextureRegion regGoldCoin;
        public boolean collected;
    
        public GoldCoin() {
            init();
        }
    
        private void init() {
            dimension.set(0.5f, 0.5f);
            regGoldCoin = Assets.instance.goldCoin.goldCoin;
            // Set bounding box for collision detection
            bounds.set(0, 0, dimension.x, dimension.y);
            collected = false;
        }
    
        public void render(SpriteBatch batch) {
            if (collected)
                return;
            TextureRegion reg = null;
            reg = regGoldCoin;
            batch.draw(reg.getTexture(), position.x, position.y, origin.x,
                    origin.y, dimension.x, dimension.y, scale.x, scale.y, rotation,
                    reg.getRegionX(), reg.getRegionY(), reg.getRegionWidth(),
                    reg.getRegionHeight(), false, false);
        }
    
        public int getScore() {
            return 100;
        }
    }

    金币就一个图片,供玩家收集,收集一个就得100分,然后消失。

    创建羽毛:

    package com.packtpub.libgdx.canyonbunny.game.objects;
    
    import com.badlogic.gdx.graphics.g2d.SpriteBatch;
    import com.badlogic.gdx.graphics.g2d.TextureRegion;
    import com.packtpub.libgdx.canyonbunny.game.Assets;
    
    public class Feather extends AbstractGameObject {
        private TextureRegion regFeather;
        public boolean collected;
    
        public Feather() {
            init();
        }
    
        private void init() {
            dimension.set(0.5f, 0.5f);
            regFeather = Assets.instance.feather.feather;
            // Set bounding box for collision detection
            bounds.set(0, 0, dimension.x, dimension.y);
            collected = false;
        }
    
        public void render(SpriteBatch batch) {
            if (collected)
                return;
            TextureRegion reg = null;
            reg = regFeather;
            batch.draw(reg.getTexture(), position.x, position.y, origin.x,
                    origin.y, dimension.x, dimension.y, scale.x, scale.y, rotation,
                    reg.getRegionX(), reg.getRegionY(), reg.getRegionWidth(),
                    reg.getRegionHeight(), false, false);
        }
    
        public int getScore() {
            return 250;
        }
    }

    它的代码几乎和金币一样,就是分数高点。

    创建兔子头:

    我们需要根据羽毛来激活是否兔子头应该powerUp,当powerUp的时候,我们把兔子头变成黄色。

    package com.packtpub.libgdx.canyonbunny.game.objects;
    
    import com.badlogic.gdx.Gdx;
    import com.badlogic.gdx.graphics.g2d.SpriteBatch;
    import com.badlogic.gdx.graphics.g2d.TextureRegion;
    import com.packtpub.libgdx.canyonbunny.game.Assets;
    import com.packtpub.libgdx.canyonbunny.util.Constants;
    
    public class BunnyHead extends AbstractGameObject {
        public static final String TAG = BunnyHead.class.getName();
        private final float JUMP_TIME_MAX = 0.3f;
        private final float JUMP_TIME_MIN = 0.1f;
        private final float JUMP_TIME_OFFSET_FLYING = JUMP_TIME_MAX - 0.018f;
    
        public enum VIEW_DIRECTION {
            LEFT, RIGHT
        }
    
        public enum JUMP_STATE {
            GROUNDED, FALLING, JUMP_RISING, JUMP_FALLING
        }
    
        private TextureRegion regHead;
        public VIEW_DIRECTION viewDirection;
        public float timeJumping;
        public JUMP_STATE jumpState;
        public boolean hasFeatherPowerup;
        public float timeLeftFeatherPowerup;
    
        public BunnyHead() {
            init();
        }
    
        public void init() {
            dimension.set(1, 1);
            regHead = Assets.instance.bunny.head;
            // Center image on game object
            origin.set(dimension.x / 2, dimension.y / 2);
            // Bounding box for collision detection
            bounds.set(0, 0, dimension.x, dimension.y);
            // Set physics values
            terminalVelocity.set(3.0f, 4.0f);
            friction.set(12.0f, 0.0f);
            acceleration.set(0.0f, -25.0f);
            // View direction
            viewDirection = VIEW_DIRECTION.RIGHT;
            // Jump state
            jumpState = JUMP_STATE.FALLING;
            timeJumping = 0;
            // Power-ups
            hasFeatherPowerup = false;
            timeLeftFeatherPowerup = 0;
        }
    
        public void setJumping(boolean jumpKeyPressed) {
            switch (jumpState) {
            case GROUNDED: // Character is standing on a platform
                if (jumpKeyPressed) {
                    // Start counting jump time from the beginning
                    timeJumping = 0;
                    jumpState = JUMP_STATE.JUMP_RISING;
                }
                break;
            case JUMP_RISING: // Rising in the air
                if (!jumpKeyPressed)
                    jumpState = JUMP_STATE.JUMP_FALLING;
                break;
            case FALLING:// Falling down
            case JUMP_FALLING: // Falling down after jump
                if (jumpKeyPressed && hasFeatherPowerup) {
                    timeJumping = JUMP_TIME_OFFSET_FLYING;
                    jumpState = JUMP_STATE.JUMP_RISING;
                }
                break;
            }
        }
    
        public void setFeatherPowerup(boolean pickedUp) {
            hasFeatherPowerup = pickedUp;
            if (pickedUp) {
                timeLeftFeatherPowerup = Constants.ITEM_FEATHER_POWERUP_DURATION;
            }
        }
    
        public boolean hasFeatherPowerup() {
            return hasFeatherPowerup && timeLeftFeatherPowerup > 0;
        }
    
        @Override
        public void update(float deltaTime) {
            super.update(deltaTime);
            if (velocity.x != 0) {
                viewDirection = velocity.x < 0 ? VIEW_DIRECTION.LEFT
                        : VIEW_DIRECTION.RIGHT;
            }
            if (timeLeftFeatherPowerup > 0) {
                timeLeftFeatherPowerup -= deltaTime;
                if (timeLeftFeatherPowerup < 0) {
                    // disable power-up
                    timeLeftFeatherPowerup = 0;
                    setFeatherPowerup(false);
                }
            }
        }
    
        @Override
        protected void updateMotionY(float deltaTime) {
            switch (jumpState) {
            case GROUNDED:
                jumpState = JUMP_STATE.FALLING;
                break;
            case JUMP_RISING:
                // Keep track of jump time
                timeJumping += deltaTime;
                // Jump time left?
                if (timeJumping <= JUMP_TIME_MAX) {
                    // Still jumping
                    velocity.y = terminalVelocity.y;
                }
                break;
            case FALLING:
                break;
            case JUMP_FALLING:
                // Add delta times to track jump time
                timeJumping += deltaTime;
                // Jump to minimal height if jump key was pressed too short
                if (timeJumping > 0 && timeJumping <= JUMP_TIME_MIN) {
                    // Still jumping
                    velocity.y = terminalVelocity.y;
                }
            }
            if (jumpState != JUMP_STATE.GROUNDED)
                super.updateMotionY(deltaTime);
        }
    
        @Override
        public void render(SpriteBatch batch) {
            TextureRegion reg = null;
            // Set special color when game object has a feather power-up
            if (hasFeatherPowerup)
                batch.setColor(1.0f, 0.8f, 0.0f, 1.0f);
            // Draw image
            reg = regHead;
            batch.draw(reg.getTexture(), position.x, position.y, origin.x,
                    origin.y, dimension.x, dimension.y, scale.x, scale.y, rotation,
                    reg.getRegionX(), reg.getRegionY(), reg.getRegionWidth(),
                    reg.getRegionHeight(), viewDirection == VIEW_DIRECTION.LEFT,
                    false);
            // Reset color to white
            batch.setColor(1, 1, 1, 1);
        }
    }

    不太明白的可以看流程图:

    setJumping的流程:

    更新岩石:

        public void setLength(int length) {
            this.length = length;
            // Update bounding box for collision detection
            bounds.set(0, 0, dimension.x * length, dimension.y);
        }

     修改Level的init()和render()

    package com.packtpub.libgdx.canyonbunny.game;
    
    import com.badlogic.gdx.Gdx;
    import com.badlogic.gdx.graphics.Pixmap;
    import com.badlogic.gdx.graphics.g2d.SpriteBatch;
    import com.badlogic.gdx.utils.Array;
    import com.packtpub.libgdx.canyonbunny.game.objects.AbstractGameObject;
    import com.packtpub.libgdx.canyonbunny.game.objects.BunnyHead;
    import com.packtpub.libgdx.canyonbunny.game.objects.Clouds;
    import com.packtpub.libgdx.canyonbunny.game.objects.Feather;
    import com.packtpub.libgdx.canyonbunny.game.objects.GoldCoin;
    import com.packtpub.libgdx.canyonbunny.game.objects.Mountains;
    import com.packtpub.libgdx.canyonbunny.game.objects.Rock;
    import com.packtpub.libgdx.canyonbunny.game.objects.WaterOverlay;
    
    public class Level {
        public static final String TAG = Level.class.getName();
    
        public enum BLOCK_TYPE {
            EMPTY(0, 0, 0), // black
            ROCK(0, 255, 0), // green
            PLAYER_SPAWNPOINT(255, 255, 255), // white
            ITEM_FEATHER(255, 0, 255), // purple
            ITEM_GOLD_COIN(255, 255, 0); // yellow
            private int color;
    
            private BLOCK_TYPE(int r, int g, int b) {
                color = r << 24 | g << 16 | b << 8 | 0xff;
            }
    
            public boolean sameColor(int color) {
                return this.color == color;
            }
    
            public int getColor() {
                return color;
            }
        }
        public BunnyHead bunnyHead;
        public Array<GoldCoin> goldcoins;
        public Array<Feather> feathers;
        
        // objects
        public Array<Rock> rocks;
        // decoration
        public Clouds clouds;
        public Mountains mountains;
        public WaterOverlay waterOverlay;
    
        public Level(String filename) {
            init(filename);
        }
    
        private void init(String filename) {
            // player character
            bunnyHead = null;
            // objects
            rocks = new Array<Rock>();
            goldcoins = new Array<GoldCoin>();
            feathers = new Array<Feather>();
            // load image file that represents the level data
            Pixmap pixmap = new Pixmap(Gdx.files.internal(filename));
            // scan pixels from top-left to bottom-right
            int lastPixel = -1;
            for (int pixelY = 0; pixelY < pixmap.getHeight(); pixelY++) {
                for (int pixelX = 0; pixelX < pixmap.getWidth(); pixelX++) {
                    AbstractGameObject obj = null;
                    float offsetHeight = 0;
                    // height grows from bottom to top
                    float baseHeight = pixmap.getHeight() - pixelY;
                    // get color of current pixel as 32-bit RGBA value
                    int currentPixel = pixmap.getPixel(pixelX, pixelY);
                    // find matching color value to identify block type at (x,y)
                    // point and create the corresponding game object if there is
                    // a match
                    // empty space
                    if (BLOCK_TYPE.EMPTY.sameColor(currentPixel)) {
                        // do nothing
                    }
                    // rock
                    else if (BLOCK_TYPE.ROCK.sameColor(currentPixel)) {
                        if (lastPixel != currentPixel) {
                            obj = new Rock();
                            float heightIncreaseFactor = 0.25f;
                            offsetHeight = -2.5f;
                            obj.position.set(pixelX, baseHeight * obj.dimension.y
                                    * heightIncreaseFactor + offsetHeight);
                            rocks.add((Rock) obj);
                        } else {
                            rocks.get(rocks.size - 1).increaseLength(1);
                        }
                    }
                    // player spawn point
                    else if (BLOCK_TYPE.PLAYER_SPAWNPOINT.sameColor(currentPixel)) {
                        obj = new BunnyHead();
                        offsetHeight = -3.0f;
                        obj.position.set(pixelX,baseHeight * obj.dimension.y
                        + offsetHeight);
                        bunnyHead = (BunnyHead)obj;
                    }
                    // feather
                    else if (BLOCK_TYPE.ITEM_FEATHER.sameColor(currentPixel)) {
                        obj = new Feather();
                        offsetHeight = -1.5f;
                        obj.position.set(pixelX,baseHeight * obj.dimension.y
                        + offsetHeight);
                        feathers.add((Feather)obj);
                    }
                    // gold coin
                    else if (BLOCK_TYPE.ITEM_GOLD_COIN.sameColor(currentPixel)) {
                        obj = new GoldCoin();
                        offsetHeight = -1.5f;
                        obj.position.set(pixelX,baseHeight * obj.dimension.y
                        + offsetHeight);
                        goldcoins.add((GoldCoin)obj);
                    }
                    // unknown object/pixel color
                    else {
                        int r = 0xff & (currentPixel >>> 24); // red color channel
                        int g = 0xff & (currentPixel >>> 16); // green color channel
                        int b = 0xff & (currentPixel >>> 8); // blue color channel
                        int a = 0xff & currentPixel; // alpha channel
                        Gdx.app.error(TAG, "Unknown object at x<" + pixelX + "> y<"
                                + pixelY + ">: r<" + r + "> g<" + g + "> b<" + b
                                + "> a<" + a + ">");
                    }
                    lastPixel = currentPixel;
                }
            }
            // decoration
            clouds = new Clouds(pixmap.getWidth());
            clouds.position.set(0, 2);
            mountains = new Mountains(pixmap.getWidth());
            mountains.position.set(-1, -1);
            waterOverlay = new WaterOverlay(pixmap.getWidth());
            waterOverlay.position.set(0, -3.75f);
            // free memory
            pixmap.dispose();
            Gdx.app.debug(TAG, "level '" + filename + "' loaded");
        }
        
        public void update (float deltaTime) {
            bunnyHead.update(deltaTime);
            for(Rock rock : rocks)
            rock.update(deltaTime);
            for(GoldCoin goldCoin : goldcoins)
            goldCoin.update(deltaTime);
            for(Feather feather : feathers)
            feather.update(deltaTime);
            clouds.update(deltaTime);
        }
        
        public void render(SpriteBatch batch) {
            // Draw Mountains
            mountains.render(batch);
            // Draw Rocks
            for (Rock rock : rocks)
                rock.render(batch);
            // Draw Gold Coins
            for (GoldCoin goldCoin : goldcoins)
            goldCoin.render(batch);
            // Draw Feathers
            for (Feather feather : feathers)
            feather.render(batch);
            // Draw Player Character
            bunnyHead.render(batch);
            // Draw Water Overlay
            waterOverlay.render(batch);
            // Draw Clouds
            clouds.render(batch);
        }
    }

    最后修改controller的update:level.update(deltaTime);

    增加游戏逻辑:在相应的object加上碰撞方法和相应处理

    也可以都交给controller,比如在WorldController中加入:

    // Rectangles for collision detection
        private Rectangle r1 = new Rectangle();
        private Rectangle r2 = new Rectangle();
    
        private void onCollisionBunnyHeadWithRock(Rock rock) {
        };
    
        private void onCollisionBunnyWithGoldCoin(GoldCoin goldcoin) {
        };
    
        private void onCollisionBunnyWithFeather(Feather feather) {
        };
    
        private void testCollisions() {
            r1.set(level.bunnyHead.position.x, level.bunnyHead.position.y,
                    level.bunnyHead.bounds.width, level.bunnyHead.bounds.height);
            // Test collision: Bunny Head <-> Rocks
            for (Rock rock : level.rocks) {
                r2.set(rock.position.x, rock.position.y, rock.bounds.width,
                        rock.bounds.height);
                if (!r1.overlaps(r2))
                    continue;
                onCollisionBunnyHeadWithRock(rock);
                // IMPORTANT: must do all collisions for valid
                // edge testing on rocks.
            }
            // Test collision: Bunny Head <-> Gold Coins
            for (GoldCoin goldcoin : level.goldcoins) {
                if (goldcoin.collected)
                    continue;
                r2.set(goldcoin.position.x, goldcoin.position.y,
                        goldcoin.bounds.width, goldcoin.bounds.height);
                if (!r1.overlaps(r2))
                    continue;
                onCollisionBunnyWithGoldCoin(goldcoin);
                break;
            }
            // Test collision: Bunny Head <-> Feathers
            for (Feather feather : level.feathers) {
                if (feather.collected)
                    continue;
                r2.set(feather.position.x, feather.position.y,
                        feather.bounds.width, feather.bounds.height);
                if (!r1.overlaps(r2))
                    continue;
                onCollisionBunnyWithFeather(feather);
                break;
            }
        }

    现在3个碰撞事件都是空的,实现逻辑是这样的:

    private void onCollisionBunnyHeadWithRock(Rock rock) {
            BunnyHead bunnyHead = level.bunnyHead;
            float heightDifference = Math.abs(bunnyHead.position.y
                    - (rock.position.y + rock.bounds.height));
            if (heightDifference > 0.25f) {
                boolean hitLeftEdge = bunnyHead.position.x > (rock.position.x + rock.bounds.width / 2.0f);
                if (hitLeftEdge) {
                    bunnyHead.position.x = rock.position.x + rock.bounds.width;
                } else {
                    bunnyHead.position.x = rock.position.x - bunnyHead.bounds.width;
                }
                return;
            }
            switch (bunnyHead.jumpState) {
            case GROUNDED:
                break;
            case FALLING:
            case JUMP_FALLING:
                bunnyHead.position.y = rock.position.y + bunnyHead.bounds.height
                        + bunnyHead.origin.y;
                bunnyHead.jumpState = JUMP_STATE.GROUNDED;
                break;
            case JUMP_RISING:
                bunnyHead.position.y = rock.position.y + bunnyHead.bounds.height
                        + bunnyHead.origin.y;
                break;
            }
        }
    
        private void onCollisionBunnyWithGoldCoin(GoldCoin goldcoin) {
            goldcoin.collected = true;
            score += goldcoin.getScore();
            Gdx.app.log(TAG, "Gold coin collected");
        }
    
        private void onCollisionBunnyWithFeather(Feather feather) {
            feather.collected = true;
            score += feather.getScore();
            level.bunnyHead.setFeatherPowerup(true);
            Gdx.app.log(TAG, "Feather collected");
        }

    试试效果,在WorldController的update加入:testCollisions();

    跑起来,看看:

    操作键:上,下,左,右,逗号,点等键。

     最后,我们跟前面一样,让摄像机跟随兔子头:在Controller的initLevel中添加cameraHelper.setTarget(level.bunnyHead);

    修改handleDebugInput()和keyUp():

    @Override
        public boolean keyUp(int keycode) {
            if (keycode == Keys.R) {
                init();
                Gdx.app.debug(TAG, "Game World Resetted!");
            }// Toggle camera follow
            else if (keycode == Keys.ENTER) {
                cameraHelper.setTarget(cameraHelper.hasTarget() ? null
                        : level.bunnyHead);
                Gdx.app.debug(TAG,
                        "Camera follow enabled: " + cameraHelper.hasTarget());
            }
            return false;
        }
    
        private void handleInputGame(float deltaTime) {
            if (cameraHelper.hasTarget(level.bunnyHead)) {
                // Player Movement
                if (Gdx.input.isKeyPressed(Keys.LEFT)) {
                    level.bunnyHead.velocity.x = -level.bunnyHead.terminalVelocity.x;
                } else if (Gdx.input.isKeyPressed(Keys.RIGHT)) {
                    level.bunnyHead.velocity.x = level.bunnyHead.terminalVelocity.x;
                } else {
                    // Execute auto-forward movement on non-desktop platform
                    if (Gdx.app.getType() != ApplicationType.Desktop) {
                        level.bunnyHead.velocity.x = level.bunnyHead.terminalVelocity.x;
                    }
                }
                // Bunny Jump
                if (Gdx.input.isTouched() || Gdx.input.isKeyPressed(Keys.SPACE))
                    level.bunnyHead.setJumping(true);
                else
                    level.bunnyHead.setJumping(false);
            }
        }
    private void handleDebugInput(float deltaTime) {
            if (Gdx.app.getType() != ApplicationType.Desktop)
                return;
            if (!cameraHelper.hasTarget(level.bunnyHead)) {
                // Camera Controls (move)
                float camMoveSpeed = 5 * deltaTime;
                float camMoveSpeedAccelerationFactor = 5;
                if (Gdx.input.isKeyPressed(Keys.SHIFT_LEFT))
                    camMoveSpeed *= camMoveSpeedAccelerationFactor;
                if (Gdx.input.isKeyPressed(Keys.LEFT))
                    moveCamera(-camMoveSpeed, 0);
                if (Gdx.input.isKeyPressed(Keys.RIGHT))
                    moveCamera(camMoveSpeed, 0);
                if (Gdx.input.isKeyPressed(Keys.UP))
                    moveCamera(0, camMoveSpeed);
                if (Gdx.input.isKeyPressed(Keys.DOWN))
                    moveCamera(0, -camMoveSpeed);
                if (Gdx.input.isKeyPressed(Keys.BACKSPACE))
                    cameraHelper.setPosition(0, 0);
            }
            // Camera Controls (zoom)
            float camZoomSpeed = 1 * deltaTime;
            float camZoomSpeedAccelerationFactor = 5;
            if (Gdx.input.isKeyPressed(Keys.SHIFT_LEFT))
                camZoomSpeed *= camZoomSpeedAccelerationFactor;
            if (Gdx.input.isKeyPressed(Keys.COMMA))
                cameraHelper.addZoom(camZoomSpeed);
            if (Gdx.input.isKeyPressed(Keys.PERIOD))
                cameraHelper.addZoom(-camZoomSpeed);
            if (Gdx.input.isKeyPressed(Keys.SLASH))
                cameraHelper.setZoom(1);
        }

    在update里加上handleInputGame(deltaTime);

    大家都知道有更加成熟的Box2D可以仿真物理世界。但是我们的兔子游戏并不是完全精确的仿真物理,甚至还有比较超物理的动作,如果用Box2D来模拟不真实的物理效果是很麻烦和多余的。

    掉命,游戏结束以及其他:

    我们通常都会在游戏结束之后经过3秒的过渡再跳转画面。

    首先定义常量在Constants:// Delay after game over
    public static final float TIME_DELAY_GAME_OVER = 3;

    把下面的代码加到WorldController:判断玩家掉水里了没

        private float timeLeftGameOverDelay;
    
        public boolean isGameOver() {
            return lives < 0;
        }
    
        public boolean isPlayerInWater() {
            return level.bunnyHead.position.y < -5;
        }

    修改init()和update():死掉一条命,右上角的小兔头就变透明

    private void init() {
            Gdx.input.setInputProcessor(this);
            cameraHelper = new CameraHelper();
            lives = Constants.LIVES_START;
            timeLeftGameOverDelay = 0;
            initLevel();
        }
    
        public void update(float deltaTime) {
            handleDebugInput(deltaTime);
            if (isGameOver()) {
                timeLeftGameOverDelay -= deltaTime;
                if (timeLeftGameOverDelay < 0)
                    init();
            } else {
                handleInputGame(deltaTime);
            }
            level.update(deltaTime);
            testCollisions();
            cameraHelper.update(deltaTime);
            if (!isGameOver() && isPlayerInWater()) {
                lives--;
                if (isGameOver())
                    timeLeftGameOverDelay = Constants.TIME_DELAY_GAME_OVER;
                else
                    initLevel();
            }
        }

    看看效果怎么样。

    为了防止摄像机向下移动的太快,修改CameraHelpe的update()

    public void update (float deltaTime) {
    if (!hasTarget()) return;
    position.x = target.position.x + target.origin.x;
    position.y = target.position.y + target.origin.y;
    // Prevent camera from moving down too far
    position.y = Math.max(-1f, position.y);
    }

    在WorldRenderer中加上game over的信息:

        private void renderGuiGameOverMessage(SpriteBatch batch) {
            float x = cameraGUI.viewportWidth / 2;
            float y = cameraGUI.viewportHeight / 2;
            if (worldController.isGameOver()) {
                BitmapFont fontGameOver = Assets.instance.fonts.defaultBig;
                fontGameOver.setColor(1, 0.75f, 0.25f, 1);
                fontGameOver.drawMultiLine(batch, "GAME OVER", x, y, 0,
                        BitmapFont.HAlignment.CENTER);
                fontGameOver.setColor(1, 1, 1, 1);
            }
        }

    加上兔子捡到羽毛的剩余时间:

    private void renderGuiFeatherPowerup(SpriteBatch batch) {
            float x = -15;
            float y = 30;
            float timeLeftFeatherPowerup = worldController.level.bunnyHead.timeLeftFeatherPowerup;
            if (timeLeftFeatherPowerup > 0) {
                // Start icon fade in/out if the left power-up time
                // is less than 4 seconds. The fade interval is set
                // to 5 changes per second.
                if (timeLeftFeatherPowerup < 4) {
                    if (((int) (timeLeftFeatherPowerup * 5) % 2) != 0) {
                        batch.setColor(1, 1, 1, 0.5f);
                    }
                }
                batch.draw(Assets.instance.feather.feather, x, y, 50, 50, 100, 100,
                        0.35f, -0.35f, 0);
                batch.setColor(1, 1, 1, 1);
                Assets.instance.fonts.defaultSmall.draw(batch, ""
                        + (int) timeLeftFeatherPowerup, x + 60, y + 57);
            }
        }

    然后把新加的这两个方法加入到renderGUI();

    private void renderGui (SpriteBatch batch) {
    batch.setProjectionMatrix(cameraGUI.combined);
    batch.begin();
    // draw collected gold coins icon + text
    // (anchored to top left edge)
    renderGuiScore(batch);
    // draw collected feather icon (anchored to top left edge)
    renderGuiFeatherPowerup(batch);
    // draw extra lives icon + text (anchored to top right edge)
    renderGuiExtraLive(batch);
    // draw FPS text (anchored to bottom right edge)
    renderGuiFpsCounter(batch);
    // draw game over text
    renderGuiGameOverMessage(batch);
    batch.end();
    }

    Nice!到这里,游戏的主体基本完成了。犒赏一下自己,嗯,实在太棒了!多玩一玩自己的杰作,等休息好了我们再继续。

    在下一章,我们将给游戏加上进入游戏之前的菜单界面,让游戏完整。

  • 相关阅读:
    TdxGaugeControl
    TdxSkinController
    delphi TdxMemData 使用
    深入方法(16)- 方法的顺序
    深入方法(15)- 调用其他单元的函数
    深入方法(14)- 在TForm1 类内声明的方法
    深入方法(13)- 在 interface 区声明的方法
    深入方法(12)- implementation 区中的方法
    深入方法(11)- 参数前缀
    深入方法(10)- 默认参数
  • 原文地址:https://www.cnblogs.com/mignet/p/libgdx_game_development_06.html
Copyright © 2011-2022 走看看