Sunday, November 7, 2010

Leveraging Java and C++ for Hybrid Games

I've been thinking a lot lately about how best to use the resources that Android provides for game development.  A lot of the game developers I know (and I know a lot!) are quick to treat any new platform as a dumb host to their game engines.  Usually developers have a bunch of code, or even entire games, that are written to be aggressively cross-platform, so all they need is a way to compile the source, attach it to input events, and draw to screen.  Any platform that can provide those basics can host their tech, so when evaluating a new platform to support, these developers only look at the most basic level of functionality.

This is certainly true on Android as well.  Lots of developers look at the NDK and see a C++ environment that they can run their code in and decide that supporting the platform only requires gluing their existing code to the hooks that Android exposes.  And that's true--if your only goal is to port an existing game from one platform to another, only the minimal set of common functionality is necessary to get something up and running.

But since I am in a position to write games exclusively for Android, I've been thinking about how to leverage parts of the platform that most game developers ignore: the OS and Java runtime itself.  There's a lot of functionality there, and maybe there are ways that I could leverage it to make better games.

One project I've been working on recently is a little game framework using the NDK.  My friend Gregg and I ported Google's open source browser-based 3D framework, O3D, to Android a while back, and I've been using that to get some dudes running around on the screen.  O3D has a big Javascript component which we've ignored; the rest of it is a C++-based, shader-centric rendering backend.  Gregg did the heavy lifting of getting the thing to run on OpenGL ES 2.0 and I've been hacking in bits and pieces of old game engines on top.  The result is that we have a pretty complete rendering engine running on Android without a whole lot of effort.

It's a lot of code considering that it doesn't really do anything yet--almost 500k lines of C/C++.  But it wasn't hard to port because in the end, Android is really just another Linux OS with hooks into things like OpenGL ES 2.0.  So for this work, we basically did what lots of other game developers do: we ported the code using as little Android-specific stuff as possible and got something up pretty fast.

I've been slowly adding game code to this project, and as of this writing I have an early prototype of a shooting game up and running: you can run a little test character around and shoot placeholder art zombies with dual thumbsticks.  It's not a game, yet, but it's enough to prove out the code.

Not a game, yet.  Place holder art courtesy of 3drt.com.
If this thing ever gets off the ground, it'll be a game written almost entirely in C++, with just a few hooks back to Java for input, sound, and application life cycle events.  Just like most games that are built to be cross platform, or brought over from other platforms.

But I think there's an opportunity to use Android's unique hybrid application structure to do things that might be difficult or impossible on other platforms.  There are areas where I can get a lot of value out of Java while leaving the game engine and performance-critical code all in C++.

For example, I've hooked up a web server to this game.  It's a very, very simple web server; I found some code on the web that implemented a basic HTTP server in Java, copied and pasted it, and then hacked it up until it did what I needed.  It runs in a separate thread within the main game process, and allows us to connect to the device from a desktop browser while the game is running.  Here's a graphic to illustrate the structure of the code.

The high-level structure of this engine.  Red bits are Android Framework, blue are separate threads, and green is native code.

I'm sure you're reading this and are thinking, why the heck would you want to run a web server inside a game?!  Well, sir, I'll tell you.  With the web server in place, I've opened the door to real-time game editing.  This web server doesn't serve static pages, it reads and writes data directly to and from the native engine.  I can, for example, pipe O3D's scene graph up to the web server and let the user browse its structure from their browser.  I can do that with my game objects too (thanks to the meta system I referenced in the last post, which lets me query the structure of a given object by string).  And perhaps most useful, I implemented a simple interface for editing shader code on the fly; I can write vertex and fragment shaders right in the browser, click a button, and immediately see the rendering change in the running game.

This obviously isn't a full runtime editor, but with just a little bit of effort it's already proved to be pretty powerful.  The whole thing is exceedingly simple: my copy-pasted web browser calls down into the native code via JNI and just passes a string payload, which a few hundred lines of runtime code process and then return to the server and thus to the browser.  I'll extend this interface as necessary to other aspects of the game; building a way to do very fast iteration for things like game play physics and shaders is the way to turn a mediocre game into a good one.

Despite the simplicity of the web server system, I'm not sure it would have been as successful on other platforms.  C++ is great for rendering a 3D shader-based game, but it's actually a bit arduous to use for building a web server.  Java, on the other hand, is a great language to write a web server in--it's actually designed with that kind of application in mind.  Android hybrid apps let you leverage both native code and Java simultaneously, which can lead to some pretty neat combinations.  I think that, if this particular game engine ever becomes a full-fledged game, this kind of language diversity will make it a lot of fun to build.

Update: Oh, internet, you fickle beast.  Every potentially disputable line of text must be disputed!

OK, to be clear: of course it's not very difficult to write a web server in C or C++.  I did not mean to offend your sensitive language fanboyism by suggesting that maybe, perhaps, possibly, some languages are more predisposed to certain types of work than others.  Though I could write a GLES 2.0 game entirely in Java, I would not choose to do so: that language is not the best fit for that problem.  So yes, you may of course write a web server in C++, or in C, or in assembler or any other language.  And it's not that hard.  But in Java, it's so, so easy.  Heck, I even implemented a memory file cache just for the heck of it.  The code generates JSON on the fly based on results coming back from the engine runtime.  Sure, you could do this in C.  Be my guest.  Me, I'm looking for the simplest possible solution to each of my problems, so I can spend most of my time on the part that counts: making the game fun.

