Laying foundations

Let's now move on from theory to practice and get down to the actual implementation details. We will begin with implementing the first basic version of CanyonBunnyMain, WorldController, and WorldRenderer. Additionally, we will use a utility class to store constant values in a new class called Constants. It is true that this class does not appear in the class diagram, as it is just there for our convenience to avoid scattering or, even worse, duplicating certain constants all over the source code files. Also, as the stored values in Constants are meant to be used in virtually any other class, it would only clutter up the class diagram by drawing one additional line for each class to Constants.

Note

For simplicity, we will use the Constants class to store our constant values. Alternatively, game constants could be made data-driven via a settings file. This would avoid the need to recompile your code when a constant is changed.

Implementing the Constants class

Here is the listing of the code for Constants:

package com.packtpub.libgdx.canyonbunny.util;

public class Constants {
    // Visible game world is 5 meters wide
    public static final float VIEWPORT_WIDTH = 5.0f;

    // Visible game world is 5 meters tall
    public static final float VIEWPORT_HEIGHT = 5.0f;
}

First, we need to define the visible world size that can be seen at once when it is not moving around in the game world. In this case, we have chosen a visible world size of five meters in terms of its width and height.

Next, we will create the other three mentioned classes, but will only add the so-called method stubs (empty methods). This way, we can focus on the layout first and gradually implement the code and other new features later, when needed. Hopefully, this approach will give you the best insight into the whole development process from start to finish.

Implementing the CanyonBunnyMain class

The following listing shows the first implementation of CanyonBunnyMain:

package com.packtpub.libgdx.canyonbunny;

import com.badlogic.gdx.ApplicationListener;
import com.packtpub.libgdx.canyonbunny.game.WorldController;
import com.packtpub.libgdx.canyonbunny.game.WorldRenderer;

public class CanyonBunnyMain implements ApplicationListener {
    private static final String TAG = CanyonBunnyMain.class.getName();

    private WorldController worldController;
    private WorldRenderer worldRenderer;

  @Override public void create () { }
  @Override public void render () { }
  @Override public void resize (int width, int height) { }
  @Override public void pause () { }
  @Override public void resume () { }
  @Override public void dispose () { }
}

This class implements ApplicationListener to become one of LibGDX's starter classes.

A reference each to WorldController and WorldRenderer enables this class to update and control the game's flow and also to render the game's current state to the screen.

There is a TAG variable that holds a unique label derived from the class's name. It will be used for any logging purposes. LibGDX's built-in logging facility requires you to pass in a so-called tag name for every message to be logged. So, to stay consistent in our code, we will simply add a tag variable to each class.

Implementing the WorldController class

The following listing shows the first implementation of WorldController:

package com.packtpub.libgdx.canyonbunny.game;

public class WorldController {
  private static final String TAG = WorldController.class.getName();
  public WorldController () { }

  private void init () { }

  public void update (float deltaTime) { }
}

This class has an internal init() method that initializes it. Naturally, all the initialization code could also be put into the constructor. However, it appears to be very helpful in many ways when an initialization code is available in a separate method. Whenever we need to reset an object in the game, we do not always want or have to completely rebuild it, thereby saving a lot of performance. Also, this approach can greatly reduce the interruptions by the Garbage Collector (GC). Instead, we try to actively reuse existing objects, which is always a recommended design goal to maximize performance and minimize memory usage. This is especially true for smartphones such as Android with limited resources.

The update() method will contain the game logic and will be called several hundred times per second. It requires a delta time so that it can apply updates to the game world according to the fraction of time that has passed since the last rendered frame.

Note

The configurations of our starter classes use vertical synchronization (vsync) that is enabled by default. Using vsync will cap your frame rate and likewise the calls to update() at a maximum of 60 frames per second.

Implementing the WorldRenderer class

The following listing shows the first implementation of WorldRenderer:

package com.packtpub.libgdx.canyonbunny.game;

import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.utils.Disposable;
import com.packtpub.libgdx.canyonbunny.util.Constants;

public class WorldRenderer implements Disposable {
  private OrthographicCamera camera;
  private SpriteBatch batch;
  private WorldController worldController;

  public WorldRenderer (WorldController worldController) { }
  private void init () { }

  public void render () { }
  public void resize (int width, int height) { }

  @Override public void dispose () { }
}

This class also has an internal init() method for its initialization. Furthermore, it contains a render() method that will contain the logic to define in which order the game objects are drawn over others. Whenever the screen size is changed, including the event at the start of the program, resize() will spring into action and initiate the required steps to accommodate the new situation.

The rendering is accomplished using an orthographic camera that is suitable for two-dimensional projections. Fortunately, LibGDX comes with a ready-to-use OrthographicCamera class to simplify our 2D rendering tasks. The SpriteBatch class is the actual workhorse that draws all our objects with respect to the camera's current settings (for example, position, zoom, and so on) to the screen. As SpriteBatch implements LibGDX's Disposable interface, it is advisable to always call its dispose() method to free the allocated memory when it is no longer needed. We will do this in WorldRenderer by also implementing the Disposable interface. This allows us to easily cascade the disposal process when dispose() in CanyonBunnyMain is called by LibGDX. In this case, we will simply call the WorldRenderer class' dispose() method, which in turn will call the SpriteBatch class' dispose() method.

Notice that this class requires a reference to an instance of WorldController in its constructor so that it will be accessible later on to render all the game world objects that are managed by the controller.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset