libGDX // Takeaways from building my first game
Earlier this year, I caught wind of a few indie games that really grabbed my attention -- namely, Bit Blaster by Nickervision and another from a designer I follow, Dave Chenell called Powder - Alpine Simulator. These two games created an itch I just needed to scratch -- how do I build one of these games?
As an admirer of Android Experiments, I remembered the Papercraft game for Android Wear. I started off by studying their code and hacked a little Android game together to get my feet wet.
You can view the code here. I muscled through this process but found it pretty difficult, especially because I was handling the lifecycle of each entity and running everything through a TimerTask. All-in-all, it was a lot of work for such a simple game. So, I started doing some research to see how I could make this process less painful. I actually reached out to Adam Nickerson, the creator of Bit Blaster, and he said he started learning on Unity & C# (tweet). I decided to see if there was a Java solution out there, since my primary focus has been on Android Development for the past couple years. After reading a few blogs / forums, I came across libGDX -- an open source, cross platform, Java based game development platform. Perfect!
Long story short, I finished and published my very first mobile game here.
A few tips
I didn't feel like writing a "how-to" guide would be the best approach as there are tons of them out there already. But I thought I'd highlight a few of the hurdles / roadblocks I had to overcome, so hopefully it'll serve as a resource for someone else.
Image Assets
Get Sketch. I'd say this is totally worth the $99. It makes it so much easier to create and export your assets.
Once all my game assets were created and exported, I really wasn't sure where to go from there. After doing a bit of reading, I found that loading individual image assets is very expensive and will cause your game to lag. So, it is ideal to store all your smaller assets in one large assets, bind that large texture once, then draw portions of it as needed. But how do you do that?! This is where TexturePacker comes in -- a command line tool that creates the one large texture image (or TextureAtlas) for you. Its pretty great once you get it setup. The libgdx docs are decent here so I won't go into too much detail. However, I did see some confusion on StackOverflow as to how this looks when its setup. So, in your project's build.gradle file, you'll want to add the gdx-tools dependency as well as import TexturePacker.
Then you can create your task to actually create the TextureAtlas. First you'll want to define the directory for where to get the small images from, where you want the one large image to go, and the name of the TextureAtlas. As you can see below, my images are stored in Android > assets > images (libGDX recommends storing assets in the Android directory). The TextureAtlas is then exported to Android > assets > textures. And I simply named the exported file(s) textureAtlas.
I used the task provided by libgdx, which worked just fine. To execute it, you can run ./gradlew texturePacker (or whatever you named your task) in the terminal. Now, whenever you add / remove / update your images assets, you can run this task and it will replace your TextureAtlas with a new one. You can read more about using the TextureAtlas here.
Event Handling
More specifically, what to do in situations where you have more than one InputProcessor. For example, you have your main UI which handles most of the game play events as well as a head-up display (HUD) with a button -- both have separate InputProcessors. Here's where you can use InputMultiplexer. This allows you to chain InputProcessors together. So, the InputMultiplexer will hand off an event to the first InputProcessor -- if it returns false, it will hand off to the next InputProcessor in the chain.
I used this in my game since you swipe the screen to move the snake, which is the primary action. I also have a HUD that contains a pause button. The InputMultiplexer, makes it possible to engage with both inputs. Pretty simple and very handy.
UI Layouts
One of the biggest struggles I had was building screen layouts. From Android Development, I'm used to building layouts using XML and being able to preview my changes in the layout editor. I felt relatively blind and left without any tools in libGDX. Then I stumbled upon Scene2d.ui to ease my pain. The scene2d.ui package provides UI widgets and other classes to assist in structuring and building your layout. There are many widgets available (buttons, labels, checkboxes, etc), but I'd like to highlight the one I found particularly useful, Table. Tables are a powerful tool to easily position your widgets .. once you get used to using them. A few key things about Tables:
- Table-based layouts will adjust to different widget sizes and screen resolutions as they do not rely on Absolute Positioning
- Note: In most cases, you'll want to set your root table to table.setFillParent(true)
- table.setDebug(true)
- This is one of the most helpful snippets -- it will display all table, cell, and widget lines. Lifesaver.
- table.add(widget).colSpan()
- SO useful when you're laying out a table that does not have an equal number of widgets per row. This can help you avoid a world of hurt trying to guess padding values to evenly space out your widgets.
Resources
I also wanted to highlight a few resources I found useful while working with libGDX for the first time:
- Udacity - 2D Game Development with libGDX (free course)
- Udacity - How to Make a Platformer using libGDX (free course)
- Game From Scratch - libGDX Video Tutorial Series (free)
Conslusion
Being familiar with Android Development, libGDX has been a fairly easy transition to game development. However, I have only scratched the surface of game development as I only made a relatively simple 2D game. As libGDX is an open source project, there seemed to be a good amount of documentation. I may not have found where the real libGDX community discusses issues yet, but the forum posts I came across seemed to have been a few years old on average. All in all, I had a good time developing this game and look forward to creating another in the future.
If you have any tips of your own or feedback for me, please let me know. Also, feel free to try out my game and let me know what you think.
UPDATE (February 20, 2017)
My game was removed from the Google Play Store -- doesn't seem like they appreciate me using iOS emojis in my Android app 😝
Anyway, I added my work to GitHub here. I hope this will be useful to someone out there