I also did not mean to suggest that I am the first to think of piping game data through a web server.  I just thought it was a neat and easy method for this project specifically on Android.  So there.

12 comments:

  1. Interesting potential article series. I shall keep an eye out on how this turns out. I've been contemplating the use of the NDK for a project for some time but haven't had time yet to devote to it.

    ReplyDelete
  2. A simple web server in C is like 50 lines of code if that. There are plenty of C based web servers and there are plenty of C/C++ game engines that provide a web server to inspect and/or edit the data. Sony has one in the PS3 SDK.

    ReplyDelete
  3. > Anonymous

    Thanks for your valuable contribution to this discussion!

    Seriously, the point was not to suggest that you can't do this in C. It's just trivial in Java. Maybe it'd be cool to, you know, use different languages for different problems depending on what a particular language is good at.

    Regardless, I've updated the post to reflect that clarification. I thought the PSSG code was cool and didn't intend to suggest that I have invented some crazy all-new method here. Don't get your feathers all ruffled over some language bias.

    Geez, some people.

    ReplyDelete
  4. Just wanted to say I appreciate all the work you've put into this game, blog, and making all this open for others to learn from! Great work!

    ReplyDelete
  5. (these are more general NDK questions, but what the heck)

    Just how portable is your engine across different devices? I know you're sitting on top of Linux, Oggles, etc, but does Android guarantee an endian-ness, word size, etc, etc?

    And how about distribution? Will you need to bundle N binaries with your APK? And how good is the android market at filtering devices that can't run your app/game/butt-scratcher based on binary compatibility?

    And if there's a link to all this instead of typing out some longwinded answer, feel free (even if its a lmgtfy ;)

    ReplyDelete
  6. As a more RepIsl-related question:

    How is this related to Replica Island? Or is it more related to RepIsl 2?

    ReplyDelete
  7. > Mark (#1)

    Android doesn't guarantee endianness--it's portable to any architecture. What the NDK does, however, is allow you to build fat binaries for each architecture that you support. Right now the three possible architectures are arm v5, arm v7, and x86. I don't need features from arm v7, and there are no x86 devices with Market available right now, so I'm compiling against arm v5 only. The code itself is entirely cross platform; all of it comes originally from Mac (PPC and x86) / Win / Linux code bases. If you choose to compile to multiple architectures, the NDK will automatically build for each abi you support and store a separate library within the libs folder of your project.

    So yes, the apk has N (right now, and for the foreseeable future, N = 1) libraries bundled with it. I suppose I could split that up into multiple binaries, but I don't see any benefit.

    Market will only distribute apps that can run on the target device's architecture. If I make something with the NDK that targets only x86, it won't show up on ARM devices. So no worries there.

    Here's the docs for the NDK:

    http://developer.android.com/sdk/ndk/index.html

    > Mark (#2)

    This isn't a game at all yet, so it's certainly not Replica Island. It could turn into a Replica game, I guess, but that's not in the cards at the moment.

    ReplyDelete
  8. Hey Chris, unfortunately this is a third Mark replying in this post, haha.

    Before I begin, I have to say thanks for the Replica Island code. A lot of my little 2D engine was built on top of the OpenGL layer inside RI.

    As for using the NDK, I think its a great thing, even if you're not going true cross platform. I'm currently doing some ES 2.0 programming, and given the state of affairs with the Android 2.0 bindings, I dont really have any alternative than to use the NDK.

    I'd discovered a great side benefit of this approach though. If I write the majority of my code in c/c++, and only rely on the Android java for things like EGL stuff, input, sound, resource loading, etc, I can run my app hardware accelerated on my desktop by only needing to duplicate that set of functionality. I have an AMD card, and anyone of them made in the last 2 years has the driver to run ES 2.0, and more cards will have the support soon once OpenGL 4.1 cards start showing up.

    This is great news, I think, for real time Android game devs, given that the android emulator is not only cumbersome, but quite slow.

    ReplyDelete
  9. if anyone has any link to a simple c++ web server and how to integrate that in an Android project (I guess through the NDK?) I'd be very gratefull :D

    ReplyDelete
  10. Hi

    You wrote: "Though I could write a GLES 2.0 game entirely in Java, I would not choose to do so: that language is not the best fit for that problem.". This is simply wrong as OpenGL ES 2.0 can be used through JOGL 2.0 and there are plenty of powerful web servers written in Java. I'm not a fanboy, I'm only a contributor of the JOGL project. I don't hide my personal preferences which are mostly a matter of taste behind wrong technical arguments. Best regards.

    ReplyDelete
  11. @gouessej though JOGL 2.0 exist that will serve the purpose as well, that does not mean it is the best fit for the problem in *his* situation.

    If he is mostly accustomed with using C for OpenGL ES, using it might be his best course of action. When you are writing a game that you need to deliver, technical concerns are not the only concerns. Things like fun, graphics, playability matters, in which you need time for those areas as well. Using something familiar saves time. Of course, you need to deliver the game before you depletes your bank account as well. :-)

    Just my 2 cents.

    ReplyDelete
  12. Interesting structure of you new engine for JNI->NDK engine.
    It's no open sourse ?

    ReplyDelete