Showing posts with label development. Show all posts
Showing posts with label development. Show all posts

Saturday, 27 December 2014

Sensory - a cause and effect light show app

While testing my latest game (Jewel Match Blitz) it became apparent that TheInvaderOne (my 9 month old daughter) was very interested in what was going on. She has always been interested in the laptop, but the phones and tablets with their sounds and bright coloured lights and tappable screens took it to another level! Testing Jewel Match Blitz soon became quite a challenge! :) I'd hand her the device to play a little, and she had great fun until it was game over - at 9 months old she was never going to be particularly great at playing a strategic action puzzle game so the game overs came thick and fast!

https://play.google.com/store/apps/details?id=com.theinvader360.jewel.match.blitz.game.free.android

The experience got me thinking about what kind of app would be suitable for a baby. TheInvaderOne loves touching the screen and seeing something happen, and feedback in the form of sound effects and bright lights never fail to raise a smile. I created a very small demo app for her using the particle effect already used in Jewel Match Blitz. When you touch the screen a particle effect is triggered at that position, keep touching and more particles are triggered. The app is multitouch enabled so up to 10 points can spawn particles in assorted colours simultaneously. She absolutely loves it!

https://play.google.com/store/apps/details?id=com.theinvader360.sensory.app.free.android

I soon realised that other babies, and potentially SEN children and adults with various learning difficulties, special education needs, and/or disabilities could also benefit from the Sensory app, so I decided to package it up and make available on the google play app store. It is 100% free and is not monetized in any way, ads in an app targeted at users with limited understanding where the aim is to randomly tap the screen would be extremely bad karma! You can find the app here - https://play.google.com/store/apps/details?id=com.theinvader360.sensory.app.free.android

I also figured that there are a few interesting principles involved in this tiny app that might mean it's of interest to other developers, especially those getting started with LibGdx. The app touches on particle effects, object pooling, multitouch, screen transitions, scene 2d ui, the asset manager, etc. The excellent Simple Game example touches on most of the main areas involved when making a basic game (assets, game loop, input, draw, sound). I think the Sensory app builds on that foundation to illustrate simply and clearly how to handle some of the more intermediate LibGdx features. You can find the open source project on github, hopefully it will be of interest to fellow developers interested in making games with LibGdx - https://github.com/TheInvader360/sensory

I'd be over the moon to hear that the little "side effect" offshoot of Jewel Match Blitz ended up helping you in some way, so please leave a 5* review of the app if you can (and maybe leave something in the comments here too!)

Saturday, 19 April 2014

LibGdx Google Mobile Ads SDK Tutorial

The number one ad service being used by Android and LibGdx developers at the moment is Google AdMob.

If you've not updated your app recently you should consider doing so soon. Google says:

Android (6.4.1 and earlier SDKs)
Deprecated. On August 1, 2014, Google Play will stop accepting new or updated apps that use the old standalone Google Mobile Ads SDK v6.4.1 or lower. You must upgrade to the Google Play version of the Mobile Ads SDK by then.

Ok, so we want to migrate to the new Google Play Services way of doing things - this blog post walks you through the process :)

Install this apk to see what we'll be building!

----------

Barebones Sample App

First thing I did was grab an up to date version of libgdx. They are now up to 0.9.9 stable, I'm sure there is a lot of awesome new stuff in there for me to investigate, but TheInvaderOne isn't really leaving me with a lot of time for Android these days so that'll have to wait!

Next I created a new libgdx project using gdx-setup-ui.jar (see this old post for a walkthrough), added a .gitignore file, and made my initial commit.


Eclipse Setup

In eclipse, import the barebones sample app (file > import > existing projects into workspace) - you should now have at least three projects in package explorer (core, android, and desktop).

Open the Android SDK Manager, download the latest SDK Platform and Google APIs (at time of writing: 4.4.2/API19), the 2.3.1/API9 SDK Platform, and from Extras - Google Play Services.

Locate the <android-sdk>/extras/google/google_play_services/libproject/google-play-services_lib/ directory on your machine (on my windows machine - C:\Program Files (x86)\Android\android-sdk\extras\google\google_play_services\libproject\google-play-services_lib) and copy into your working directory alongside the existing libgdx projects.

File > Import > Android > Existing Android Code, Next, Browse, navigate to the local copy of google-play-services_lib in your working directory, Ok, Finish.

Right-click your android project, select Properties, Android, scroll down and click Add, select the google-play-services_lib project, Ok.

A refresh and clean in eclipse probably wouldn't hurt at this point, so go ahead and do that.


AndroidManifest.xml

Ensure that the target in android project's project.properties file is at least 13, and the android:minSdkVersion in your AndroidManifest.xml is at least 9. Sadly this does mean users running ancient versions of Android will be excluded, but there's nothing we can do about this. There are very very VERY few devices still running versions below 2.3/API9, so at least you won't be excluding many users...

