Thursday, January 8, 2015

Making Games in Liblol: Part 1: The Important Files

The first step in learning to use liblol is understanding how the files are laid out, and what each file is expected to do.  In this tutorial, I'll cover the basics of what goes where, and how everything fits together.

Let's start by taking a quick look at the way Android Studio should look when you get started:


On the left hand side, we're in the "Project" view, and there are three entries in the list: android, core, and desktop.  (Note: if you can't see this, try either holding "Alt" and typing the number "1", or clicking on "1: Project" on the far left).

The "lol" in liblol stands for "Lehigh Overlay for LibGDX".  Lehigh is the university where I'm a professor.  An "overlay" is a layer of code that sits on top of another layer of code, to wrap, extend, or simplify its functionality.  And LibGDX is an amazing system for developing cross-platform games in Java.

In LibGDX, a game consists of multiple folders.  "Core" is where your main game code goes.  "Android" has a small wrapper that describes how to run your game as an Android application.  "Desktop" has a small wrapper that describes how to run your game on your computer.  It's also possible to create an "ios" folder, for iPhone/iPad/iPod development, and an "html" folder for developing games that can be played through a web browser.

Expand the "core" folder, and you'll see an entry called "java".  This is where all the code goes.  If you expand it, you'll see two more folders: "com.me.mylolgame" and "edu.lehigh.cse.lol".  The first of these is where you'll write code.  The second is where the code for liblol itself goes.  Open up "com.me.mylolgame", and you should see a screen like this:


There are six files: Chooser, Help, Levels, MyGame, Splash, and Store.  Of these, all but MyGame follow the same pattern: there is a method called "display", which is responsible for drawing an interactive screen representing part of the game.  The five files correspond to five key parts of any game: the opening screen (Splash), the help system (Help), the screens for picking which level to play (Chooser), a store for buying power-ups and upgrades using in-game currency (Store), and the actual playable levels of the game (Levels).  MyGame is where we configure the game.  Let's start there:

Basic Game Configuration

Let's take a look at the structure of MyGame.java:


/**
 * The starting point for a Lol game is right here. This code does two important
 * configuration tasks: it loads all the assets (images and sounds) used by the
 * game, and it tells the Lol engine about all of the other configuration that
 * needs to be done.
 * 
 * Be sure to look at the Levels.java file for how each level of the game is
 * drawn, as well as Splash.java, Chooser.java, Help.java, and Store.java.
 */
public class MyGame extends Lol {
    /**
     * Set up all the global configuration options for the game
     */
    @Override
    public void configure() {
        ...
    }

    /**
     * Load all the images and sounds used by our game
     */
    @Override
    public void loadResources() {
        ...
    }
}

This says that there are two functions: configure(), which sets our global configuration, and loadResources(), which gets all of the images and sounds ready for use in our game.

Let's look at configure() first:


    /**
     * Set up all the global configuration options for the game
     */
    @Override
    public void configure() {
        // to see documentation for any of these variables, hover your mouse
        // over the word on the left side of the equals sign
        mWidth = 960;
        mHeight = 640;
        mNumLevels = 92;
        mEnableVibration = true;
        mUnlockAllLevels = true;
        mShowDebugBoxes = true;
        mStorageKey = "com.me.mylolgame.prefs";
        mDefaultFontFace = "arial.ttf";
        mDefaultFontSize = 32;
        mDefaultFontRed = 0;
        mDefaultFontGreen = 0;
        mDefaultFontBlue = 0;
        mDefaultWinText = "Good Job";
        mDefaultLoseText = "Try Again";
        mGameTitle = "My Lol Game";
        mEnableChooser = true;

        // don't change these lines unless you know what you are doing
        mLevels = new Levels();
        mChooser = new Chooser();
        mHelp = new Help();
        mSplash = new Splash();
        mStore = new Store();
    }

This code does two things: first, it sets the default values that are used throughout liblol.  These include the size of the screen, the number of levels, whether to run in debug mode, how to configure the default font, and what some of the default text values should be.  As the comment in the code says, you can hover over each of the variables to get additional information.  Here's an example:


The text in the Documentation window is automatically generated from the comments in the code.  This is a good point to keep in mind: if you document your code, then the tools will help you understand it later on, when there's more code than you can remember!

The second part of the configure() method tells LibLOL about the five components of your game.  It's rare that you'll need to change these lines.

Configuring and Loading Images and Sounds

