Mikołaj Koziarkiewicz

In this episode…​

…​we will start the actual development of the game by planting some boilerplate, taking a crash course in libgdx, and setting the stage for the actual streaming implementation.

Libgdx Basics

Project Structure

Libgdx, as mentioned previously, is a popular JVM framework for game design. Rudimentary Scala support exists - in fact, our game skeleton is based on ajhager’s g8 template, or rather, its fork by Darkyenus.

Because libgdx is a multi-platform engine, projects using it are always multi-module, split into:

  • a core module that contains the generic base of the game,

  • one or modules, each for a different target’s specific code, e.g. desktop, android, ios, etc.

In our case we will be only implementing a desktop version, so we will have two modules: core, and desktop.

Boilerplate classes

The core 's structures starts with the primary entrypoint class - a subclass of Game. Each platform variant creates an instance of this class during initialization.

In turn a Game operates on a number of Screen s, exactly one of each is always active. The Screen subclasses usually contain most of the game’s logic, the Game subclass should only provide minimal global controller "glue".

Both Game and Screen are coded in by implementing the provided lifecycle methods, create, pause, resume, dispose etc. [1].

With the general introduction out of the way, let’s see how a minimal game looks like. Here’s the core logic:

package net.mikolak.stream_bullethell

import com.badlogic.gdx.graphics.GL20
import com.badlogic.gdx.{Game, Gdx, ScreenAdapter}

class BulletHell extends Game {

  override def create(): Unit = { (1)
    setScreen(new MainScreen) (2)
  }

}

class MainScreen extends ScreenAdapter { (3)

  override def render(delta: Float) = {
    Gdx.gl.glClearColor(0, 0, 0.5f, 1) (4)
    Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT)
  }

}
1 Overriding a lifecycle method here.
2 Setting the active screen to our implementation.
3 Using an abstract Adapter class instead of the actual Screen interface for convenience.
4 Painting the background color to dark blue.

We then define a platform specific implementation, in this case, a "desktop"[2] JRE target:

package net.mikolak.stream_bullethell

import com.badlogic.gdx.backends.lwjgl.{LwjglApplication, LwjglApplicationConfiguration} (1)

object Main extends App {
    val cfg = new LwjglApplicationConfiguration
    cfg.title = "stream-bullethell-demo"
    cfg.height = 480
    cfg.width = 800
    cfg.forceExit = false
    new LwjglApplication(new BulletHell, cfg) (2)
}
1 "Desktop"-specific imports.
2 Pointing to our Game subclass.

This leaves us with an 800px by 480px screen with a dark blue background.

Erecting a base camp

The previous listing doesn’t leave us much room for experiment, so let’s spice things up a little by adding a proper Hello World message to MainScreen:

class MainScreen extends ScreenAdapter {

  private lazy val camera = new OrthographicCamera() (1)
  private val batch: SpriteBatch = new SpriteBatch() (2)

  private lazy val font = {
    val f = new BitmapFont()
    f.getData.setScale(2f)
    f
  } (3)

  override def show() = {
    camera.setToOrtho(false, 800, 480) (4)
  }

  override def render(delta: Float) = {
    Gdx.gl.glClearColor(0, 0, 0.5f, 1)
    Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT)
    camera.update()
    batch.setProjectionMatrix(camera.combined) (5)
    batch.begin() (6)
    font.draw(batch, "Hello libgdx!", 0, font.getCapHeight) (7)
    batch.end()
  }

}
1 The camera defines how the player "looks" at the object on the scene. In this case, we are using an Orthographic camera, which means we’re looking at the scene "straight down" (representing a 2D game - libgdx is also capable of 3D).
2 A SpriteBatch lets us draw multiple objects in one pass. Due to how actual games have a lot of objects on screen, using a SpriteBatch instance is the standard way of presenting anything on screen in libgdx.
3 Fonts, like many other resources, are explicitly declared for efficiency’s sake. This will give us a "default" font.
4 Once the screen becomes visible, the camera is set to show a top-down view of a rectangle of [0, 0, 800, 480] - since this is the same area as the "desktop" target’s window, each scene point corresponds to a single pixel.
5 The SpriteBatch is ordered to present the same viewport as the camera.
6 A batch must be always explicitly begun and ended. Objects are queued for drawing with it in between those two points.
7 Here’s where we actually draw the text. The X coordinate corresponds to the far-left side of the screen, and the Y coordinate corresponds to the bottom of the screen plus the capital-character height of glyphs of our font.

This nets us an actual Hello World, but we still have nothing to work on.

Tick tick tick tick

Screen s in libgdx are updated once per an interval called a tick. For each tick, the render method is called, and only once it’s complete can another tick occur[3]. This means all your game’s logic other than (de)initialization should be called from render, and - ideally - run in the same thread.

Due to machine-specific issues or issues with the game logic itself [4], the length of time each tick can take is not constant - this is why the delta parameter is provided, giving the millisecond amount between current an previous ticks.

As you have probably figured out by now, we’re going to need to tap into the tick mechanism to get started. So, let’s end this installment by printing up subsequent ticks. Here’s how our MainScreen will look now:

class MainScreen extends ScreenAdapter {

  lazy val camera = new OrthographicCamera()
  val batch: SpriteBatch = new SpriteBatch()