Add these two lines as children of the 'application' element:
<meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version"/><activity android:name="com.google.android.gms.ads.AdActivity" android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize"/>

Add these two permissions as children of the 'manifest' element:
<uses-permission android:name="android.permission.INTERNET"/><uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

Save changes, then refresh and clean in eclipse for good luck...


Banner Ad

See this version of the android project's MainActivity class for a reasonably straightforward banner ad implementation.


Interstitial Ad

This diff shows an interstitial ad implementation (ActionResolver interface lets us trigger interstitial actions from the core project while retaining the invaluable LibGdx cross-platform functionality).

----------

That's all there is to it!

As always, please feel free to leave comments below. I can't really offer support - TheInvaderOne and "Real Life Day Job" leave me very little free time these days, but other visitors will often leave helpful solutions, and if I find a spare moment every now and then I do try to answer any unresolved queries.

Anyway, I hope you have fun making your games - be sure to leave a note here if you release something on google play or the amazon market, I'm always happy to check out new games :)

PS - one final note if cloning from https://github.com/TheInvader360/tutorial-libgdx-google-ads, pay attention to the problems view in eclipse! You will need to create an empty 'gen' directory in both the google-play-services_lib and tutorial-libgdx-google-ads-android projects, and ensure you have the required android sdks installed. As is often the case with eclipse, a liberal amount of refreshing and cleaning will do no harm...

Sunday, 9 February 2014

Back with a new game - Little Fish

I've been away from the world of Android Games for a little while, but I do have a couple of good excuses:

  1. My role has changed at work and I am now a developer - this is pretty awesome. Ok so it's dry databases and stuff, not games, but I'm getting paid to do what I enjoy, and am feeling pretty good about that! It does mean more of my spare time being spent on work related learning though, so a little less time for Android Game development.
  2. Even bigger news than career change... We're expecting our first baby!!! TheInvaderOne should be delivered by the stork at the end of next month :-o Preparing for the arrival of a human worm baby takes up a lot of time, though of course nowhere near as much time as once she has actually arrived. Spending time with her will be way higher up the list of priorities than playing with Android, so I either need to drop my hobby, or make it more efficient...

What I have been doing over the past few months (as and when I found a few spare hours here and there) is working on a sort of 'white label' app built on top of LibGdx. It includes a lot of the dull and boring to implement stuff that I end up doing over an over again, highscores, user preferences, ads, facebook integration, google play game services integration, splash screen, etc. In theory I will be able to use this as a quick start platform to speed up the game production process in future. I don't currently have plans to open source this as it's a bit too closely tied to my own stuff, and decoupling would take valuable time that could be better spent making games, but maybe sometime in the future it'll be an option.

I'm hoping that this quick start platform will allow me to continue making Android Games even after baby has arrived. The recent success of Flappy Bird proves that a game doesn't have to be sophisticated to become a runaway success. At its core it's a simple game (basically a reskinned helicopter game), with simple graphics. I'm sure the developer wouldn't mind me saying a similar game could be built in a single weekend, especially when leveraging a quick start platform. I've had some success in the past with my Racing Game and Quack Attack that proves the same point, simple/fun/addictive beats complicated/polished/boring. So, in future I can focus more on game mechanics and less on the surrounding app furniture, this can only be a good thing :)

I've just published my first game that makes use of the white label quick start sausage machine (catchy name) "Little Fish". The gameplay is pretty simple - you control a little fish that eats smaller fish. Bigger fish will eat your little fish, so avoid them! There's the added complication of poison fish that you must avoid at all costs (even if they're tiny). Once you've eaten enough little fishies (empty hunger meter), you progress to the next level where you'll be a bit bigger. Of course the screen is no bigger, so dodging the predators will get harder the more you progress! Simple game, but fun and addictive :)


I've added a couple of new features to Little Fish too. First there's a kids mode, there are no gameovers in this mode (unless you choose to quit) the tradeoff being no global leaderboard score submission. I've seen lots of little children want to play mobile and tablet games recently, but when they are very small it can be frustrating losing quickly, the kids mode will help keep them happy and occupied for longer. It can also double as a training mode, once the child has mastered the more forgiving kids mode, they can try the more challenging normal mode! The other new feature is extended controller support. Not only can you choose to control the Little Fish by touch or tilt, you can also use the dpad of an xperia play (and hopefully any other android device that has a control pad) or a HID compliant external controller. The guys over at Moga recently sent me some awesome free stuff, and it was an absolute breeze to get Little Fish working with the Moga in HID mode. When I've had time to play with the Moga SDK properly I expect I'll write a blog post dedicated to that.


I hope you'll check out Little Fish and of course all my other games. As always, I hope you have fun!

Saturday, 19 October 2013

LibGDX Google Play Game Services Tutorial


Google Play Game Services offers cross platform social leaderboards, achievements, and much more (realtime multiplayer, cloud saves, anti-piracy...). I've started implementing google play game services leaderboards and achievements in my LibGDX Android Games, and the purpose of this blog article is to walk through the process so you can do the same!

  • I've published an example project on Google Play check it out!
  • The example project is freely available on GitHub check that out too!
  • You can also get the complete (free) version of Super Jump a Doodle here!

Continue reading after the jump to find out how to add these features to your own games!


Monday, 10 June 2013

One million installs!


1,066,345+ users have installed my LibGDX Android games :)

