This update was good fun to write, feels like quite a lot was achieved in not a lot of code :) I've now implemented collision detection, tilt control, a level timer, and world forces (gravity and terminal velocity).
Collision Detection
I added a bounding box to both the Bobo and Block classes. Bobo's bounds are updated whenever he is updated, this is not necessary in the case of static Block objects. The main game loop calls checkCollisions() each cycle, this is an inefficient but perfectly functional collision checking method:
private void checkCollisions() {
int numBlocks = level.getBlocks().size;
for (int i = 0; i < numBlocks; i++) {
Block block = level.getBlocks().get(i);
if (block.getBounds().overlaps(level.getBobo().getBounds())) {
level.getBobo().hitBlock();
}
}
}
If any Block bounding boxes overlap Bobo's bounding box, call bobo's hitBlock() method, which slows him right down:
public void hitBlock() {
velocity.set(0, -20);
}
The efficiency of the collision checking routine could be massively improved by only checking for collisions with nearby blocks that Bobo could possibly collide with (as opposed to every single block in the level), but I'm lazy and this will do the job for now...
Tilt Control
I made some changes to the handleInput method:
private void handleInput(float deltaTime) {
if (Gdx.app.getType() == Application.ApplicationType.Android) {
level.getBobo().moveBobo(deltaTime, Gdx.input.getAccelerometerX() * -50);
}
if (Gdx.app.getType() == Application.ApplicationType.Desktop) {
float moveBobo = 0;
if(Gdx.input.isKeyPressed(Input.Keys.LEFT)) moveBobo = -100f;
if(Gdx.input.isKeyPressed(Input.Keys.RIGHT)) moveBobo = 100f;
level.getBobo().moveBobo(deltaTime, moveBobo);
}
}
The if statements allow for platform specific controls - on Android use the accelerometer, on the desktop use the cursor keys. The user input results in a call to Bobo's moveBobo() method:
public void moveBobo (float deltaTime, float moveBobo) {
velocity.x = moveBobo;
update(deltaTime);
}
Basically, alter Bobo's velocity in accordance with the passed in parameters, then call bobo's update method:
public void update(float deltaTime) {
if (-velocity.y < TERMINAL_VELOCITY) {
velocity.add(Level.gravity.x * deltaTime, Level.gravity.y * deltaTime);
}
position.add(velocity.x * deltaTime, velocity.y * deltaTime);
bounds.set(position.x, position.y, WIDTH, HEIGHT);
}
If Bobo has not yet reached his terminal velocity on the y-axis, apply acceleration/gravity (a property of Level - "gravity = new Vector2(0, -30);") to his velocity, then update his position in respect of his velocity (and the time since last update), and update his bounding box to match his new position.
Level Timer
Finally, there's a timer to keep track of how long it takes to get to the end of the level. Currently it just outputs a message to the console, but that's enough to prove it works.
When the level is created, the current time is recorded (startTime = TimeUtils.nanoTime();).
checkGameover() is called on each cycle of the main game loop:
private void checkGameover() {
if (level.getBobo().getPosition().y <= level.getLevelEnd())
System.out.println("Finished level in "+(TimeUtils.nanoTime()-level.getStartTime())/1000000000+" seconds!");
}
And here's the Level getLevelEnd() method:
public int getLevelEnd() {
return -((levelHeight * Block.HEIGHT)-Bobo.HEIGHT);
}
That's it, nothing more to it :)
What Next?
At this point, the basic game mechanic is complete. I could (should??) go on to implement the other screens, the in game heads up display, the high score recording... But, err, I'm not happy with the game. The setting/story is a bit too convoluted, the uniform blocky walls are a bit rubbish, and the tilt controls feel a bit weird when controlling a character that's facing you and running down the screen.
I'm going to revisit the level generation code to get things looking a little less blocky, change the direction of play to up not down, and maybe change the setting from a running clown to something a bit more "normal", a racing car on a road, a speed boat on a river, or the old classic - a helicopter in a cavern.
You can checkout the game in its current state here if you like. It should look quite different come my next update!