Saturday, February 15, 2014

Libgdx - Generate Bitmap Fonts for Any Screen Size With Minimal Loading Time.

UPDATE: I got some requests, so I created a github repo to make it easy to include this functionality into your project.  This the best way to use this code.

https://github.com/jrenner/gdx-smart-font


This post will show you how to use the FreeTypeFontGenerator (a libgdx extension) and the BitmapFontWriter (included in gdx-tools) to dynamically generate your bitmap font to suit the screen size of the device the app is running on.  We will also optimize the process so that the fonts are only generated if there is no previously generated version found.

FreeTypeFontGenerator is not part of the core libgdx package (not in gdx.jar), to learn how to include it in your project, or use it in general, see this page on the wiki.

BitmapFontWriter is also not part of libgdx core.  It is located in the gdx-tools.jar.  Fortunately, it has little dependencies, which means you can just copy/paste the code of the BitmapFontWriter class directly into your project as a single file, and get it working with little alterations.

Once you get those two things setup, you are ready to go.  Below is the code you need to accomplish font generation/loading.

We get three main benefits from this code:
#1 No need to pre-render font bitmaps using Hiero or some other tool

#2 Fonts are perfectly (more-or-less) sized in proportion to whatever screen size the app is launched with.  Screen-size changes in between launch are also handled. (For mid-game resizing, you would have to do some more work)

#3 By saving the generated fonts to file, we can load from file in subsequent startups where the screen size has not changed (On Android, it should never change).  In my case, this cuts down the loading time for fonts dramatically, make the app start up much snappier.

In my case, where I generate 4 fonts, generating fonts took 3765ms, while loading the pre-generated fonts only took 325ms.  That's more than 3 seconds shaved off of app startup time!

In the images below, notice how despite the different window sizes, the fonts retain the same proportion.  The same effect will occur on Android screens.


1280x720

800x480



First, let's take a look at the code generating the fonts:


Now, let's see how we save the generated fonts to file.  These methods could be directly copied and pasted into your project without alteration.

Tuesday, September 10, 2013

A convenient desktop launcher class for libgdx

I use this in my libgdx project to make switching screen sizes and emulating the dimensions of various phones easy to do.  I thought I'd share it here:



Wednesday, July 3, 2013

dirhelp - understanding Linux's Filesystem Hierarchy Structure

A while back I created a command line utility to help with learning the linux filesystem hierarchy structure (FHS), it's called dirhelp.

Here is some example usage:

jrenner@main:/$ dirhelp
[/] Primary hierarchy root and root directory of the entire file system hierarchy.
jrenner@main:/$ dirhelp opt
[/opt] Optional application software packages.
jrenner@main:/$ cd /var/log
jrenner@main:/var/log$ dirhelp
[/var/log] Log files. Various logs.
jrenner@main:/var/log$ dirhelp /usr/share
[/usr/share] Architecture-independent (shared) data. This directory contains subdirectories with specific application data, that can be shared among different architectures of the same OS.  Often one finds stuff here  that  used  to live in /usr/doc or /usr/lib or /usr/man.
jrenner@main:/var/log$ dirhelp /usr/local
[/usr/local] Tertiary hierarchy for local data, specific to this host. Typically has further subdirectories, e.g., bin/, lib/, share/.
jrenner@main:/var/log$ cd /usr
jrenner@main:/usr$ dirhelp *
'/usr/games' - no information found
'/usr/lib32' - no information found
[/usr/bin] Non-essential command binaries (not needed in single user mode); for all users.
[/usr/include] Standard include files for the C compiler.
[/usr/lib] Libraries for the binaries in /usr/bin/ and /usr/sbin/.
[/usr/local] Tertiary hierarchy for local data, specific to this host. Typically has further subdirectories, e.g., bin/, lib/, share/.
[/usr/sbin] Non-essential system binaries, e.g., daemons for various network-services.
[/usr/share] Architecture-independent (shared) data. This directory contains subdirectories with specific application data, that can be shared among different architectures of the same OS.  Often one finds stuff here  that  used  to live in /usr/doc or /usr/lib or /usr/man.
[/usr/src] Source code, e.g., the kernel source code with its header files.
[/usr/X11R6] X Window System, Version 11, Release 6.


Monday, May 6, 2013

Getting Into Open Source as an Inexperienced Self-Taught Programmer

I often see questions from newer programmers like myself asking how they can start getting involved in open source projects. On Reddit's learnprogramming subreddit, it is #9 on the FAQ list.