Due to reporting lag that number is a few days out of date, and it doesn't include installs from third party scraper style stores, so the real number will be a little higher, but I can safely say I have over a million installs in total. Awesome :)

So, how do the various markets stack up?

Sunday, 26 May 2013

Street Race Swipe LibGDX Scene2D Tutorial



I have been meaning to write a LibGDX Scene2D tutorial for some time now (ever since my Quack Attack FREE Duck Hunt Game got ridiculously popular). The problem has been finding the time, instead of writing blog entries I've been making games!

I had a great idea for a multitasking game, play four independent games at one time to train your brain and test your ability to multitask. The result was my 4 Games 1 Screen FREE Brain Training Game. I built this game as four separate games from the outset, with the intention of possibly building further on each minigame and releasing as standalone apps. The first of these standalone apps is Street Race Swipe Racing Game, which brings us neatly to the point of this article...


Street Race Swipe Racing Game is such a simple game at its heart that it seems like an excellent candidate for a tutorial article :) I remember being massively impressed by the example SimpleApp on the LibGDX wiki when first starting out, there was so little to it but it touched on all the basics of what is needed to make a game. I'm hoping this mini project will be almost as simple and just as helpful to others!

Monday, 17 December 2012

Tower Defence - Slacker's Diary


I've been slacking recently. Between work, Christmas preparations, and home improvements, there's not been a whole lot of time left over to work on Android games. Anyway, that's enough of the excuses, question is - what am I going to do about it?

I've made a little progress on Tower Defence, but the plan is to put it on the back burner for now, keep working on it whenever I have a nice block of time to dedicate to it, but if I only have an hour or so available at a time to work on more trivial projects instead. I love the momentum that builds up when working on really small simple games, and I'm hoping to get a few of these little games started and finished in the next few months, and just keep chipping away at TD as a longer term project.

Here's a video of the tower defence game as it stands:


Most of the basics are there really, but getting the game finished involves quite a few tasks, not all of them trivial - adding enemy waves, turret upgrades, multiple enemy types, multiple turret types, lots of level maps, level unlocking, graphical improvements, game balancing, etc. I might put an early unfinished version of the game up on the market at some point, maybe with rough graphics, just a handful of levels, and not the best balancing, but I worry that if I do that I might never finish the game properly!

On a positive note, keep your eyes peeled for a new project starting soon! :)

Tuesday, 20 November 2012

Tower Defence - First Progress Report


My last post was very wordy. This one should make up for that...

Here's what I've got so far:



It's starting to look a little like a TD game :)

Next up - I think it's time to get them turrets a'shootin!


Sunday, 21 October 2012

Making a game in a weekend… Can it be done?


UPDATE - Download the finished game for free here!

I’d like to enter a Ludum Dare 48 hour competition one day, but I don’t think I’m ready yet. Create a finished game in a single weekend, sounds like a monster task!
This weekend I decided to give it a test run, see how far I can get in a couple of days. The answer is – further than I’d have guessed! Here’s a runthrough of the process…


Saturday, 25 August 2012

First 3D project

As expected, I ended up starting a new project... It's quite a leap up from what was achieved in Race Game.

Laptop video (shows 2D and 3D rendering plus raw map files):


Android video (shows smooth 3D rendering on android device):


Next steps will include:
  • Control scheme to suit android devices
  • Nice 3D models for keys, treasures, etc
  • Animated opening doors (quite how is a mystery!)
  • Cartoony / cutesy graphics and sound
  • Level select screen
  • Level complete screen
  • Game complete screen
  • Efficiency improvements
  • Lots more level maps
I think I'm going to drop the 'score' aspect, instead an achievement based level rating sounds good... Finish level for one star and ability to progress to next level, finish level having collected all treasure awards additional star, finish level in under X seconds awards additional star. Quite easy to progress through the levels, but replays required to get 100% perfect three star level rating.

Interestingly, Race Game has a fair number of android 1.6 users. Considering how few 1.6 devices exist, it's clear that there are people out there with low spec devices that want to play casual fun games. With this in mind, I'm going to keep striving for as near global compatibility as possible.

This game will be an arcade/maze/puzzler/adventure mashup. I'm going to leave out enemies, make it more about getting to the exit quickly, exploring, etc. This simplifies things for me, and should result in a game that appeals to quite a wide market.

A separate game that introduces first person shooter elements (zombies, weapons, and a darker art style) could be built on top of this base later on.

The code is freely available here, and there's a demo up on google play - check it out!


          

Sunday, 12 August 2012

