Friday, December 24, 2010

Hot Failure

An article I originally wrote for Game Developer Magazine called Hot Failure has been reposted over at Gamasutra.com.  It's all about the metrics reporting system in Replica Island.  Check it out!

http://www.gamasutra.com/view/feature/6155/hot_failure_tuning_gameplay_with_.php

Sunday, November 21, 2010

Building a Reflective Object System in C++

Every game engine I've worked with for the last several years has had some sort of reflection system.  Reflection, and its cousin introspection, are features supported by some languages that allow runtime inspection of object structure and types. My most recent game, Replica Island, as a Java application makes use of Java's Class object, as well as useful type-related tests like instanceof.  Many other languages support some sort of reflection, especially those that are modern and VM-based (like C#).  Reflective objects can provide the answers to all sorts of interesting questions at runtime, like "is this anonymous pointer derived from class X?" or "does this object have a field named Y?"  It's also common to be able to allocate and construct objects by string in reflective systems.

These traits make it very easy to serialize and deserialize reflective objects: entire object trees can be written to disk and then read back again without the serialization code having to know anything about the objects it is writing.  Reflection also makes it very easy to write tools; if the tools and the runtime have access to the same type data, the tools can output data in the same format that the runtime will access it in memory (see my previous post about loading object hierarchies).  Reflection systems can also make for some pretty powerful tools: for example, it's easy to build a Property Editor dialog that can edit any object in the code base, and automatically adds support for new classes as they are written over the course of development.

But C++ doesn't support reflection.  There's RTTI, which gives a tiny little sample of the power that a real reflection system brings, but it's hardly worth the overhead on its own.  C++'s powerful template system is often used in places that reflection might be used in other languages (e.g. type independent operators), but that method is also restricted to a small subset of a fully reflective system.  If we want real reflection in C++, we'll need to build it ourselves.

Before we dive into the code, let me take a moment to describe the goals of my reflective object system.  Other reflection systems might choose a different approach based on different needs (compare, for example, Protocol Buffers to the method I'm about to describe).  For me, the goals are:
  1. Runtime type information of pointers.
  2. Ability to iterate over the fields in an object.
  3. Ability to query and set a field in an object.
  4. Ability to allocate and construct an object by string, or based on other meta data.
  5. No extra overhead for normal class use.
The Java Class object is a pretty good model to follow here: each class has a static object that describes the class in detail.  Using classes normally involves no extra overhead, but if we choose we can also load the Class descriptor and work with objects using reflection.  So my goal is to make something like the Java Class object in C++; my approach is to generate a class for each reflected class that holds metadata about the class it describes.  A "meta object."

Once I start generating meta objects for individual classes, servicing the first goal of anonymous pointer typing isn't very hard.  As long as we know that the pointer comes from some base type that implements a virtual accessor for returning the meta object, we can pull a static class definition out and compare it to other classes, or to a registry of meta objects (and, if we're tricky, we can even do this when we can't guarantee that the pointer is derived from some known base).  So let's assume we have a way to generate meta information for each class, wrap it up in a class called a MetaObject, and stuff it as a static field into the class it describes.

The next question is, what does this MetaObject class contain?  Well, per requirement #2, it must at least contain some information about fields.  In order to access fields within a class we'll need to know the offset of the field, its size (and, if it's an array, the size of each element), and probably the name of the field and the name of its type as strings.

Now might be a good time to think about what a C++ object actually looks like in memory.  Say we have the following object:
class Foo : public MetaBase
{
   public:
      static const MetaObject sMeta;  // The object describing Foo
      virtual const MetaObject* getMetaObject() { return &sMeta; }  // required by the abstract base
 
      void setup() { mBar = 10; mBaz = 267; }
   private:
      int mBar;
      int mBaz;
};

If we allocate an instance of Foo and then pop open our debugger to inspect the raw memory, it probably looks something like this (assuming MetaBase has no fields):

C0 A1 D0 F7     // Pointer to the virtual table; some random address
00 00 00 0A     // Value of mBar
00 00 01 0B     // Value of mBaz

I say "probably" because the actual format of a class in memory is basically undefined in C++; as long as it works the way the programmer expects it to, the compiler can do whatever it wants.  For example, the actual size of this object might very well be 16 bytes (rather than the twelve bytes shown above), with zero padding or junk in the last word; some architectures require such padding for alignment to byte boundaries in memory.  Or the vtable might be at the end of the object rather than the beginning (though, to be fair, all the compilers I've worked with have put it at the top).

Anyway, assuming this is what we see in the debugger, it's not hard to pull out the information we want for our meta object.  The value of mBar is at offset 4 (the first four bytes are the address of the virtual table), and the value of mBaz is at offset 8.  We know that sizeof(int) == 4.  And sMeta, because it is static, doesn't actually appear in the class instance at all--it's stored off somewhere else in the data segment.  If we had this information about every field in every class, we'd easily be able to access and modify fields in objects without knowing the type of the object, which satisfies most of the goals above.  And since this data is stored outside the object itself, there shouldn't be any overhead to standard class use.

Here's a abbreviated version of the object I use to describe individual fields in classes.  You can see the entire object here.

class MetaField : public Object
{
public:
  enum MetaType
  {
    TYPE_value,
    TYPE_pointer,
  };
  
  MetaField(const MetaType type, const char* pName, 
    const char* pTypeName, int offset, size_t fieldSize)
  : mType(type),
    mpName(pName),
    mpTypeName(pTypeName),
    mOffset(offset),
    mFieldSize(fieldSize),
  {};
  
  const char* getName() const;
  const char* getTypeName() const;
  const int getOffset() const;
  const size_t getFieldSize() const;
  const MetaType getStorageType() const;
  
  virtual void* get(const MetaBase* pObject) const;
  virtual void set(MetaBase* pObject, const void* pData) const;
  
private:
  const MetaType mType;
  const char* mpName;
  const char* mpTypeName;
  const int mOffset;
  const size_t mFieldSize; 
};


A static array of MetaFields is defined for each class and wrapped up in a container MetaObject, which also provides factory methods and some other utility functions.  You can see that object here.  These two objects, MetaField and MetaObject, make up the core of my C++ reflection implementation.

So we know what information that we need, and we have a class structure to describe it.  The hard part is finding a way to generate this information automatically in a compiler-independent way.  We could fill out MetaObjects by hand for every class, but that's error prone.  It might be possible to pull this information out of the debug symbols generated for a debug build, but symbol formats change across compilers and we don't want to compile a debug build for every release build.  We could probably contort C++ macro expansion to generate meta data, but in the interests of sanity let's not do that.  We could write a preprocessor that walks our header files and generates the necessary meta data, but that's actually a sort of annoying problem because of the idiosyncrasies of C++ syntax.

The solution I chose is to use a separate format, an interface definition language, to generate metadata-laden C++ header files using a preprocessor tool.  The idea is that you write your class headers in the IDL, which converts them to C++ and generates the necessary metadata objects in the output as it goes.  I leverage compiler intrinsics like sizeof() and offsetof() to let the compiler provide the appropriate field information (meaning I don't care where the vtable is stored, or what padding might be inserted).  My IDL looks like this:

metaclass PhysicsComponent
{
  base GameComponent

  function void update(const float timeDelta, GameObject* pParentObject) { public }
  function virtual bool runsInPhase(const GameObjectSystem::GameObjectUpdatePhase phase) { public }
  
  field mMass { type float, value 1.0f, private }
  field mStaticFrictionCoeffecient { type float, value 0.5f, private }
  field mDynamicFrictionCoeffecient { type float, value 0.1f, private }
  // mBounciness = coeffecient of restitution. 1.0 = super bouncy, 0.0 = no bounce.
  field mBounciness { type float, value 0.0f, private }
  field mInertia { type float, value 0.1f, private }
}

.. and the output of the preprocessor tool looks like this:

class PhysicsComponent : public GameComponent
{
 public:
  void update(const float timeDelta, GameObject* pParentObject);
  virtual bool runsInPhase(const GameObjectSystem::GameObjectUpdatePhase phase);
 private:
  float mMass;
  float mStaticFrictionCoeffecient;
  float mDynamicFrictionCoeffecient;
  // mBounciness = coeffecient of restitution. 1.0 = super bouncy, 0.0 = no bounce.
  float mBounciness;
  float mInertia;
 public:
  // AUTO-GENERATED CODE
  static void initialize(PhysicsComponent* pObject);
  static PhysicsComponent* factory(void* pAddress = 0);
  static void* factoryRaw(void* pAddress, bool initializeObject);
  static PhysicsComponent* arrayFactory(int elementCount);
  static const MetaObject* getClassMetaObject();
  virtual const MetaObject* getMetaObject() const;
  static bool registerMetaData();
  static PhysicsComponent* dynamicCast(MetaBase* pObject);
};

You can see that the IDL pretty much just spits C++ out exactly as it was written, but in the process it also records enough information to generate the functions at the bottom of the class.  The most interesting of those is getClassMetaObject(), which is a static method that defines the meta data itself:

inline const MetaObject* PhysicsComponent::getClassMetaObject()
{
  static MetaField field_mMass(MetaField::TYPE_value, "mMass", "float",
    offsetof(PhysicsComponent, mMass), sizeof(float));
  
  static MetaField field_mStaticFrictionCoeffecient(MetaField::TYPE_value, 
    "mStaticFrictionCoeffecient", "float", 
    offsetof(PhysicsComponent, mStaticFrictionCoeffecient), sizeof(float));
  
  static MetaField field_mDynamicFrictionCoeffecient(MetaField::TYPE_value, 
    "mDynamicFrictionCoeffecient", "float", 
    offsetof(PhysicsComponent, mDynamicFrictionCoeffecient), sizeof(float));
  
  static MetaField field_mBounciness(MetaField::TYPE_value, "mBounciness", "float",
    offsetof(PhysicsComponent, mBounciness), sizeof(float));
  
  static MetaField field_mInertia(MetaField::TYPE_value, "mInertia", "float",
    offsetof(PhysicsComponent, mInertia), sizeof(float));
  
  static const MetaField* fields[] =
  {
    &field_mMass,
    &field_mStaticFrictionCoeffecient,
    &field_mDynamicFrictionCoeffecient,
    &field_mBounciness,
    &field_mInertia,
  };
  
  static MetaObject meta(
    "PhysicsComponent", 
    MetaObject::generateTypeIDFromString("PhysicsComponent"),
    MetaObject::generateTypeIDFromString("GameComponent"), 
    sizeof(PhysicsComponent),
    static_cast(sizeof(fields) / sizeof(MetaField*)), 
    fields, 
    GameComponent::getClassMetaObject(), 
    &PhysicsComponent::factoryRaw);
  
  return &meta;
}

*note that, in more recent versions, I've replaced offsetof() with a macro that does the right thing for compilers that do not support that intrinsic.  Offsetof() isn't really kosher in C++, but for my purposes it works fine.  If you want to learn all about it, and why it's rough for "non-POD types," try Stack Overflow.

With this data, I now have a pretty complete reflection system in C++.  I can iterate over fields in a class, look them up by string, get and set their values given an anonymous pointer.  I can compare object types without knowing the type itself (I can implement my own dynamic_cast by walking up the MetaObject parent hierarchy and comparing MetaObject pointers until I find a match or reach the root).  It's very easy to construct objects from a file, or serialize a whole object tree.  I can, for example, make a memory manager that can output an entire dump of the heap, annotated with type and field information for every block.  And I can compile all of my objects into a DLL and load them into a tool and have full type information outside of the game engine environment.  Sweet!

There are, however, many caveats.  This implementation doesn't even attempt to support templates, multiple inheritance, or enums.  If we serialize and deserialize using only this data, some standard programming practices start to get screwed: what happens when we can construct objects without invoking the constructor?  How do we deal with invasive smart pointers or other data that weakly links to objects outside of the immediate pointer tree?  How do we mix objects that have this meta data and objects that do not?  How do we deal with complex types like std::vector?  If object structure is compiler dependent, how can we serialize class contents in a way that is safe across architectures?  These are all solvable problems, but the solutions are all pretty complicated.  They often involve dusty corners of the C++ language that I rarely visit, like placement new.  If you get into this stuff, Stanley Lippman is your new best friend.

But even with those caveats in mind, the power of reflection is absolutely worth the price of admission.  It's the first chunk of code I write or port whenever I start a new project in C++.  It was the first bits of my old game engine that I got running on Android, and is now the core of the engine I am building on that platform.  Reflection is not a simple bit of infrastructure to get up and running, but once you have it it's really hard to go back.

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.

Wednesday, November 3, 2010

Game Object Construction Rabbit Hole

Today I want to write a little bit about a boring, yet utterly fundamental part of game engine design: spawning game objects.

Garry's Mod makes it look easy.
Say you have a level that contains a player object and an enemy object.  However these objects are represented in memory, you have to allocate them somehow.  And probably register them with some sort of update loop, and maybe load some other data (graphics, sound?) associated with those objects.  There's a little bit of bootstrap to just get the game into a state where the simulation can start.

So, how do you do it?  How do you get that player and enemy up and running?  This is one of those problems that can be as complex as you choose to make it.

Well, I mean, you could write a function that looks like this:

void startUpGame()
{
   spawnPlayer();
   spawnEnemy();
   // done!
}

Sounds good until you get to level 2, which has two enemies.  You could make a spawning function for every single level, I guess.  It would work, but it wouldn't scale, especially if you have lots of objects to spawn.  I think the average Replica Island level has several hundred objects to spawn, so writing one of these for each level would suck hard.

Long, long ago I wrote a game called Fysko's Playhouse for Mac OS 6 computers.  If that fact alone doesn't date me, this will: it starred the mascot of a local BBS of the same name.  Anyway, back then I had no idea what I was doing, and so when faced with this problem of how to spawn game objects for different levels in a way that doesn't suck, I hit the code with a hammer and moved on.  My solution back then was to write a level editor (in HyperCard!!) that would output start up functions like the one above.  I could draw a level in the editor, hit a button, and out would pop a bunch of Pascal code which I could then copy and paste into the game.  Great!

Well, not really.  That kind of solution works only for very simple games and only when the programmer is the level designer.  And even then it's kind of crappy.  Move a guy 2 pixels to the left and you have to recompile your code.

Some years later I wrote a Bomberman clone called Bakudanjin.  This time I was a little smarter.  Instead of hard coding my level information, I made a map file describing every level.  The map file was basically just a bunch of indexes with XY locations.  To start the level, I load the file and then walk through each index.  The index maps to a table of function pointers (or, since this was also Pascal, a big-ass switch statement) that call the appropriate spawn functions.  Actually, Replica Island works this way too.

And if you just clicked on that link, you can see why this method isn't so hot either: Replica Island only has about 50 different object types and that code is still 6500 lines long.  And a lot of it is copy and paste, because many objects turn out to be structurally similar.  And god forbid you accidentally get your map format indexes out of sync with your runtime indexes; arbitrary enums needing to correctly index into separate arrays is a recipe for bugs.

Still, this is a quick and easy method, and it worked fine for Bakudanjin and Replica Island.  All that code gets thrown out and rewritten when I start a new game, though.

The problem here is that all this bootstrap code is basically code describing data.  I draw a line between "code" and "data" as follows: code is literally programming that instructs the game how to operate.  Data is non-code that is input to the code system.  You feed data into your game and out comes a playable simulation.  Things like enemy placement on a map are subject to lots of iteration and change; the code to actually move an enemy to that location is probably pretty stable and static.  Therefore, the placement information is data and shouldn't live in code, while the runtime for consuming that data is code but can be generic and reused across multiple levels and games.

So in order to write better code and to enable faster iteration and reusability, it's probably a good idea to move more of the information for spawning guys into data.  Moving spawn locations into a file wasn't a bad first step, but we can go further.

What does spawnPlayer() do, anyway?  It probably allocates a bunch of objects, ties them together with pointers, and sets a bunch of parameters on those objects.  Hmm, sounds like something we could represent with just some smarter data.

How about this: we'll make all objects in the world basically the same, make a single spawnObject() function, and then expose a bunch of parameters which we can use to customize the objects and differentiate them.  If we can do that, all we need to do is serialize all the parameters and pass them to spawnObject().  Health = 5, Speed = 10, Sprite = "AngryGorilla.png", etc.

GameObject* spawnObject(ObjectParams* params)
{
   GameObject* object = new GameObject;
   object->setLife(params->life);
   object->setSprite(params->sprite);
   if (params->isThePlayer)
   {
      object->setRespondToControllerInput(true);
   }
   // ...
   return object;
}

OK, that works, but now we have a new problem: it's actually pretty hard to make all our objects exactly the same.  Take the code that reacts to controller input, for example.  That belongs on a player object but on nothing else; with this type of system every single angry gorilla is going to carry that code around, probably turned off with a flag that we serialized.  Or consider what happens when an object is hit.  The player probably wants to get damaged, go into a short invincibility mode, and then go back to normal.  The enemies probably want to get damaged and not be invincible.  If the player dies there's probably some code to cause the Game Over screen to pop up.  Not so for an enemy.

We could make this all the same code and control it with flags, but it's going to become ugly fast.  Maybe if we can refactor our game such that all objects are functionally similar we can ease the pain, but that will make it hard to say, add in little bits of player-specific hacks to improve the feel of game play later.  A better system would be able to generate objects that only contain the code that they need.  If we use the aggregate object model that I often recommend, we could think of this as only inserting relevant components.  In a more traditional object model, we could think about instantiating the object at a particular level of derivation from the base to provide only the necessary set of functionality.  Either way, we're talking about sticking code together with pointers and setting parameters.  Hmm, sounds like data again.

One method I've seen but never tried myself is to define a hard-coded list of object types ("player", "angry gorilla", "banana bomb", etc), and then provide a unique struct of static spawn data related to each type.  For example, the player object would be allocated to contain code for movement based on the controller, and it would read at spawn time a PlayerObjectData struct.

GameObject* spawnObject(ObjectType type, void* params)
{
  GameObject* object = NULL;
  switch (type)
  {
    case TYPE_PLAYER:
        object = new PlayerObject();
        object->parseParams(static_cast<PlayerObjectData*>(params));
        break;
    // ...
  }
  return object;
}

The attractive thing about this method is that you get a chance to control object creation on a per-type basis, but you can also serialize different data for each type, thus avoiding the one-size-fits-all problem.  That should let you move almost all information about this object into data, and just leave this one spawn function in code.

But let's go a step further.  Say we don't want to have to enumerate every object type in code.  If objects are really just collections of data and code, why can't we move the entire structure of a game object into data?

In a language that supports reflection, this shouldn't be too hard.  We can encode an entire object hierarchy, say as XML, and then use it to allocate classes, patch pointers, and set fields.  In a language like Java, we can look up class names by string and instantiate them, and poke into fields to finish constructing objects.  We can imagine some XML that looks like this:

<object name="gorilla" type="com.gorillaboom.gameobject">
  <field name = "mLife">10</field>
  <field name = "mSprite">gorillagraphic</field>
</object>

<object name="gorillagraphic" type="com.gorillaboom.imagefile">AngryGorilla.png</object>

If we write an XML parser to build object trees for us based on this, our entire spawn code can become a single call to that parser.  The parsing code is complicated but generic, it can be reused across objects and levels and games.  And we still have the ability to customize each object because the hierarchy can contain custom classes or be structured differently per type.

GameObject player = (GameObject)constructFromXML("player.xml");

Even cooler, this method isn't even specific to game objects.  We could use it to serialize all sorts of data, even the contents of our main loop.  The code is still code, but once we put the structure in data we have a crazy amount of control.

But, getting back to just the game object application of this idea, there are two problems.  First, this approach requires us to walk the XML object tree every time we want to spawn an object.  We could try to walk the XML once and then use the resulting object tree as an entity "archetype," but that way leads to a particular brand of hell known as "shallow copy vs deep copy." When trying to copy the tree to create a new game object instance, how do you know which pointers should be recursively copied and which should be copied by value?  People have lost years of their life to that problem.

A less practical but ultimately simpler solution is just to re-parse the XML for every instantiation.  Which brings us to the second problem: reading XML and stuff is slow.  I mean, really slow.  Compared to the simple code functions we started with, it's glacial.  And allocation-heavy.  Not something we really want to do during the runtime of a game.

I know what you're going to say.  Hey, dumbass, just use a binary format instead of XML.  Problem solved.  And that's true, to an extent.  Excuse me for a moment while I go out on a limb to the extreme of this line of thought.

If you're going to go to a binary format, why not just store the entire object tree in its native memory format on disk?  Build the object hierarchy offline, write it as binary data to a file, then load it at runtime and just patch pointers.  Boom, instant object tree.  In C++ you can actually do this by building your own reflection system, making liberal use of placement new, and then walking the objects stored in the file to patch pointers.

I've actually written this system before.  It becomes horrifically complicated, but it does work.  A couple of years ago I wrote an engine that could load a binary blob of C++ objects as a contiguous block, walk the objects therein to patch vtables and other pointers, and then simply start using the objects as regular fully constructed C++ objects.  You lose constructers (objects were constructed before they were written to disk) and destructors (lifetime of the object is the lifetime of the blob; individual objects within the blob can't be freed), and god help you if you try to manage those objects with reference counts or smart pointers, but the method does work and it's pretty fast.  To make a new instance of the object tree, you can just memcpy the whole block and repatch pointers.  Cool.

It starts to break down when you need to target multiple platforms, or build your data files on an architecture that does not match the runtime architecture.  These problems are also solvable, but probably not in-place; you'll need to read the objects out of the file and then allocate them at runtime to ensure padding and vtable placement is correct.  And if you do that you're back to a lot of runtime allocation and object parsing.  The system is still complicated but some value is lost.

So for a new code base that I'm working on, I'm experimenting with a slightly different approach.  I still want to use the "load code structure from data" approach, but I don't want it to be slow or architecture dependent (or complicated, if I can avoid it).  And I need to be able to spawn objects with this system dynamically at runtime.  So instead of constructing objects directly, I'm constructing factory objects that can generate new instances of my object hierarchy on the fly.

The method is to read in an object hierarchy as XML.  Instead of building the tree right there, I build a bunch of "instruction" objects--basically the minimal list of commands required to recreate the object tree described in XML.  "Create an object of type GameObject," "Set field mLife of object index 5 to 10," "Point field mSprite of object index 22 to object index 25."  Each of these small "patch" objects gets initialized with a single command (representing a delta from the default state of the object upon construction), and the whole list of patches is stored in a factory object I call a "builder."  Reading the XML is still slow, but I only need to do it once before the game starts; at runtime, when I want to spawn a new object tree, I simply execute the appropriate builder.  The runtime speed is similar to what we had way back at the top of this lengthy post: just a bunch of object allocations and field initializations.  Should be pretty fast.

Builder* enemyBuilder = makeBuilderFromXML("angrygorilla.xml");

GameObject* enemy1 = enemyBuilder->build();
GameObject* enemy2 = enemyBuilder->build();
GameObject* enemy3 = enemyBuilder->build();

One nifty aspect of this approach is that I can easily extend the XML format to do more complicated things by building more complex patch object types.  The basic set of patches (int, float, vector, pointer, string, etc) are entirely generic, as is the builder system itself.  But I can add to that engine- or game-specific patches if necessary.  I've already added a patch that knows about this particular engine's asset system, and can use it to schedule other files for loading, thus allowing for references to external assets which may be loaded in the future (and patched at that time appropriately).  A different game might have an entirely different asset system, in which case I can chuck the one patch written for this game and write a new one against that engine; the system should scale without losing its general purpose core.

The actual XML parser and builder system is very simple--only a couple hundred lines of code.  But I should mention that it only works in C++ because my game engine is backed by a (fairly involved) reflection system.  Using an Interface Definition Language, I can create classes that are laden with meta data, much like Java's Class object.  Using that data I can poke into anonymous classes at runtime and set fields, which is how the patches in the builder actually work.  I think this approach could be done without reflection, but it would basically resemble the hard-coded types with unique static data structs method that I mentioned above.  I'll talk more about the reflection system in a future post.

To bring this giant document to a close, I just want to note that the methods I've described here are hardly an exhaustive list.  These are the various approaches that I've tried to spawn objects in games; there are many others and probably a lot of really good ideas that I've never considered.  But when making a game engine, the question of how objects get spawned--and what a game object actually is, is a pretty huge piece.  Though sort of mundane, it's probably worthy of a lot of thought.

Friday, September 17, 2010

Long Time, No See

I haven't written anything here lately because, well, I've been swamped, and I mean like seriously submerged in the murky depths of work, travel, and more work.  We're talking Creature from the Black Lagoon levels of swamped here.  I'm probably growing gills.  That would actually be pretty cool.


Apparently I need to, at the very least, log in to the blog a little more often because I was pretty surprised to find 45 comments awaiting moderation today.  Sorry about that.  I turned off moderation for now, and unless the spammers ruin it, we can leave it off.

That said, let's lay down some ground rules.

1) If you're stuck, or have a question about a particular level, posting a comment here is probably not the fastest route to an answer.  I don't have time to answer (I'm swamped, remember?), so another forum someplace might be a better bet.

2) I love bug reports.  I especially love bug reports that are entered into bug reporting systems.  If you'd like to report a bug (or, as the case seems to be most commonly, a feature request), there's a whole official-looking system all set up for you already.

3) There's some pretty interesting code discussion going on at the forum setup for that purpose.  If you want to talk code, that's the right spot.

So, being swamped, I don't have a whole lot of new information to report, so I'll leave you with two cool things.

First: there are at least five games on the Market that were built with Replica Island code: Android Jump (Papijump clone), Prototype (an Arkanoid game with some interesting twists), Greedy Pirates (a Nanaca Crash sort of game with cannon balls instead of safe-for-workified girls), Super Treasure Rocket (a platformer), and Project G.E.R.T. (I'm not sure what to call this one).  Though not yet on the Market, there's also a pretty neat Fruit Ninja clone, complete with 3D fruit to slice, that was built on the RI code.  I think that's pretty freaking awesome. Update: We can add Ski Classic and Auto Traffic to the list, as well as Pocket Racing to list!  These games were built with SpriteMethodTest source, which is basically the primordial version of the renderer in Replica Island.

Second: Here's a picture of the Replica Island booth (part of a larger Android booth) at Tokyo Game Show this week.  This was all put together by a third-party event organizer, and while I gave them permission to show the game, I had no idea it'd be so, I dunno, official looking.  Cool!

Sunday, June 20, 2010

Replica Island Passes a Million Installs

Holy crap!

Replica Island passed 1,000,000 installs today, 103 days since its launch on March 9, 2010.

Thanks for your support, everybody!

Monday, May 3, 2010

Control Configuration and Abstraction



The #1 thing that I've learned since shipping Replica Island is that users want configurable controls.  I mean, I might have guessed that some devices would have one sort of controller and not another, but I didn't anticipate the number of people who prefer a specific control configuration even when others are available.  Users with trackballs and directional pads asked for configurable keyboard settings, and when I added orientation sensor-based movement for devices without other controls (I'm looking at you, Xperia), many users who could already play the game chose to switch to tilt controls too.  I've made four updates so far and all of them have had to do with the input system; in the first three I added more and more configuration options, and in the most recent (v1.3) I rewrote the core input framework to improve non-standard control configurations.

When I started writing Replica Island, the only device available was the G1.  About half way through development I switched to an HTC Magic, and at the very end of development I switched to a Nexus One. The game was entirely designed around HTC's trackball-on-the-right design.  Fairly late in development, devices sporting directional pads (like the Motorola Cliq, and more importantly, the Droid) started to hit the market, so I added some support for d-pad controls.  I didn't really think anybody was going to use the keyboard to play, so I only added a few key-based controls to support the ODROID.

The input system started out like this:


MotionEvents from touch and trackball motion, as well as KeyEvents, were passed to the InputSystem (via the GameThread, for reasons I'd rather not discuss), which recorded them in some internal structures.  The goal here was to abstract the Android events from the game interface.  The game wants to be able to say things like "is the jump button pressed," or "was the jump button just pressed since the last frame," or "how long has it been since the last time the button was pressed."  It's a query-based interface, rather than the message-based interface that the Android framework provides.  So the initial role of the InputSystem was to record Android events so that they could be queried in the future.

The trackball was tricky to get right.  I want to allow the player to flick the trackball in a direction and have the character get an impulse in that direction scaled by the magnitude of the flick.  But the Android motion events come in at a fixed frequency and fixed magnitude, so in order to build a vector describing recent motion, I needed to maintain some history between motion events.  My first implementation, which survived for the entire course of development, was to cache a history of 10 motion events and calculate the average direction of motion across all of them to find the flick direction and magnitude.  After a specific timeout had passed with no new events, the cache was cleared and averaging would begin again with the next event.

This worked ok as a way to calculate a motion vector, but it had problems.  The biggest issue was that there was no way for a user to move slowly; even if the user rolled the ball slowly (thus causing motion events to come less frequently), as long as he rolled fast enough to make the internal event timeout, the events would get averaged together and would come out looking the same as a fast flick.  So users who tried to move with precision or in small steps often found themselves rocketing across the level.

When I went to add d-pad support, I just treated the pad as a different source of motion events.  I treated each keydown as a roll of a specific magnitude in a specific direction, and fed that into the same cache system I used for motion events.  This worked, sort of: it allowed me to pipe the directional pad through the trackball interface (which connected directly to the game) pretty easily, but it didn't feel good.  The problem with this approach was that directional pad events don't need any averaging; in fact, you want exactly the most recent state to be represented, as the player can release a key at any time (the trackball, unlike other kinds of input, never goes "up", and thus required a history).  So directional pad support in Replica Island, in the first few versions, sucked.

Add in configurable control options and very quickly my simple G1-centric input system grew into a mess that didn't work very well.  So, for the most recent version, I rewrote the whole thing.  Now the structure looks like this:


The main change here is to separate input recording (necessary for querying) from game-specific filtering and control configuration switching.  The InputSystem is now generic; it just records input events from the keyboard, touch panel, orientation sensor, and trackball, and provides an interface for the current state (as defined by the most recently received events) to be queried.  A new system, InputGameInterface, reads the hardware state from InputSystem, applies heuristics and filters, and presents fake buttons for the game to use.  This way the game can ask for the "directional pad" and get input from a trackball, orientation sensor, keyboard, directional pad, or whatever, already filtered and normalized.  I put all of the filtering code for the trackball into this class, and I can now pass directional pad input directly to the game without tying it to the trackball.

Speaking of the trackball, I changed my approach to filtering.  Now I accumulate trackball events that occur within a very short cutoff, and average them after a slightly longer cutoff.  Instead of turning the trackball input "off" after a fixed duration, I make it decay until it reaches zero.  This lets the user make small, precise movements, and still get a big motion from a large flick (as in the latter case, events occur in rapid succession and accumulate).  This method also gave me an obvious spot to stick a sensitivity factor for the trackball, which several users of devices with optical trackpads (HTC Desire, Samsung Moment, etc) had requested.

The new system probably needs a bit more tuning, but I played the game through with it and it feels pretty good.  The code is about 100x cleaner now, and InputSystem is something that others can easily reuse without any other dependencies.

Sunday, April 11, 2010

Design Post-Mortem: Three Mistakes

While I'm pretty happy with Replica Island, releasing it has definitely been a learning experience.  Some of the design choices Genki and I made were good, others were ok, and a few were bad.  Today I'm going to talk about three mistakes I made in the design of this game.

Mistake #1: This particular jump.


Turns out that a lot of players die right here.  Heck, I have the metrics to prove it.  This is sort of a difficult jump because you have to make it across a wide pit and then land in a very small space near the top of the screen.  This jump started out a little easier, but it got harder when I compressed the vertical size of this level to deal with some camera problems.  The real problem here, though, is the distance.  It turns out that this is the first spot in the game where you are required to use second-order flying skills to reach the other side.

Just what is that skill?  Well, it turns out that some players never realize that they can stay aloft for longer if they let momentum rather than fuel carry them forward.  If you press the jump button and get your speed up in the air, you can release the jump button and stay aloft until gravity overtakes you and you begin to fall.  At that point you can hit the jump button again to combat gravity and maintain your altitude.  You can't do this forever because you'll eventually run out of fuel, but using this method you can jump much greater distances than if you just hold the jump button down constantly.
The real problem is that I never teach players how to fly that way explicitly.  There is lots of tutorial levels designed to make sure you can fly, but it turns out that only the most basic flying skills are required to get passed those sections.  This area is the first in which you cannot progress unless you've figured out how to use the more complex flight mechanics, and people get stuck here.

What can I do about it?  Probably this area itself is fine; a better tutorial on this particular skill is probably in order.

Mistake #2: The Case of the Robot Spewing Spawner


When I made the robot spawners, I though it would be a funny easter egg if you could possess them.  Part of the plan was to allow the possession orb to possess any machine, and I thought possessing the spawners would be a little hidden reward for users that experiment.  The problem is, I added this functionality before we understood how the robot puzzles were going to work; in the final game, it's trivially easy to possess a spawner, and most users are confused rather than elated.  Even worse, being able to possess a spawner sometimes gets in the way of possessing a robot, which is pretty annoying.  I realized that this might be a problem before we released the game, but I left it alone because I thought it was funny.  Now there are multiple videos about it.  Pretty undeniable proof that I messed this up.

What should I do about it?  I should probably turn the easter egg off or at least find a way to make it much harder to find.

Mistake #3: The impossible puzzle.


You have no idea how many people have e-mailed me about this puzzle.  It's clearly the most difficult part of the game for a huge number of users.

In the first version of the game, this section was missing the red spikes due to a bug in the level data, which made this puzzle even more confusing.  But even after fixing that, I continue to get several e-mails a day asking about this part.

If you don't want this puzzle spoiled for you, stop reading now.

OK, I warned you.  The solution here is to use the Possession Orb to grab the robot and run him into the button.  Pretty simple, I thought; the real challenge in this puzzle's original form was actually just maneuvering the Orb through the spikes before it dissipates (in an update I added a gem to this level, so the Orb survives for longer).  But it turns out that users weren't even figuring out that they could use the Possession Orb here, even though they've seen this pattern several times in slightly different contexts earlier in the game.

I finally realized what the real failure is here: players don't realize that the Orb can fly.  The tutorial says something like, "tilt the phone to control the orb," but if you never try tilting it up, you'll never learn that the Orb can fly.  I think that players also forget that the Orb is in their arsenal, but they'd probably figure that out eventually.  Not expecting it to be able to fly means that many don't even try it.  This is a fundamental teaching failure on my part and makes this puzzle a whole lot harder than it was intended to be.

What can I do about it?  Well, as a first step, the tutorial level should force you to send the ball up at some point.  After that though, the game needs to reenforce the fact that the Orb can fly, so I'll probably need to modify some levels to encourage that behavior.

The great thing about this is, I can fix the problems and send out an update and see if my fixes were successful.  And if not I'll try again.  Traditional video games have never had this sort of ability to iterate interactively with the audience, and I'm really learning a lot from it.

Friday, April 9, 2010

Replica Island: One Month On

As of today, Replica Island has been available on Android Market for exactly one month.  I thought this would be a good time to see how it's been doing.

Turns out it's doing pretty well!  It's holding steady at 4.5 stars and it just passed 250,000 installs.  There have been a few bugs; I've made a few updates, and there are a few more fixes in the works.  But most users have been extremely positive about the game.

I've been diligently recording my install numbers from the Android Market Publisher site all month so that I can produce this graph.

Before I talk about the graph, let me tell you a little bit about my launch plan.

Replica Island is a series of experiments.  I'm trying to learn how games should be made for Android, and part of that process is learning how they should be marketed.  So as part of the experiment, I made the following launch plan:
  • First ten days: no PR, no announcements, nothing.  Just upload it and see what happens.
  • Day 10: send out press releases, upload YouTube video, post on blog.
  • When installs start to slow, prepare a second round of press releases, this time for a different audience.
My marketing budget for this project is $0.00.  I know basically nothing about marketing, and I sometimes think that Nicholai, my PR guy, was dropped on his head as a child.  This plan reflected my need to spend no money and have basically no method of marketing other than trying to get the word out to blogs and news sites.

The first week I made no announcements in order to track the quality of organic growth.  Turns out organic growth was steady and apparently fairly constant; Replica Island was downloaded about 18k times in that first week.  

On 3/18/10 I uploaded the first update.  This update fixed a few bugs and added tilt-based controls.

On 3/19/10 Nicholai sent out press releases to a bunch of Android blogs and a few non-Android gaming blogs.  The total number of blogs targeted was small, maybe five or six.  Of those, AndroidGuys.com was the first to respond (and their report remains one of the most detailed).  A bunch of other blogs copied and pasted the AndroidGuys report (I swear 99% of blogs nowadays are basically retweets of other people).  There was an immediate increase in daily downloads.

On 3/22/10 Gizmodo posted the YouTube video and wrote a nearly content free report (though they still managed to work in an anti-iPhone reference, as if part of their editorial goal is to promote fanboyism).  Apparently a lot of people read Gizmodo, as downloads spiked on that day and then continued at increased volume.  Also, the retweeting of the Gizmodo article guaranteed that the first several pages of search results for "Replica Island" were all different sites referring to the same two articles.

On 3/30/10 Replica Island was added to the list of Featured Apps in Android Market (full disclosure: I'm a Google employee but was not involved in the decision to feature this game).  You can see the effect of being featured in the graph; downloads per day shot way up, and have remained high.  Featuring makes apps really visible!

Since app downloads haven't slowed down yet, I haven't implemented the next part of the plan, which is a second round of press releases aimed at different blogs.  I hear that Nicholai has some crazy scheme up his sleeve, but as long as it costs $0.00, I'm fine with it.

So, here's my takeaway from this first month on Market:
  • Users want games in traditional genres.  Replica Island gets a lot of love from users just for being a recognizable game genre.
  • Updates don't seem to really affect downloads.  Some developers have complained that mixing uploads and new releases in "Just In" allows unscrupulous developers to ship superfluous updates just to increase their visibility, but my data doesn't show any particular advantage to being in Just In.  I think that list moves too quickly.
  • Organic growth can work, but even the tiniest bit of marketing goes a long way.  Getting the word out to blogs, even with a simple web site or press release, is huge.  Those people who are expecting direct-to-consumer digital distribution to be the end of marketing are sorely mistaken.
  • The YouTube video we made was almost an afterthought, but it's been reproduced in more blogs than any of our screenshots or promotional text.  YouTube will definitely be a big part of our next push.
  • Nicholai went to all the trouble to make a press kit, and write press releases, as described in the excellent Care and Feeding of the Press, but 99% of blogs just copied and pasted the summary text we put on the front page.  I think less than 10% of the blogs that posted about the game actually tried playing it.
  • Development and marketing on a budget of $0.00 totally works!
So that's all for now.  I'll report back when the data reveals some new pattern.  Thanks much to everybody who is playing, and to all of the blogs who covered the game, even those that just copied their text from somebody else.

Thursday, April 8, 2010

Monday, March 29, 2010

Replica Island User Comments Are Hilarious

Update: Blogger apparently isn't advanced enough to deal with images reliably. I moved them to a regular web site.


So Replica Island has been out for about three weeks now, and today it reached 85,000 installs, which is pretty cool.

Lots of users have been nice enough to leave feedback, too.  Most of the feedback is overwhelmingly positive, which is fantastic--there's nothing better than knowing that something you made is bringing other people pleasure.  And even the negative comments can be useful; I've identified several bugs and high-value features thanks to the suggestions of users posting on the Market page.

Here's a few of the comments that really made my day.

Flattery will get you everywhere.  I'm preparing a fix as we speak!



That's some high praise right there.

Thanks!

Then there are the useless comments.  These are comments that, typically, contain so little information or are so undecipherable that they don't tell me (or a perspective user) anything useful about the game.  These are mostly comments like, "doesn't work" or "I'm stuck."


First the shift key and now this!


Wait, which is it?  Man, how would you rate a game that you liked?


Thanks for the bug report!  I'll get right on that, uh, wait, what did you say happened again?


Perhaps you missed the text at the very beginning of the game that explained how to move?  It's pretty complicated, I know: "roll the trackball" or "press the d-pad."  I mean, come on, give me a break, right?


Harsh!  Wait, are you saying that the effort is only worth 2 stars, or that the game is so bad that it only warrants 2 stars because we put a lot of effort into it.  Wait, what are you saying again?


Your feedback has ensured a higher standard of quality for our next app!


Thanks, but maybe you meant to post on the Zenonia page?

Then there are the hilarious comments.  Sometimes they are sort of innocent, like this one.


Sorry to let you down Etan, but I'm not sure exactly where that expectation came from, as this is our first game and all.  Also, maybe you could have added "mediocre" or "run-of-the-mill" in there somewhere--I'm sure there's some way to fit in another few words meaning "average."


See, this is almost a useful comment!  There really aren't any cutscenes in the game (well, there's one, but I won't spoil it), but there is a lot of dialog--maybe that's what you meant?  I'm not sure how to make the game faster and slower at the same time, though.

There were a bunch of comments with a common theme that I couldn't figure out.


Uh-oh, that sounds like a bad bug!


How could this happen?  I tested the Droid extensively!


Oh no!  This sounds like a real problem!

I was so confused about what these posters were trying to tell me.  Is there some horrible bug in my game that prevents moving forward?  How can that be?  And if that's the case, how come only 4 people out of 1000 have reported it?  I've played the game on the Hero, I know that it works fine.

Finally, one final post from a user with this problem suddenly made it clear what was happening.  This post has since been removed by its author, but it lives on forever in the databases of services like AppBrain.


If you've played Replica Island, you might remember the intro sequence.  In it, a character (Wanda) runs through a few short credits, finds the broken Android robot, and says a few words.  Then the game changes to the first level, in which Dr. Kabochanomizu teaches you how to play.  That intro sequence takes, on average, 48 seconds (I know because I have user data from 85k users telling me so).  During that period, you can't control the game.  These users are people who booted the game up and closed it again in less than 48 seconds, and then went back to Android Market and wrote a review.

I actually figured this out before Patricia came along and made it clear, so in the 1.1 update I released about two weeks ago I added a little flashing "Please Wait" message to this part of the game.  Still a few folks (like our friend Patricia here) didn't figure it out and gave up in less than 48 seconds.

I guess I don't have anything to say to people who give an app less than one minute to be awesome.  It might be nice if Market displayed the amount of time each user had the app installed before writing a review.



Ah, the good old backhanded complement!  However, this poster is mistaken: I never claimed that the game would get 50 fps on the Droid.  I said it would get 50 fps on the G1, which it does during normal play (it can drop to about 30 in complex scenes).  No game draws faster than 30 fps on the Droid (or Nexus One) because those devices are fill limited.  Sorry about your luck, Mario, but your device is going to be 30 fps for all games forever.  It's still a pretty cool phone, though.



Do you see this!?  THIS is how you write useful feedback!  Both points of feedback are great, particularly the suggestion box.  I am totally going to add that in the next update.  Glad she liked the game, too.

The funniest comment so far, however, wasn't posted on Android Market.  The user was so incensed at the game that he visited the Replica Island web site and sent e-mail to Nicholai, my PR guy.
By the way, your game sucks big donkey balls. I have spent a Good amount if time playing only to find I am at a part I can't pass. I would tell you what part of this stupid game it is from but I can't go to a reference point. I have also ran into several game glitches and I just can't believe you would publish such a piece of shit. Fuck you.
This is so awesome.  Mr. Russell Hall, whoever you are, you totally made my day.  Hopefully one day you'll figure out wherever it is that you are stuck and continue putting a good amount of time into my donkey-ball-sucking-game.  Seriously, this was the first comment to really make me laugh out loud.  Thanks.

Tuesday, March 23, 2010

Design Post-Mortem: The Possession Orb

Rather than write a big long post-mortem of how developing Replica Island went, I'm thinking about writing smaller articles that focus on a single element of development.  Just because the game has shipped does not mean that development is over, and I'm sure that I have much more to learn now than I did before the game shipped.  And speaking of the game's release, it's tearing up the charts, thanks to Nicholai and his crack team of PR ninjas (ok, he doesn't really have any PR ninjas).  This article, despite being ultra thin on details, seems to have reached a lot of users.  I'll post more details soon.

Ok, so for this first Design Post-Mortem, I thought I would talk about the evolution of the Possession Orb.  The Possession Orb is a special projectile that the Android robot can fire out of his body.  It has the power to possess machines, and running it into, say, an enemy robot will let you control that robot.  The Orb is controlled by tilting the phone, and you can extend its life time by collecting red gems.

The Possession Orb did not originally start out as an orb.  And actually, it didn't originally have anything to do with possession either.

My original design for the Possession Orb was called the Player Ghost.  The idea was that the player could drop the ghost somewhere in the game world, and after a few seconds it would begin to replay the player's recent movement.  At any time the player could click a button and instantly teleport back to the ghost's current location--it was like a way for the player to undo a few seconds of movement.  The ghost, I figured, could also press buttons, so there could be timing challenges involving hitting buttons with the player's body and then again a few seconds later with the ghost.

I got this idea from a crazy Nintendo Entertainment System game called Lot Lot.  Lot Lot is a puzzle game in which two cursors move across a board filled with balls.  One cursor is under the player's direct control, and the second cursor is following the path of the first, but about two seconds delayed.  When the player's cursor is over a grid square that has balls in it, the player can press a button to swap those balls for the ones in the square pointed to by the second cursor.  So game play consists of thinking about where you want the two cursors to be, drawing a path that you know will be correct two seconds into the future, and then hitting the button at the right time to shift balls to the edge of the board before they fill up.  It's very difficult to understand at first but once it clicks the game play is crazy.  Here's a video of Lot Lot in action:



So, my idea was that the Player Ghost would be like Lot Lot's second cursor: a replay of the player's recent movement that could still affect the game world.

Here's some early design sketches I made about this idea:



Sounds cool, right?  I thought it would be cool if you could snap back to the ghost's location too.



I liked this idea, but when I ran it by Genki, my partner in crime, he was skeptical.  He thought that puzzles would be hard to design and that users would have a hard time understanding the mechanic.  But I wanted to try it out so I went ahead and implemented it anyway.

Functionally, the Player Ghost worked exactly as I had imagined.  It wasn't hard to implement and it actually looked pretty cool.  But it quickly became clear that Genki was right: the concept made no sense and designing puzzles was really hard.  It was clear that puzzles were going to require a bunch of different objects just so that the ghost could work (e.g. doors that close immediately after you pass through them, rather than after a fixed duration), which lowered the quality of the idea significantly.  And it was confusing as heck; I wasn't confident that even with supporting game objects the idea would ever really make sense to users.

Genki suggested that instead of the player leaving the ghost behind, the ghost should leave the player behind.  This idea made a lot more sense, but I wasn't sure how to make puzzles out of it.  Eventually we realized that possession is a cool mechanic that the ghost could be useful for (rather than just depressing buttons), and that tilt controls might be a fun way to add diversity to the input system.  Tilt controls implied flying, so the ghost was freed from gravity.  And at that point, it didn't make any sense for it to look like the Android robot any more, so we changed it into an orb (collisions with the background were more believable this way too).

Once we hit on the mechanic a lot of potential avenues for game design immediately presented themselves, which was a good indicator that the idea had more legs than its original version.  Actually, I think that this mechanic is quite under-used in Replica Island.  There's a lot more that we could have done with it, and actually tested with it, that didn't make it into the final game (try running the Possession Orb into a turret, for example).  Maybe this is something to experiment with in a future update.

Saturday, March 20, 2010

Replica Island Released!

I released Replica Island almost two weeks ago, just before I gave a talk about Android game development at the Game Developers Conference.  Here's the quick details:

Here's a QR Code you can scan to bring the game up in Market:

And here's a quick trailer video:


Whew, glad to get that stuff out of the way.

You might be wondering why I am posting this now instead of two weeks ago.  Well, I wanted to run an experiment.  I wanted to see what the game would do on Android Market with zero promotion.  So other than mentioning the game in my talk, I've not advertised Replica Island anywhere or done anything (other than a quick update to address control concerns) to make it particularly visible.  I wanted to see what would happen if I just left it alone for a while.

So after 10 days on Market, I'm sitting at about 18k installs and 4 out of 5 stars.  Not bad!  By comparing the data I get from the Market Publisher site to the data coming back via my own reporting system, I can tell that about 15% of users choose to opt-out of the anonymous metrics reporting system.  Which is great--I have tons of data from users who are cool with me having it.

As of today I've had Nicholai, my PR guy, turn on the PR faucet.  He's going crazy with press releases and other promotional tools.  The next experiment is to see what happens to my download growth rate once Nicholai has worked his magic.  Once that experiment has produced enough data, I'll post about it here.

I've also rewritten a lot of my data visualization tools to deal with the huge amount of data I am getting from users.  I'll write a post about the new system I am using to visualize the player death data next.

In the mean time, check the game out and let me know what you think!

Friday, January 22, 2010

Fragmentation? More like Fragmentawesome.

I'm lucky enough to have occasional access to lots of different Android devices via my work. The whole point of the Android approach to apps is that you can write an app on one device (or even an emulator) and deploy it across everything. In my case, that's been pretty true. I've tried Replica Island on the following devices:
  • Google Nexus One
  • Verizon Droid by Motorola
  • HTC Magic (The myTouch in the US, HT-03A here in Japan)
  • HTC Dream (The G1)
  • Samsung Behold II
  • Samsung Galaxy
  • HTC Hero
  • HTC Tattoo
  • LG Eve
  • ODROID
  • Covia SmartQ5
  • Android for x86
The cool thing is, Replica Island ran on all of them without complaint. That's not to say it was playable on all of them--the Covia SmartQ5, for example, has no keyboard, trackball, or even orientation sensors, and you have to use a stylus on the screen (it also has no GPU so the game runs extremely slowly). And some devices (like the LG Eve) have directional pads that are really poor for games. I ran the game under Android for x86 via virtualization, and while it worked it was slow enough that I have new respect for the Android emulator. But the game runs, pretty much error free, on every single Android device I've tested it on.

I don't have regular access to all this hardware to test on, so when a phone comes my way I jump on it, install the game, and try it out.  Excepting basic support for multiple screen sizes and input systems, I don't have any device-specific code. I developed Replica Island almost entirely on Dream and Magic devices; it's built for a trackball and touch screen. I've added support for directional pads as well, which covers almost all of the phones on the market. The game runs at a nice frame rate on the Dream/Magic hardware, and it's very smooth on faster devices like the Nexus One and Droid. But that's it--no special case code for any particular device anywhere. Cool!

You might be interested in which of these devices plays Replica Island the best. The answer might surprise you. Wait for it... ok, it's the ODROID.

Yeah, seriously.

What the heck is the ODROID? Well, it's an Android device (not a phone) sold by a South Korean company called Hardkernel. Actually, the consumer version isn't even for sale yet, but you can buy test hardware for nebulous "development purposes" on their web site. The Wonderswan ODROID runs Android 1.5 (sounds like they will have a 2.0 update soon), has an HVGA screen, a Samsung CPU at 833mhz, a touch screen, orientation sensors, and all the other standard stuff. What sets it apart is the game-focused form factor, a real directional pad, and four face buttons. The thing is clearly designed for games.


My ODROID arrived in the mail yesterday, direct from South Korea. It's clearly prototype hardware; the thing is made out of light plastic and looks fairly cheap. There's a very strange power button that doubles as a hold switch and screen orientation switch, and I keep accidentally hitting the capacitive volume controls where I expect shoulder buttons to be. The directional pad is actually pretty bad compared to what you'd find on gaming hardware like the Nintendo DS or Playstation Portable, but it's better than your average phone. The thing can talk to adb, it came with an SD card already installed, and supporting the A/B/X/Y buttons is trivially easy (they just map to regular keyboard events).

But the reason that the ODROID is the best device for playing Replica Island isn't just because of the game-like form factor and controls. Unlike most other Android devices, the ODROID is a combination of fast CPU and medium resolution screen. The devices with larger screens tend to be fill-rate bound; though the Nexus One and Droid have extremely capable CPUs and GPUs, the high resolution screens on those devices work against them when it comes to games (it's almost impossible to break 30 fps on those devices via the GPU, though they can crunch really complex scenes at that speed without breaking a sweat). On the other hand, the Magic/Dream class of devices have the same HVGA resolution, but tend to be CPU bound--rendering is fast but I spend quite a lot of time running the game simulation. The ODROID has neither problem--its CPU is pretty fast and its GPU has no problem filling the HVGA display. As a result, Replica Island is silky smooth on the ODROD--a constant, reliable 60fps. Add that to the game-ready control scheme and you have a pretty great game experience.

That's part of what's so awesome about the run-everywhere Android approach. Replica Island works on all Android devices, pretty much by default. It's fun to play (well, I think it's pretty cool) on most average phones. But when some crazy company wants to make some crazy device that's good at one thing, they can do so without requiring any changes to the applications themselves. In this case, the ODROID is a surprisingly solid game device, at least for games like mine (though other games, particularly 3D games with complex scenes, are probably faster on devices like the Nexus One). And supporting it costs me literally nothing; I just loaded it up and it worked. That's pretty neat.