Thursday, June 27, 2013

Helpful Java Libraries: Notes from my IndyJUG presentation

Introduction

Yesterday, I gave a presentation at the meeting of the Indianapolis Java Users' Group. The presentation, "Serious Game Development in Java," gave some background about how I transitioned from game hobbyist to serious game development researcher, and I talked about my two successful Java-based serious games: Morgan's Raid and Equations Squared.

A portion of the attendees at the IndyJUG meeting
Usually when I talk about these projects, I am describing the immersive learning environment, my experience working with multidisciplinary undergraduate teams, or design and evaluation processes. Given that this crowd was primarily professional Java programmers, I decided to take a different tack, and I talked about the software architecture and what I learned by building these games. In particular, I talked about some of the libraries we incorporated into the game. Several attendees asked me if I could share more information about the libraries and why I chose them, so I decided to write this follow-up.

Morgan's Raid

Morgan's Raid was written using Slick2D, which had been my go-to library for Java game development. However, the original developer and maintainer, Kevin Glass, has moved on from the project, and it seems to be struggling now. Kevin did a good job keeping the libraries in sync with the native libraries of lwjgl, and with him off the project, I would not recommend starting new projects in Slick2D. Kevin has moved on to libGDX, which looks like an interesting project, although I prefer PlayN, as described in the next section.

Here is a brief description of the other libraries we used in Morgan's Raid. For brevity, I'm not including their transitive dependencies, but note that managing transitive dependencies on this project is precisely why I was blown away by Maven, as described in the next section.
  • Apache Commons CLI: robust handling of command-line arguments, which we used to easily modify runtime behavior, e.g. fullscreen vs. windowed mode
  • Apache Commons Configuration: robust handling of application configuration, such as animation speed, default volume, etc.
  • EasyMock: mocking library for test-driven development
  • Guava: broad and robust library that simplifies Java development, making particular use of the Lists, Maps, and Objects classes.
  • Joda-Time: all the time calculations are handled with this fantastic library, and if you're doing any time-based logic, you should be using it too.
  • SnakeYAML: parser for YAML, which we used to describe the cinematic scenes in the game
  • CruiseControl: though not a library, we used this for continuous integration
I have several posts on this blog about the design and development of Morgan's Raid. If you're new, here are some of the most descriptive:
When I began work on this project, I knew I wanted to develop an HTML5+Javascript solution with the least possible amount of pain. I evaluated several possibilities and settled on PlayN. This amazing library allows cross-compilation of the same codebase to desktop Java, HTML5+Javascript (via GWT), Android, and iOS (and Flash, kind of, but its support has not been great).

PlayN relies upon Maven to manage dependencies and project configuration. It took me some time to make sense out of how it was working, but now it's hard to imagine going back to manual dependency management. In Morgan's Raid, for example, when I wanted to add a new library, I had to manually download the binaries, and all the binaries of its transitive dependencies, put them into my project's lib folder, configure the build path, configure native libraries if necessary, and then hope that all the different libraries would work together. To upgrade any library to a new release, which happened to some of our core libraries during development, I had to repeat this process by hand. By contrast, to add, say, Mockito to Equations Squared, I just added this to my pom file:

<dependency>
  <groupId>org.mockito</groupId>
  <artifactId>mockito-all</artifactId>
  <version>1.9.0</version>
  <scope>test</scope>
</dependency>

That last bit, the scope, is really fascinating: it says that the project should use Mockito only when running unit tests. Scopes aren't needed for most of the libraries I use, but this example shows how simple a process it is to specify them. Also, need to update to a new release? Just update that version tag and Maven takes care of the rest.

Speaking of Mockito, it has become my favorite mock object library for Java. The API design is elegant and allows for readable code with minimal boilerplate. Here's a sample unit test—the same one I showed in my IndyJUG presentation—that demonstrates Mockito. By way of explanation, this code builds a token list containing "-" and "1", parses it into the expression "-1", then creates a visitor object and hands it to the expression. The expected behavior is that the visitor visits two nodes in the parse tree: the unary negation and the value 1. Note that mock and verify are static calls to the Mockito library.

@Test
public void testVisitorHitsNegationAndInteger() {
  tokens = ImmutableList.of(
    SymbolToken.MINUS, 
    IntegerToken.create(1));
  Expression e = parseTokens();
  Expression.Visitor visitor = mock(Expression.Visitor.class);
  e.accept(visitor);
  verify(visitor).visit(UnaryOperation.NEGATE);
  verify(visitor).visit(1);
}

Equations Squared uses the pythagoras, React, and TriplePlay libraries from ThreeRings. Pythagoras is a collection of geometry utilities that is well described on its Web site. React brings functional reactive idioms and the slots/signals idiom to Java, and that merits a small example. My GameView class exposes a signal with a method like this:

public SignalView onGameOver() {...}

Any agent in the system that needs to know when the game end condition is met can connect a slot that is notified when the signal is emitted, for example:

game.onGameOver().connect(new UnitSlot() {
  @Override
  public void onEmit() {
    displayListOfBadgesAndDemerits();
  }
});

Signals can have type parameters as well, though here I am using the simplest form. React also provides convenient value objects that emit signals when values change:

Value<Integer> v = Value.create();
...
v.connect(new ValueView.Listener() {
    public void onChange(Integer newValue, Integer oldValue) {
        // Handle change here.
    }
});

As you can see, what I'm doing is using React to provide convenient, quick, efficient reification of the observer design pattern. No extra boilerplate required here, no fat interfaces and adapter classes: just hook up slots and signals and get going.