Racing Game - Powering on ahead!

I've neglected the blog for a few days, spent my time working on the app rather than writing about it. As a result, quite a lot of progress has been made in the past few days :)

Here's a video of the app as it currently stands:



Wednesday, 8 August 2012

Racing Game - limiting scope, wishlist culling, and task prioritisation (or, The battle against hobbyist A.D.D.)

I have a horrible habit of starting a project, having great fun with it, then either losing interest, or heading off in a different direction to what was originally planned, unnecessarily complicating things, and giving up. End result is an unfinished project kicked to the kerb and a new one started. Repeat ad infinitum. It's like hobby ADD. I have so many started but unfinished projects it's not even funny. I know I'm not the only one!

This time it'll be different I said. This time I'll see it through til the end... But I so want to start a new project. I want to make a start on a platform game, Super Mario 3 on the NES is still one of the best games ever in my opinion, I want to make something similar. I want to create an arcade blaster, I loved Spy Hunter as a kid, I want to remake it for android, maybe 2D gameplay with 3D graphics. I want to create a basic 3D engine, maybe start with a first person perspective maze game, and extend to create a first person shooter, or a first/third person driving sim. I have lots of ideas, and I want to start on them all at once. So much ambition, so little attention span...

I'm pleased that I got further than usual this time - I've actually published an early alpha of Race Game on Google Play. I think it's in no small part due to me publishing this worklog and publicly sharing the code on github, there may not be that many visitors (yet?), but I still have a funny feeling of responsibility to get something finished. What's currently on Google Play is very much unfinished, so I'm definitely not off the hook yet (I won't be until I hit v1.0 at least), but it still feels like a mini victory over my hobby ADD :)

I've been reviewing the ideas/todo list and have decided to be pretty ruthless in terms of what stays and what goes. What's staying has been split into 'must haves' and 'would likes', and each list has then been prioritised.

I think it's fair to say that until all the 'musts' have been tackled the game is essentially broken, pretty good definition of must have really... Once all the 'musts' have been taken care of, I can package the app up as v1.0, update on Google Play, and go on to start a new project with a clear conscience.

The 'would like' items can be deferred to a later update. None are crucial to the functioning of the game. Only reason facebook bragging is at the top of the list is because it interests me personally, I think it would be a cool feature to re-use in future games (players post achievements to their wall, friends download the app to compete... a kind of viral promotional platform). Variable difficulty should be easy enough to implement, good bang for buck ratio (players could choose a quick course to kill 30 seconds, or a longer course when they're feeling a bit more hardcore etc, tailor game to the player for relatively small effort on my part), might as well get it done. The rest of the list are items that simply add a little polish to the game. I like to keep reminding myself that atari/spectrum games were ugly as sin but good fun, so I'm not too worried about this stuff really (just as well, I'm no artist!). Learning a little about animation and intro/outro scenes would help me when working on future projects, so I might have a little poke around in those areas, but we'll see.

The 'dropped' items won't be implemented in this project. I would like this project to remain simple and easy to read when finished. I know it'll help me if I ever need to quickly check back to see how I solved a particular problem in the past, maybe it'll help others too. The simpler and clearer the better, so I don't want to pollute it with too many extra features and it ending up a confused mess. There's nothing to stop me (or someone else) coming back and making Race Game Deluxe in the future, but it will be a seperate project, this particular project won't live forever, it will serve its purpose and then development will stop.

So, it looks like I have a plan. Great. As an added bonus, that 'must' list looks quite small and manageable, which is nice. I'm quite confident that I'll be able to get a modest v1.0 published on Google Play soon, and only then start tinkering with 3D mazes and tiled maps and other cool stuff... I guess the question of if/when v1.1 will see the light of day depends on how interesting the next project is, but I'm determined to get v1.0 out there pre-September (I got this far in 10 days of spare time so that should be a very achievable goal)!


          

Tuesday, 7 August 2012

Racing Game - Too early to go alpha?

I've still not taken care of my housekeeping tasks, but I do have a fully functional HUD now - this makes me feel a little guilty but a lot happy :)


Monday, 6 August 2012

Racing Game - HUD and Timer



As expected, I left the housekeeping for a while and carried on with the fun stuff :) There's a couple of things worth a little mention today:
  1. How to render a heads up display
  2. Introduction of a new timer class

Friday, 3 August 2012

Racing Game – Bobo’s end


In my last post I mentioned that having play tested a little I wasn’t really satisfied with how the game played. The levels were too blocky, character movement felt like it was in the wrong direction, and the story/theme was a bit forced and rubbish.
The simplest way to reduce the blockiness of the level would be to simply shink the tile sizes. Creating loads of block objects seemed a bad idea though (taking it to the extreme there could be one per pixel!). Instead I went back to the drawing board to rethink the level concept. Here’s a simple definition of a level:
  • A level row is 10px high and 240px wide
  • The viewable portion of the level is 320px high (32 x rows)
  • An example row could be: 80px wide grass, 80px wide road, 80px wide grass
  • The road sections are the same width in all the levels rows
  • The left grass section can increase/decrease in width by up to 4px per consecutive row
  • The right grass section takes up the remainder of the levelRow width
With these rules defined, I went on to rewrite the level generation code:
 public Level(int screenWidth, int roadWidth, int roadOffset, int levelLength, int rowHeight) {  
  this.screenWidth = screenWidth;  
  this.roadWidth = roadWidth;  
  this.roadOffset = roadOffset;  
  this.levelLength = levelLength;  
  this.rowHeight = rowHeight;  
  this.levelRowRoadOffset = new int[levelLength];  
  offroadAreas = new Array();  
  generateOffsets();  
  generateOffroadAreas();  
  generateFinishLine();  
  car = new Car(new Vector2((screenWidth/2)-(Car.WIDTH/2), 20));  
 }  
 private void generateOffsets() {  
  for (int row=0; row<levelLength; row++) { // for each row in the level  
  levelRowRoadOffset[row] = roadOffset;  
  // generate a random integer (between -4 and +4)  
  int modifier = (randomGenerator.nextInt(9)) - 4;  
  System.out.println("Modifier: "+modifier);  
  // apply modifier offset provided road would remain in bounds  
  if ((roadOffset + modifier >= 1) && (roadOffset + modifier + roadWidth <= screenWidth)) {  
   roadOffset += modifier;  
  }  
  }  
 }  
 private void generateOffroadAreas() {  
  for (int row=0; row<levelLength; row++) { // for each row in the level  
  OffroadArea leftGrass = new OffroadArea(0, row * rowHeight, levelRowRoadOffset[row], rowHeight);  
  offroadAreas.add(leftGrass);  
  OffroadArea rightGrass = new OffroadArea(levelRowRoadOffset[row] + roadWidth, row * rowHeight, screenWidth - (levelRowRoadOffset[row] + roadWidth), rowHeight);  
  offroadAreas.add(rightGrass);  
  }  
 }  
 private void generateFinishLine() {  
  finishLine = new FinishLine(0, levelLength * rowHeight, screenWidth, 40);  
 }  

Bobo became Car, Block became OffroadArea, and there were a few little changes to these classes, nothing really worth mentioning here. The drawing routine in GameScreen changed a little:
 for(OffroadArea offroadArea: level.getOffroadAreas()) {  
  spriteBatch.draw(grassTextureRegion, offroadArea.getBounds().x, offroadArea.getBounds().y, offroadArea.getBounds().width, offroadArea.getBounds().height);  
 }  

If you’d like to see the full extent of the changes made, the complete source can be found here.


What next?

Lots to do…
  • I can think of a couple of of efficiency improvements to do – there’s no sense in checking the whole level for collisions, and the same goes for rendering rows that are offscreen (espcecially those you have passed and won’t possibly see again).
  • I think maybe there should be subclasses of OffroadArea, ice, grass, rocks, finish line, etc, all with different behaviour, but for now I’ll leave things as they are, “it aint broke, why fix it”.
  • The level may need a little tweaking, certainly in later levels the game would need to get tougher. Deceleration when offroad needs tweaking too, it’s too sudden at the moment.
  • There’s a cheat possible where if you leave the screen bounds you race ahead, I’ll need to constrain car to world bounds.
  • The timer needs to be reintroduced, current time should be displayed oncreen, and high scores should be saved to persistent memory.
  • A delay before starting the race would be nice, maybe a traffic light graphic or “3, 2, 1, Go!” message.
  • The finish line could be improved, maybe a nice animation of the car driving offscreen?
  • Sound effects would be nice.
  • Maybe the car should rotate a little when ‘steering’?
  • Maybe some dirt particles should get kicked up when the car is offroad?
  • I’m already thinking about the third dimension. I need to forget about this for now if I ever want to produce a finished game. Maybe this game should be RaceGame2D, and RaceGame3D could be another project for another time!
There’s no doubt loads more to do that I’ve not thought of yet. I think I have plenty to be getting on with though! Don’t really know what I’ll tackle next, so the next update will be a lucky dip! Until then, here’s a bonus video of the basic game as it currently stands :)
          

Thursday, 2 August 2012

Run Bobo Run – Basic game mechanic complete



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!


          

Tuesday, 31 July 2012

Pulling the level generation code into Run Bobo Run



I didn’t expect to be posting again for a few days, but it turns out smooshing the procedural level generation algorithm into the LibGDX project was really straightforward, so I figured I might as well post a little something about it today :)
I added the Level class that I posted previously, and just made a few little changes to it:
  1. I changed char[][] to int[][], no real reason for this, either would be fine
  2. I pulled in Bobo and Array<Block> from GameScreen
  3. I replaced the console print method with a method to translate levelLayout to blocks placed in the level
  4. Finally, a constructor pulls all this together to allow easy creation of a level with a Bobo in it