I want to share my own experience.

After about a year and half of teaching myself programming, I had dabbled in a variety of languages and a few different programming environments.  I had a little experience in a large range of fields: Android development, Python desktop applications, network servers and clients in C and Go, and various toy game projects in a variety of frameworks.  While this provided me with a lot of useful learning opportunities, it never left me feeling skilled enough in any one area to meaningfully contribute to an open source project.

Some time in 2012, I heard about Glances, a curses based system monitor program written in Python.  I thought it was a nice program, downloaded it, and used it from time to time.


Eventually, in February of this year (2013), I came across Glances again when I was looking for open source projects to contribute to.

Python was the language I first started to learn programming with, and it is probably still the language I feel most comfortable in, so the project was a good fit for me.

The most difficult part of getting involved in a new project is understanding the project structure and the code base.  Fortunately for me, it wasn't necessary to understand the entire code base before I started making some changes.  By starting with a very small change, you can hopefully avoid affecting other parts of the code.  If you want to continue contributing to the project, it will eventually be essential to understand how everything works together, but changing some string formatting here and there, or adding a new data piece to an object might not be that big a deal.  You should still do your best to tread carefully.  The best case scenario is your pull request gets reject with some nice comments asking for changes.  The worst case scenario is you introduce bugs into the project that go undiscovered until it's too late.

I began to contribute to the project by adding small, easy to implement features.  Specifically, I added options for displaying network traffic data.  I think this is an excellent way for newer programmers to start contributing, but it is important to keep in mind that the maintainers of the project may not necessarily be interested in adding these features, depending on their vision for the project.  Communication is important if you don't want to risk wasting your time.  It doesn't hurt to first send an email laying out your plans, and asking for opinions, or even just asking for help.

Next, after doing more work on small features and various bug fixes, I implemented a feature that allowed Glances to run without collecting processes data, which was the vast majority of CPU overhead.  This allowed Glances to run on my Raspberry Pi, using only 2-4% of CPU, instead of 20% (!).  Of course, it meant sacrificing data for individual processes, but a system monitor app that takes 20% CPU is of questionable usefulness anyways.

This, is in turn, gave me an idea for how I could further contribute.  Glances can run in server mode, and using an XML/RPC api, it can deliver its data in json format.  I run my Raspberry Pi headless, so this seemed like it could be really useful when ssh is not an option.

As I mentioned above, I had some experience with Android, so I spent a month or so implementing the Glances API in Java, which is technically the first open source project of any usefulness that I have created.

The next step after that was to create the Android app. It uses the Java Glances API to collect the data and display it to user:


The final product can be downloaded here

Or you can view the Github repo

Interestingly, shortly after the creation of the repo, a contributor helped out by adding a French localization (Glances is popular in France, the home of its creator) and also the cpu and memory utilization bars seen in the above screenshot.

I  think the key to getting involved in your first open source project is to aim small, be polite, and don't be afraid to ask questions.  Things can really ramp up from there.

Making a Guided Missile in libGDX with Box2D

To see an example, take a look at this video:


Or this one with overhead strikes:

Finally here is a video that shows a large number of missiles chasing another missile:


To create a guided missile like this, you have to do a few things:

  1. Have a target, that is updated every frame with its current position
  2. (Optional) set some fixed waypoints on the way to the target to alter the flight path, this creates the overhead strike you see in the video, and is one way to improve accuracy
  3. Create a "steer point" that will guide your missile towards the next waypoint/target, but corrects for velocity of the chaser and the chased
  4. Turn the body of the missile until it is facing the steer point.
  5. When we are happy with the facing of the body, we accelerate it.
  6. If you want the missile to explode, you can check distance from target, or use Box2D's contact listener
Setting the targeting and updated it's Vector2 position should be easy enough, so I won't explain it here. Let's skip to step 3.

Assuming we have a target, let's face the target
let's correct for velocities: 


Now let's seek the waypoint:


And that's about it.  Here is the code for constraining the angle to 180 and -180 degrees:
Now you need to implement acceleration and contact/explosion handling on your own.

Saturday, May 4, 2013

Air Resistance in Box2D

I've seen many questions asking how to implement air resistance (drag) in box2d, and the most common solution is to use body.setLinearDamping.  After just a little bit of research, I discovered that calculating air resistance is not that difficult.  Here is an example in Java using box2d.
Note: this is not a full simulation of aerodynamics, it only affects linear velocity.
After reading the source, check out the algorithm in action in this video.