The next part of MyGame.java is a little bit trickier.  The code looks easy enough:


    /**
     * Load all the images and sounds used by our game
     */
    @Override
    public void loadResources() {
        // load regular (non-animated) images
        Media.registerImage("greenball.png");
        Media.registerImage("mustardball.png");
        Media.registerImage("red.png");
        Media.registerImage("leftarrow.png");
        Media.registerImage("rightarrow.png");
        Media.registerImage("backarrow.png");
        Media.registerImage("redball.png");
        Media.registerImage("blueball.png");
        Media.registerImage("purpleball.png");
        Media.registerImage("msg1.png");
        Media.registerImage("msg2.png");
        Media.registerImage("fade.png");
        Media.registerImage("greyball.png");
        Media.registerImage("leveltile.png");
        Media.registerImage("audio_on.png");
        Media.registerImage("audio_off.png");

        // load the image we show on the main screen
        Media.registerImage("splash.png");

        // load the image we show on the chooser screen
        Media.registerImage("chooser.png");

        // load background images
        Media.registerImage("mid.png");
        Media.registerImage("front.png");
        Media.registerImage("back.png");

        // load animated images (a.k.a. Sprite Sheets)
        Media.registerAnimatableImage("stars.png", 8, 1);
        Media.registerAnimatableImage("stars_flipped.png", 8, 1);
        Media.registerAnimatableImage("flystar.png", 2, 1);
        Media.registerAnimatableImage("starburst.png", 4, 1);
        Media.registerAnimatableImage("colorstar.png", 8, 1);

        // load sounds
        Media.registerSound("hipitch.ogg");
        Media.registerSound("lowpitch.ogg");
        Media.registerSound("losesound.ogg");
        Media.registerSound("slowdown.ogg");
        Media.registerSound("woowoowoo.ogg");
        Media.registerSound("fwapfwap.ogg");
        Media.registerSound("winsound.ogg");

        // load background music
        Media.registerMusic("tune.ogg", true);
    }

All that's happening is that we're loading image and sound files, and providing a bit of information about them.  But where do these files come from?  If you switch to the "Project" view and navigate to the android/assets folder, you'll see that all these files are saved there:


You can even drag and drop files into this folder of Android Studio to add media to your game.

There are four patterns in this code:

  • Media.registerImage() - register a plain .png image for use in the game
  • Media.registerSound() - register an .ogg file for use as a short sound effect in the game
  • Media.registerMusic() - register an .ogg file for use as a long-playing background music in the game; you must also indicate whether the music should loop or not
  • Media.registerAnimatableImage - register a .png image for use in the game, but indicate that the image should be treated as a grid, so that you can employ flipbook-style animation

Note: if you register a sound, you cannot use it as music in your code, and vice-versa.

About this "animatable" image idea: the best way to understand it is with an example.  Consider the following (horribly drawn) image:

We may want to have a character in the game that is shaped like a star, but with a color that is constantly changing.  If we register the above image as having 8 columns and 1 row, then LibLOL will only show 1/8 of the image at any time, and we can use our code to indicate how to cycle through the 8 images.

People often ask "can I use .mp3 files?" and "do I have to use .png images?".  It's possible to use .mp3 files, but you should be sure that there are no licensing restrictions on your use of the mp3 format in your game.  As for png files, they are almost always a better choice than jpegs.  The png file format supports transparency, and it uses lossless compression.  That means it won't blur the lines of a carefully drawn cartoon.  Using jpeg is fine for full-screen background images.  That's about it.  You should never use wav audio files or gif images.

Making Interactive Screens

This tutorial is a bit longer than I expected, so we're going to wait until next time to talk about how to make the individual interactive screens (Splash, Chooser, Levels, Help, Store).  However, you should feel free to explore these files now.  As you do, remember two things:

  • There should be ample comments, especially in the earlier parts of each file, to help you understand what is going on.
  • If you are trying to find a specific feature, you can look at the LibLOL JavaDocs.  Oh, and just to reinforce a point: all of those JavaDoc web pages were automatically generated from the comments in the code... if you comment your code well, the tools will work for you!

The levels of the code I provide are not really meant to be enjoyable.  Instead, they are meant to provide a demonstration of how the different features of LibLOL work.  I encourage students to read my code while running it / playing the game.  Then, I suggest they make small changes to the code and re-run it.  Doing this (reading while running) is the best way to gain an appreciation for how the code works, so that you can figure out how to use it to make a new game.

So by all means, go ahead and start reading the code and playing the levels of my sample game.  As you do, you should get a sense for how LibLOL makes it easy to achieve complex effects in your game.  And if you can't find a feature you need, leave a comment... the feature may be there and you just don't see it, or it may be in the LibGDX package, just waiting for me to provide an easy interface to it within LibLOL.

No comments:

Post a Comment