[案例研究]—superJumper 6.碰撞检测与游戏结束

注:请务必结合代码理解!

上一节已经分析了游戏的刷新过程,那么接下来要说的就是碰撞检测了,还是回到一切的源头World.update()方法:

   public void update(float deltaTime, float accelX) {
        updateBob(deltaTime, accelX);
        updatePlatforms(deltaTime);
        updateSquirrels(deltaTime);
        updateCoins(deltaTime);
        if (bob.state != Bob.BOB_STATE_HIT)
            checkCollisions();
        checkGameOver();
    }
当所有的物体都更新完毕,并且Bob的状态不是Bob.BOB_STATE_HIT时,那么就会执行checkCollisions(),代码如下:

    private void checkCollisions() {
        checkPlatformCollisions();
        checkSquirrelCollisions();
        checkItemCollisions();
        checkCastleCollisions();
    }
同样的把碰撞检测分成了几个部分,分别是:Bob对Platform,Bob对Squirrel,Bob对Item(Coin和Spring)以及Bob对Castle。原理都是一样的,只要看一个就够了, checkPlatformCollisions(),代码如下:

  private void checkPlatformCollisions() {
        if (bob.velocity.y > 0)
            return;

        int len = platforms.size();
        for (int i = 0; i < len; i++) {
            Platform platform = platforms.get(i);
            if (bob.position.y > platform.position.y) {
                if  (OverlapTester
                        .overlapRectangles(bob.bounds, platform.bounds)) {
                     bob.hitPlatform();
                     listener.jump();
                    if (rand.nextFloat() > 0.5f) {
                        platform.pulverize();
                    }
                    break;
                }
            }
        }
    }
碰撞检测的原理就是,通过把Bob的作用范围 bounds与其他物体的对比,对比的方法如同前提到的OverlapTester .overlapRectangles() 传入两个矩形(Retrangle),如果碰撞就返回true,否则返回false。

那么相应的,在这个checkPlatformCollisions()方法里,如果Bob 被检测碰撞到platform,则调用bob.hitPlatform(),并且播放声音。而bob.hitPlatform()做的就是改变Bob的状态,并把它的velocity.y重新赋值为11( 如同前面提到的),也就是重新赋予他跳跃的能力。
这也是为什么所有游戏物体的update方法中,要实时更新bounds(作用范围)的原因,因为,物体的bouns必须是准确的,否则,在碰撞检测中就会出现你不想发生的情形。

当checkCollisions()方法被执行完毕,也就碰撞检测完后,还会执行一个checkGameOver() 方法,代码如下:

   private void checkGameOver() {
        if (heightSoFar - 7.5f > bob.position.y) {
            state = WORLD_STATE_GAME_OVER;
        }
    }

这个方法就是检测Bob是否摔死,也就是否跌落只屏幕的下边界。而判断的依据就是bob.position.y 是否小于heightSoFar-7.5f 这个值。heightSoFar就是Bob在跳跃中的最高点坐标,它在World.updateBob()方法中,被不断的更新,以记录最新的最高点坐标。而heightSoFar-7.5f 表示的就是屏幕的下边界Y坐标的值。记住,游戏中的物体使用的是WorldRender中的OrthographicCamer,也就是当前屏幕的高度为15个单位,而WorldRender中的OrthographicCamer它的Y坐标是与Bob实时更新的(前面已分析)。也就是说屏幕中点的
Y坐标的值就是等于heightSoFar。所以heightSoFar-7.5f 表示的就是屏幕的下边界Y坐标的值。
如果bob.position.y 小于heightSoFar-7.5f就是表明,Bob摔出了下边界,那么游戏就结束了。

当World.update()被执行完,也就是游戏物体都刷新了,碰撞检测也完了,checkGameOver()也执行完了。那么就会回到GameScreen的
updateRunning() 方法继续执行后续的代码:

private void updateRunning (float deltaTime) {
                 //得到触碰点的位置
if (Gdx.input.justTouched()) {
guiCam.unproject(touchPoint.set(Gdx.input.getX(), Gdx.input.getY(), 0));
                         //是否点击了暂停键
if (OverlapTester.pointInRectangle(pauseBounds, touchPoint.x, touchPoint.y)) {
Assets.playSound(Assets.clickSound);
state = GAME_PAUSED;
return;
}
}

                 //监听按键
if(Gdx.app.getType() == Application.ApplicationType.Android) { 
world.update(deltaTime, Gdx.input.getAccelerometerX());
}
else {
float accel = 0;
if(Gdx.input.isKeyPressed(Keys.DPAD_LEFT))
accel = 5f;
if(Gdx.input.isKeyPressed(Keys.DPAD_RIGHT))
accel = -5f;
world.update(deltaTime, accel);
}

                 //刷新分数
if (world.score != lastScore) {
lastScore = world.score;
scoreString = "SCORE: " + lastScore;
}

                 //是否通关
if (world.state == World.WORLD_STATE_NEXT_LEVEL) {
state = GAME_LEVEL_END;
}

                 //是否游戏结束
if (world.state == World.WORLD_STATE_GAME_OVER) {
state = GAME_OVER;
if (lastScore >= Settings.highscores[4])
scoreString = "NEW HIGHSCORE: " + lastScore;
else
scoreString = "SCORE: " + lastScore;
Settings.addScore(lastScore);
Settings.save();
  }
}

当world.update(deltaTime, accel) 执行完后,也就说游戏中物体的状态可能已经发生了改变。那么首先是刷新分数,然后是判断World的状态state,如果为World.WORLD_STATE_NEXT_LEVEL,那么就把GameScreen的state切换为GAME_LEVEL_END,表示主角Bob通关了;如果为World.WORLD_STATE_GAME_OVER,那么就把GameScreen的state切换 GAME_OVER ,表示Bob为能通过,游戏结束,同时还要记录最高分。而World的状态state正是在World.checkCollisions()方法中根据不同的碰撞事件改变的。

如果World的状态state 为World.WORLD_STATE_RUNNING , 那么游戏就会正常进行下去,直到状态被改变。


假设主角Bob不幸死亡(摔死或被飞行松鼠撞死),那么GameScreen中的state就被切换成GAME_OVER,相应的present()中会执行
presentGameOver()方法,打出GameOver的字样。而update()执行的就是updateGameOver()方法,代码如下:

private void updateGameOver () {
if(Gdx.input.justTouched()) {
game.setScreen(new MainMenuScreen(game));
}
}
也就是说只要一发生触屏事件,就把Screen切换会主菜单,一切重新开始。这样一个游戏的完整流程就结束了。


至此,superJumper 这个案例也就分析结束。其他的一些小细节,通过读代码就能理解了。希望这一系列的文章,能加深大家对libgdx的理解。本人能力有限,如有不妥的地方,欢迎大家j纠正!


欢迎转载!请注明原文链接,谢谢!  http://tonmly.blog.163.com/blog/static/174712856201171104651470/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值