  var tick = 1L

  lazy val font = {
    val f = new BitmapFont()
    f.getData.setScale(2f)
    f
  }

  override def render(delta: Float) = {
    tick += 1 (1)

    //print tick
    Gdx.gl.glClearColor(0, 0, 0.5f, 1)
    Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT)
    camera.update()
    batch.setProjectionMatrix(camera.combined)
    batch.begin()
    font.draw(batch, s"Tick: $tick", 0, font.getCapHeight) (2)
    batch.end()
  }

  override def show() = {
    camera.setToOrtho(false, 800, 480)
  }
}
1 Setting the tick number…​
2 …​and printing it out.

You can grab the source code of the entire project in this state here. Libgdx itself has very comprehehsive documentation, so if you wish to find out more about it, its wiki is a good place to start.

Next up

Now we finally have a starting point for actual development of our concept. In the next installment, which will follow very shortly, we’ll get on to do that - specifically, by creating a simple stream that is able to tap into the tick mechanism of libgdx’s engine.


1. This factory-method-based approach to lifecycle management is quite widespread, and used most prominently in the JVM world by the Android ecosystem
2. In the "personal computer" sense: anything running on an i386/amd64 architecture or similar.
3. In other words, the render method is guaranteed to be called at most once simultaneously - similarly to how receive works for Akka actors. This is also how most JVM GUI engines operate.
4. As corollary to the above, sluggish game logic in the render implementation causes the subsequent call to be delayed.
Mikołaj Koziarkiewicz

What?

As I alluded to earlier, my free time (or at least the portion dedicated to coding) was recently taken up by a specific project. That project has been finally released: say hello to pomisos.

Pomisos is a desktop productivity app that helps users with elements of the Pomodoro Technique, specifically automating distraction removal (e.g. e-mail clients). There’s more info on the project page, what I’m going to concentrate on here are several thoughts that came up during the app’s development.

JavaFX is/was surprisingly ahead of its time

While the previous "official" Java desktop GUI framework, Swing, was based on the Publisher-Observer pattern, JavaFX is instead oriented around Properties.

Although superficially similar (they also allow listeners to be added), the crucial difference is the concept of "binding" properties to one another, essentially synchronizing them automatically. This allows for essentially writing GUI logic like a set of logic rules, e.g. (pseudocode) :

managePane.visible.bind(option.selected)

where visible and selected are both of type BooleanProperty. What’s more, you can bind multiple properties into complex statements, which essentially allows you to create dataflows that are updated automatically.

Essentially, the logic starts to look like a declarative stream specification, much more maintainable and convenient than the "Listener Hell" of Swing. It’s a shame JavaFX arrived only when classic desktop apps have already started to go out of fashion.

There’s comprehensive support for JavaFX in Scala

If you do want to start developing JavaFX applications, however, there’s several libraries that allow to comfortably code using Scala.

The first one, of course, is scalafx, which simply "Scalifies" the API, and adds a convenient DSL for property bindings. The previous example would now look like:

managePane.visible <== option.selected

Even more rule-like[1]!

Another thing is FXML development. FXML works pretty much like e.g. Android’s UI XML files - it allows you to separate general UI specification (the XML) from your business-logic code (a Controller class).

To take advantage of that convenience in Scala, there’s scalafxml. What’s especially nice is that integrates Scala DI approaches (like Macwire), to automatically instantiate the Controller classes[2].

Gremlin-based Graph DBs are too involved for simple projects

Over the last year or so, I’ve been evaluating Gremlin/TinkerPop, specifically the Scala implementation, in a variety of projects. Out of curiosity, I went with it as the DB layer for pomisos, using an embedded OrientDB instance as the storage implementation.

Unfortunately[3], while the API Gremlin API is almost amazingly intuitive (and the Scala implementation doubly so, big kudos to Michael Pollmeier for his work here), I found the "constant" cost of introducing this kind of abstraction seems to be an overkill for projects with only several, unconected, entity types.

Specifically, the biggest problem was creating generalized DAOs, and attempting to use edges as an Ersatz for trivial relations.

To be clear though: in this case, the aforementioned cost of introduction is comparable to an RDBMs. It’s just that, for projects of scale comparable to pomisos, simple object stores are more than sufficient.

Relaxed approach to development is the way to go when prototyping

From my observations, it appears there’s a persistent myth that experienced developers somehow create perfect code instantly - like some sort of rainbow-excreting unicorns. I find that exceedingly harmful, since it effectively reduces the amount of code that gets out to the public, due to lowered self-esteem of aspiring devs.

By the way, one of the best things in Clean Code is the part where Uncle Bob shows the continuous process of implementing a simple example, starting from a very messy prototype.

This is exactly why I haven’t squashed the ongoing commits. I think it’s a good idea for there to be more transparency in development of similar-scale projects, exactly because of the learning potential in demonstrating the actual coding process.

Coming up

That’s all regarding the development of pomisos. Check out the project if you’re interested.

Next time, we’ll go back to streaming and game development!


1. Although, to be honest, I’m not a fan of the other parts of the DSL, as I find "plain" map/flatMap combinators would be a much better fit here, instead of a tailor-made DSL.
2. There’s one problem - the DI for those classes is handled at runtime.
3. …​and as I expected…​