I could have included block creation in the generateLayout method (under the “levelLayout[row][col] = ’0′;” line) and left out the translateLayout method completely, but separating out layout generation and translation to world co-ordinates seemed like a good idea.
Here’s the full source for Level.java
 package com.mrdt.runboborun;  
 import java.util.Random;  
 import com.badlogic.gdx.math.Vector2;  
 import com.badlogic.gdx.utils.Array;  
 public class Level {  
  private Bobo bobo;  
  private Array blocks;  
  private Random randomGenerator = new Random();  
  private int levelHeight, levelWidth, pathWidth, pathOffset;  
  private int[][] levelLayout;  
  public Level(int levelHeight, int levelWidth, int pathWidth, int pathOffset) {  
  blocks = new Array();  
  generateLayout(levelHeight, levelWidth, pathWidth, pathOffset);  
  translateLayout();  
  bobo = new Bobo(new Vector2((GameScreen.WIDTH/2)-(Bobo.WIDTH/2), 0));  
  }  
  private void generateLayout(int levelHeight, int levelWidth, int pathWidth, int pathOffset) {  
  this.levelHeight = levelHeight;  
  this.levelWidth = levelWidth;  
  this.pathWidth = pathWidth;  
  this.pathOffset = pathOffset;  
  this.levelLayout = new int[levelHeight][levelWidth];  
  for (int row=0; row<levelLayout.length; row++) {  
   for (int col=0; col<levelLayout[row].length; col++) {  
   if ((col < pathOffset) || (col >= pathOffset+pathWidth))  
    levelLayout[row][col] = '0';  
   }  
   int stepModifier = (randomGenerator.nextInt(3)) - 1;  
   if ((pathOffset + stepModifier >= 0) && (pathOffset + stepModifier + pathWidth <= levelWidth))  
   pathOffset = pathOffset + stepModifier;  
  }  
  }  
  private void translateLayout() {  
  for (int row=0; row<levelLayout.length; row++) {  
   for (int col=0; col<levelLayout[row].length; col++) {  
   if (levelLayout[row][col] == '0') {  
    Block block = new Block(new Vector2(col*Block.WIDTH, -row*Block.HEIGHT));  
    blocks.add(block);  
   }  
   }  
  }  
  }  
  public Bobo getBobo() {  
  return bobo;  
  }  
  public Array getBlocks() {  
  return blocks;  
  }  
 }  

As a result of introducing the Level class, the GameScreen class needed a little tidying up.

Project is up on github, feel free to check the project out, have a play with it, and comment if you have any ideas or suggestions :)


          

Monday, 30 July 2012

Getting Started with LibGDX


Exciting times… By the end of this post we’ll have something that loosely resembles the beginnings of a game! Not only that, we’ll be able to run it on the desktop or if we like on android (either a real phone or the emulator).
It really will be just the beginning though… Today’s focus is on creating a game world comprised of block objects, adding a player controlled object (Bobo) to the world, and locking the camera onto Bobo such that the level ‘scrolls’ and Bobo always remains within sight. Later we’ll deal with collision detection, game winning states, scoring, etc, but for now let’s just take it one step at a time!

Getting Started with LibGDX

I’ll assume you already have your environment set-up. If not, follow the instructions here, and come back when you’re done :)
Ok, now generate a new shell libgdx project using the gdx-setup-ui.jar. These are the values I used:


Next, fire up eclipse, file > import, general > existing projects into workspace, set root dir to wherever you specified when creating the shell project (in my case D:\Workspace), make sure all three projects are ticked, then click finish. If it all went well you should see the three projects in project explorer. Right click the desktop project, opt to run as java application, click on the Main item in the dialog, then ok. The default hello world app should open, it looks a bit like this:


Assets

I created a couple of sprites to get us started, bobo.png and block.png (both 16x32px per original spec). These should be placed in the assets/data dir of the android project. While you’re at it, delete libgdx.png, you won’t be needing it again.

Manifest

Open AndroidManifest.xml (it should be in the root of the android project). For now, all we need to do here is change the android:screenOrientation value from “landscape” to “portrait”.

Bootstrap

I renamed MainActivity.java (android project src) AndroidStarter.java, and Main.java (desktop project src) DesktopStarter.java. Just personal preference thing. Nothing needs changing in the android starter, but in the desktop starter we should set cfg.width to 240, and cfg.height should remain as 320, this just means the app we preview on the desktop will default to the target resolution of 240×320.

Getting down to business

With the initial setup out of the way, we can now get on with the business of making our game.
We’re only implementing the GameScreen right now, but we’re aware that there will be more screens added later on, so we should probably plan for that from the outset. There’s a nice little article here on the subject, makes a lot of sense to me so let’s do it!
Open RunBoboRun.java, delete all the contents, and replace with the following:

 // In anticipation of further screens being added, I followed this suggestion:  
 // http://code.google.com/p/libgdx-users/wiki/ScreenAndGameClasses  
 package com.mrdt.runboborun;  
 import com.badlogic.gdx.Game;  
 public class RunBoboRun extends Game {  
     GameScreen gameScreen;  
     @Override  
     public void create() {  
         gameScreen = new GameScreen(this);  
         setScreen(gameScreen);  
     }  
 }  


