Sunday, December 5, 2010

Adding dependency injection to jMonkeyEngine with Google Guice

I'been playing for a while with jMonkeyEngine 3. I downloaded the SDK and tried the starter tutorial series. I recommend you reading these tutorials before reading this post.

The examples where created extending the SimpleApplication class, which provides many services as instance variables, such as instances of AssetManager, AppSettings, etc. All the examples were written in a single class. I wanted to split the functionality into smaller classes, so I needed to pass such references to other classes. A way to implement this in a generic way could be integrating Google Guice. I recommend you reading some basics about Guice too.

I built 3 annotations:
  • GuiNodeRef: for injecting a reference to guiNode instance.
  • AssetManagerRef: for injecting a reference to assetManager instance.
  • AppSettingsRef: for injecting a reference to appSettings instance.
A new base application class, GuiceApplication, will create and configure the injector:

public abstract class GuiceApplication extends SimpleApplication {

    private Injector injector;

    @Override
    public final void simpleInitApp() {
        /* building modules */
        Collection<module> modules = new LinkedList<module>();

        modules.add(new AbstractModule() {

            @Override
            protected void configure() {
                bind(AssetManager.class).annotatedWith(AssetManagerRef.class).toInstance(assetManager);
                bind(Node.class).annotatedWith(GuiNodeRef.class).toInstance(guiNode);
                bind(AppSettings.class).annotatedWith(AppSettingsRef.class).toInstance(settings);
            }
        });

        this.addApplicationModules(modules);

        this.injector = Guice.createInjector(modules);
        this.injector.injectMembers(this);

        this.guiceAppInit();
    }

    public abstract void guiceAppInit();

    protected void addApplicationModules(Collection<module> modules) {
    }
}

The simpleInitApp, which is inherited from SimpleApplication, creates the injector, configures it using a collection of modules, injects application members, and calls the abstract guiceAppInit method. A module that binds the three annotations mentioned before is provided by default, but you can add custom modules by overriding the addApplicationModules method. I took this idea from RoboGuice, which is  a framework that we are using at LeapFactor in order to integrate Guice into Android.

Now you can define injections in the application or in classes injected into the application. Injecting defined annotations would look like this:

@Inject
private @AssetManagerRef AssetManager assetManager;

@Inject
private @GuiNodeRef Node guiNode;

@Inject
private @AppSettingsRef AppSettings settings;
...


I tried it creating a simple Breakout-Arkanoid-like (without bricks :P) game. When I got my first computer in 1988, I started learning Sinclair Basic by writing a simple brick game. I called it Batty II, since I had a tape with (the excellent!) Batty game. This will be a remake, so I called Batty II too. You can download it here. I used the same guice-2.0-no_aop.jar that we used for Android at LeapFactor in order to avoid unnecessary dependencies.

Here you have some screenshots:


Mmmm, the physics engine makes the paddle rotate! This didn't happened with my CZ Spectrum+!


And finally, a friendly message indicating that the game is over:






2 comments:

  1. interesting! is there a reason why you prefer annotated bindings over "pure" (i.e. without annotatedWith())?

    ReplyDelete
  2. No special preference. Both approaches have advantages and disadvantages. The same example could be implemented, for example, with Spring using XML. I was just playing a little with jMonkey and Guice seemed pretty simple to me for making a proof-of-concept.

    ReplyDelete