Today I set out to develop the invincibility item. The idea is that when picked up, the player will be invincible for 3 seconds and be able to break through trails, but the outer walls will still kill the player. My plan was to develop the invincibility code, build the item graphics and then put it all together in the game as an item that can be picked up. I first got side-tracked by how ugly the items were and decided to build uniform items for the game. I spent a few hours in photoshop making animated, 3d, orb-looking items. After that I got the trail-breaking code working, with a few bugs.
Today I added a new item which, when picked up, causes the racer's trail at that point to fade to nothing. The idea is that the game will be more dynamic if new opportunities can open up while playing. My tests of the item show that it's going to be a good addition to the game as I've already enjoyed playing the game more with it. The code itself was a little annoying because the entire game was designed with the concept of 1 trail (List of Coordinates to represent the path) per player and now I had to change it to multiple trail segments for each player. To complicate matter more, each trail segment could be "dissolving" independently. I solved all of these problems though and by 2:15am, the item was done.
After working with the AI a bit, I realized that the game feels totally dull to me. I spent a little time thinking about game design and decided to go with levels and items. Items weren't designed in to the game at all so I have to add the whole concept in from scratch. The first item going in is the Speed Boost item. When a player picks it up, their racer will move a notch faster until the end of the round. I have a problem though, the game is coded to run at the speed of the current level, not of the current player.
I was recently asked how to have objects that animate themselves (change frames) in a stable way that isn't dependent on the FPS or lag of the device. There are many ways to do this but I have a simple one which uses the difference between the last tick and the current tick to count down. My example is in Java and is suitable for most games. The first step is to use a main loop which gives the updates that info. The best way to do this is to give every thing that is updating the exact same time information and have them all use that.
Developing AI for an action/puzzle game can certainly be a challenge. What is the best approach? How do I want the computer to "feel?" How hard is too hard? What algorithms will be efficient enough to work well on a mobile device? These are all questions I had to ask myself when I was planning Light Racer 2.0. Light Racer 1.0 had just one AI implementation. 2.0 has 3: Easy, Medium and Hard. Easy will be the old Light Racer 1.0 AI. I made the decision to make Medium AI use a pathfinder algorithm and always target 1 tile in front of the opponent. A* seemed like an obvious choice for this task, but once I implemented it, I started to find that the AI is still lacking.
Most of what was done on days 5 and 6 was code to lay the foundation for the new medium and hard AI. Both AIs will make use of path-finding algorithms and because of that, using tiles to approximate coordinates will be far more CPU efficient, so long as creating the tiles themselves doesn't eat too many cycles. My strategy was to have each AI player manage its own tiles relative to itself. This makes it so that the point the player is at is at the center of a tile and that the tile size can be relative to the number of pixels a racer moves between AI updates.
Much like the first two days of work, days 3 and 4 involved mostly refactoring the existing code to bring it all in to the new architecture. The end of the fourth day was much more exciting than the rest because nearly 100% of the design was completed and I was able to work on new code again. I implemented 2D coordinate interpolation for the racer physics and AI, which I had a few problems with but overcame. I also implemented visual AI debugging which is key in developing better AI.
The first two days of actual coding have involved mostly refactoring. If you're curious as to why I'm doing all of this refactoring, I will recap on the new requirements which involve multiple kinds of AI, a new game object that I call the "decimator" and real-time multiplayer functionality. Many would think that the only way to do that would be to rewrite the game to support this, so why am I opting for refactoring to start? Some would argue that it's semantics but for the most part, refactoring is taking existing code without changing functionality and rewriting is completely scrapping a functional piece of code and developing it from scratch. Lots of the code in Light Racer was really good but just not organized to allow for new features to be added in without too much headache.
Version 1.0 of Light Racer didn't have much to say for architecture. There was a single Activity which dealt with the buttons, showed instructions and displayed the main game View. I'll cover the way the menus are going to work in a different article but suffice to say for now that having a single Activity deal with multiple different things is not a good idea at all in Android. The main View was a SurfaceView and simply started up the main game thread. The Thread class was the main game and besides the Sound Manager and a very light Player class which held the state, path and animation information for any given player, there wasn't a whole lot to it. This made it easy to develop but the new requirements are to have NPCs (Non Player Characters), network multi-player, different 2D and 3D displays and more. How does one tackle such a problem? With a better design, of course.
As of the start of this journal in April, 2009, my first Android game, Light Racer, had over 250,000 downloads and was on version 1.0.1. That game was developed in about 3 weeks time in my spare time and was released right when the G1 was made available. I had over a quarter of a million downloads of that first game, so why did I feel like spending months rewriting it and developing a 3D version of it? Well, I wasn't totally happy with the old version. It had really bad AI. I wrote that quickly just so I could have a computer to play against when testing but never implemented a better version. It was a little slow and choppy on some phones. It lacked depth and the way it was designed makes it hard to continue to add new parts to the game. It didn't have multiplayer support. It didn't look very nice. Basically, it wasn't a game that I could personally be proud of developing and I felt that there was so much potential for a great multiplayer 3D game, but I wanted to bring the 2D game up-to-date in the process, so I ended up doing both. Because of the months of development effort documented in this journal, Light Racer v2 and Light Racer 3D are both complete and are worlds better and more advanced than the first title. In the following pages, I give away many tricks and code samples of how to do almost you need to develop a good Android game.