The libgdx-users wiki article does a great job of explaining so I won’t bother going into it any further here.

Game Objects

There are a couple of very obvious game object candidates – the world is made up of Blocks, and Bobo moves around the world, let’s create a class for each…

 // A simple class for Block objects  
 package com.mrdt.runboborun;  
 import com.badlogic.gdx.math.Vector2;  
 public class Block {  
     public static final int WIDTH = 16;  
     public static final int HEIGHT = 32;  
     private Vector2 position = new Vector2();  
     public Block(Vector2 position) {  
         this.position = position;  
     }  
     public Vector2 getPosition() {  
         return position;  
     }  
 }  

There’s not a whole lot to the Block class. A couple of constants define the size (measured in pixels), a Vector2 is used to record its position in the world (set during construction), and there’s a position getter/accessor method. That’s all there is too it.

 // A simple class for Bobo, all straightforward apart from maybe update method.  
 // From obviam.net:  
 // We simply add the distance travelled in delta seconds to Bob’s current position.  
 // We use velocity.tmp() because the tmp() creates a new object with the same value  
 // as velocity and we multiply that object’s value with the elapsed time delta.  
 package com.mrdt.runboborun;  
 import com.badlogic.gdx.math.Vector2;  
 public class Bobo {  
     public static final int WIDTH = 16;  
     public static final int HEIGHT = 32;  
     private Vector2 position = new Vector2();  
     private Vector2 velocity = new Vector2();  
     public Bobo(Vector2 position) {  
         this.position = position;  
     }  
     public void update(float delta) {  
         position.add(velocity.tmp().mul(delta));  
     }  
     public Vector2 getPosition() {  
         return position;  
     }  
     public void setVelocity(Vector2 velocity) {  
         this.velocity = velocity;  
     }  
 }  


There isn’t much more to the Bobo class. In fact, looking at the two classes I think maybe there should be a parent Tile object that Block and Bobo extend, but let’s forget about that for now, we can always come back to this later if we like. So what is different about the Bobo class? Put simply, it’s capable of movement. Bobo has a velocity (a Vector2), the value of which is set via a setter/mutator method. On each update Bobo’s position is altered in accordance with his velocity. I pinched the update method from obviam.net, he explains it as follows – “We simply add the distance travelled in delta seconds to Bob’s current position. We use velocity.tmp() because the tmp() creates a new object with the same value as velocity and we multiply that object’s value with the elapsed time delta.”
So far so good. Time to implement the GameScreen!

GameScreen

