注:请务必结合代码理解!
上一节已经分析了游戏的刷新过程,那么接下来要说的就是碰撞检测了,还是回到一切的源头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/