Where PlayN provides a low-level API for game development, TriplePlay provides many of the niceties one needs to get games up and running, such as handling screen transitions, layer animations, and UI widgets. One of the reasons I love TriplePlay (and PlayN) is that the designer takes care to support fluent programming idioms. This is a direction I have been taking much of my own development as well. Consider this example from Equations Squared that handles popup notifications:

tweenTranslation(popup.layer())
    .from(325, 320)
    .to(325, 300)
    .in(0.9f)
    .easeOut()
    .then()
    .tweenAlpha(popup.layer())
    .to(0)
    .in(0.3f)
    .easeOut()
    .then()
    .action(deleteLayerAction);

The code reads exactly as one would explain the animation sequence. When source code is as short and expressive as it needs to be to convey an idea, that's a good program. Working with some of the fluent styling API in TriplePlay takes a little getting used to, especially if one comes from a push-button background as in Swing. However, I really felt like my own ability to express myself fluently in Java increased after learning to use TriplePlay.

For more on Equations Squared, check out The Story of Equations Squared.

Acknowledgements

I want to thank Michael Dowden for inviting me to present, and to all the IndyJUG community for their warm welcome. The event was graciously hosted by E-gineering, and I could tell by their amazing facilities that they are a company who takes their work seriously and respects their employees. Check out this centrally-located kitchen!
The E-gineering Kitchen
I also want to recognize the valuable contributions of the Apache Foundation, Google, and ThreeRings for their support of open source software development, as well as the significant contributions of Kevin Glass to Slick2D and Michael Bayne to the whole PlayN ecosystem.

8 comments:

  1. I wanted to mention yesterday, but forgot about it when we started talking about board games, that our Linux team here at work uses Maven.

    ReplyDelete
    Replies
    1. Maven is extremely popular in industry and even more so in the open source community. Unfortunately I have had no end of trouble with Maven, even after three books and several attempted projects. It has always been easier for me to manage dependencies manually than make Maven happy. Perhaps I will try again on a project where I control all of the variables and do not have to convince Maven to work in a locked-down network with a screwed-up project configuration.

      Delete
    2. Fortunately, PlayN provides an archetype that does all the default project configuration for you. I have not had to make my own POM files. The most I have done is add dependencies, which works great. Sometimes one has to make changes to both the pom and the gwt.xml file for HTML5+JS, though, and that's easy to forget. At least, for me it is.

      Also, I've only been doing local development and have not tried setting up multiple maven repositories. As I mentioned in the presentation Q&A, I will be using PlayN in my game programming class for the first time this Fall. However, I think I'll just follow this same model and have each individual developer run their own maven repository, rather than fiddle with networked configurations.

      Delete
    3. I should mention: PlayN has a useful Getting Started page on the wiki, which includes the maven command for creating a new project from the archetype. More info at http://code.google.com/p/playn/wiki/GettingStarted

      Delete
  2. You've been contributing to the wrong forum :-P
    Better to concentrate our efforts, me thinks (rather than post in ooo libs, which is technically correct for tripleplay... but I don't think you can separate TP from playN at this point).

    https://groups.google.com/d/msg/playn/X2t4FNZ5dbc/5_B2u8HCdusJ

    ...and by the way, your Animator issue, I commented on recently in a different thread.

    https://groups.google.com/d/msg/playn/xkesFfuIYlw/frEYA9JcCXoJ

    PlayN could use with better documentation, and I suspect that's something you're passionate about, given this blog post (which I've added to the community wiki).

    DMG

    ReplyDelete
    Replies
    1. It sounds like you're suggesting that posting on my own blog is "wrong." I am not sure you read the whole post: it's a summary of notes from a presentation I gave.

      To be clear, I don't have any issues with the TriplePlay animator system. I think it's fantastic. You're welcome to your own opinion, of course, but I find most of PlayN and TriplePlay to exemplify the design practices I want to inculcate in my students.

      Delete
    2. I apologize for writing badly and being misunderstood. I wasn't suggesting at all that you stop writing blog posts. Please write more! :-)

      I was encouraging you to post more in the PlayN forum, instead of the OOO libraries forum (where I found you). I think the more cross-pollination that happens in the community the better, and I for one was completely unaware of the OOO libraries forum until yesterday (Found it on the React library's wiki page) I imagine that there are many more like me, and that's not the greatest situation. I mentioned that having different forums for different libraries might be technically correct, but as it regards to TriplePlay and PlayN, really anybody interested in public posts about tripleplay should be interested in PlayN and vice-versa.

      Please understand that there is no judgement on my part. I think people perform best when they do so voluntarily. If that wasn't communicated, I apologize again. If you disagree with anything I've written that's fine.

      I fully agree that Michael's and others' code is amazingly elegant. He is quite the engineer. I mean to take nothing away from him when talking about how the functionality or documentation could be better. Despite his amazingly crafted engineering, there still are common use-cases that the framework doesn't cater for, and having your and other's input on those issues would be a good thing!

      And that's all I meant to communicate.. that if you have any notes, it would be a pleasure for you to put them up on the wiki (or on your blog and I'd link to them). I thought that as a professor you'd appreciate the move for greater clarity/functionality/participation.

      Regards

      DMG :-)

      Delete
    3. Gotcha!

      I should be having 1-3 teams using PlayN this semester, and I plan to write about the experience (as time allows). It will be my first time leading a student team using PlayN+TriplePlay. If we end up with any generally useful tips or resources, I'll be sure to post them!

      Delete