I’ve said this many times already, but I’ll say it again… I’m learning as I go, and I may not be doing things the “right” way. This class should probably be split into smaller pieces, maybe I should have distinct renderer and controller classes, etc. For now I’m just working on making things work, I can worry about doing things the “right” way later on. When you’re making a game who cares if you did it the “right” way anyway, it just needs to work! With that out of the way, let’s have a look at the code:

 // This basic GameScreen class demonstrates:  
 //  How to create a game level comprised of multiple block objects  
 //  How to create a dynamic bobo object that moves around the level in response to user input  
 //  How to create a 2D camera that follows bobo on the y-axis  
 package com.mrdt.runboborun;  
 import com.badlogic.gdx.Gdx;  
 import com.badlogic.gdx.Input;  
 import com.badlogic.gdx.Screen;  
 import com.badlogic.gdx.graphics.GL10;  
 import com.badlogic.gdx.graphics.Texture;  
 import com.badlogic.gdx.graphics.g2d.SpriteBatch;  
 import com.badlogic.gdx.graphics.OrthographicCamera;  
 import com.badlogic.gdx.math.Vector2;  
 import com.badlogic.gdx.utils.Array;  
 public class GameScreen implements Screen {  
     private static final int WIDTH = 240;  
     private static final int HEIGHT = 320;  
     private RunBoboRun game;  
   private Bobo bobo;  
   private Array<Block> blocks;  
   private OrthographicCamera cam;  
   private Texture boboTexture;  
   private Texture blockTexture;  
     private SpriteBatch spriteBatch;  
     public GameScreen(RunBoboRun game) {  
         this.game = game;  
         boboTexture = new Texture(Gdx.files.internal("data/bobo.png"));  
         blockTexture = new Texture(Gdx.files.internal("data/block.png"));  
         createLevel();  
         // orthographic camera (2D camera) of fixed width and height, larger screens will scale to fit  
         cam = new OrthographicCamera(WIDTH, HEIGHT);  
         // camera focus: x-axis middle of level, y-axis 100px below bobo, z-axis ignored  
         cam.position.set(WIDTH/2, bobo.getPosition().y - 100, 0);  
       spriteBatch = new SpriteBatch();  
   }  
     private void createLevel() {  
         // create bobo and add him to the level  
         bobo = new Bobo(new Vector2((WIDTH/2)-(Bobo.WIDTH/2), 0));  
         // create an array to hold all the block objects  
         blocks = new Array<Block>();  
         // nasty temp cludge to blat out a bunch of blocks... will be replaced by level generation algorithm soon!  
         addBlock(new Vector2(0, 32));  
         addBlock(new Vector2(16, 32));  
         // -- add lots more blocks here if you like...  
         addBlock(new Vector2(224, -448));  
     }  
     private void addBlock(Vector2 position){  
         Block block = new Block(position);  
         blocks.add(block);  
     }  
   @Override  
     public void render(float delta) {  
         handleInput();  
         // user input has an impact on bobo, so update his state  
           bobo.update(delta);  
           // following bobo update, move camera accordingly (focus rule same as in constructor)  
         cam.position.set(WIDTH/2, bobo.getPosition().y - 100, 0);  
         // clear screen  
           Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);  
           // call cam.update() after changes to cam (http://code.google.com/p/libgdx/wiki/OrthographicCamera)  
           cam.update();  
           // set projection and model-view matrix after update (http://code.google.com/p/libgdx/wiki/OrthographicCamera)  
           cam.apply(Gdx.gl10);  
           // setProjectionMatrix before drawing sprites (http://code.google.com/p/libgdx-users/wiki/Sprites)  
           spriteBatch.setProjectionMatrix(cam.combined);  
     spriteBatch.begin();  
       for(Block block: blocks) {  
           spriteBatch.draw(blockTexture, block.getPosition().x, block.getPosition().y, Block.WIDTH, Block.HEIGHT);  
       }  
         spriteBatch.draw(boboTexture, bobo.getPosition().x, bobo.getPosition().y, Bobo.WIDTH, Bobo.HEIGHT);  
         spriteBatch.end();       
     }  
     private void handleInput() {  
         // if a valid keypress, respond accordingly (set bobo's velocity such that he moves in that direction)  
     if(Gdx.input.isKeyPressed(Input.Keys.DOWN)) {  
         bobo.setVelocity(new Vector2(0, -100));  
     }  
     if(Gdx.input.isKeyPressed(Input.Keys.UP)) {  
             bobo.setVelocity(new Vector2(0, 100));  
     }  
     if(Gdx.input.isKeyPressed(Input.Keys.LEFT)) {  
         bobo.setVelocity(new Vector2(-100, 0));  
     }  
     if(Gdx.input.isKeyPressed(Input.Keys.RIGHT)) {  
             bobo.setVelocity(new Vector2(100, 0));  
     }  
         // if no valid keypress, respond accordingly (set bobo's velocity such that he does not move)  
     if   
     (!(Gdx.input.isKeyPressed(Input.Keys.UP))&&!(Gdx.input.isKeyPressed(Input.Keys.DOWN))&&!(Gdx.input.isKeyPressed(Input.Keys.LEFT))&&!(Gdx.input.isKeyPressed(Input.Keys.RIGHT)))  
     {  
         bobo.setVelocity(new Vector2(0, 0));  
     }  
   }  
   @Override  
   public void resize(int width, int height) {  
     }  
     @Override  
     public void show() {  
     }  
     @Override  
     public void hide() {  
     }  
     @Override  
     public void pause() {  
     }  
     @Override  
     public void resume() {  
     }  
     @Override  
     public void dispose() {  
     }  
 }  


I think the code and comments (don’t miss the links in the comments!) should make sense without too much further explanation.
On entry we:
  1. Create our assets (in this case our two textures)
  2. Create a level comprised of an array of Blocks and a Bobo
  3. Create a camera focused on Bobo
  4. Create a spritebatch to allow drawing of sprites to screen
The render method can be thought of as the main game loop, it’s called repeatedly while the GameScreen is active. Here’s what we need to do every time render is called:
  1. Handle user input – if a valid key is pressed (or not), set Bobo’s velocity accordingly
  2. Update Bobo
  3. Update camera position (lock on to Bobo)
  4. Draw the sprites to screen
That’s basically it :)
The controls are more than a little bit dodgy (no diagonal movement, and you’re stuffed if your phone has no cursor keys), the ‘level’ is hardcoded, the assets aren’t disposed cleanly on close, and there’s no doubt a lot more that needs tidying up, but this post is getting a bit long so I’m going to leave it there for now. When all is said and done, we have an application that will run on the desktop and on android, and the camera follows Bobo around the world, that’s exactly what I hoped to achieve today, so this seems like a good place to stop.
Here’s a screenshot of the ‘game’ as it stands:


Next post I’ll probably look into pulling in the level generation algorithm, and maybe do some collision detection, or maybe investigate accelerometer controls, I don’t really know yet!