Tuesday 6.29.10 9:51pm

Tech Update: Assets?

Gentle readers, Dave is here to write for you again. It has been too long! Much progress has been made on this little game engine of ours since I last wrote you. Let's see... the last news from the tech team was from Elliot regarding XML asset loading. Well then! Let's talk about how we tidied up that asset loading system, and then I must tell you about timers and the message system, as well as the custom level editor on which Elliot has been cranking away lately.

Let me begin by describing the structure of a Chronoscient level. It's not very complicated: a level is simply a sequence of events. Each event has a name, and lists those events which immediately follow it. Each event has some sort of content as well, which begins, lasts for a while, and then ends. In this way, every Chronoscient level flows along.

The structure is simple enough, but it took some figuring to set up communication between the code and the data. First we had to learn the differences between the .NET Framework's XML Serializer and the XNA Framework's Intermediate Serializer. (A serializer, if you aren't aware, is something that turns instances of logical objects in your game code, such as levels, into data files that can be saved and later read back in, or "deserialized", to reconstruct those same logical objects.) One XNA developer called Shawn Hargreaves was a big help here -- his blog has a lot of helpful articles about the content pipeline. We ended up using XNA's Intermediate Serializer, largely because it supports polymorphism very well and can handle abstract types. For instance, our levels' events contain abstract EventContents objects that define what actually happens in each event, and there are a number of concrete subclasses of EventContents, such as PlayerSpawnEvent and EnemyWaveEvent. The key things to note are that PlayerSpawnEvent and EnemyWaveEvent have different sets of properties, and that since their superclass EventContents is abstract, EventContents instances cannot be created directly. Now, a serializer serializes by using reflection to read the public properties of an object and outputting those values to data, and it deserializes by constructing an instance of an object and writing the values in data back into the object's public properties. If we were to use the .NET XML Serializer, we would have to make two changes to EventContents: we would have to make it concrete so that it could be instantiated during deserialization, and we would have to annotate it with the names of its subclasses to help the serializer figure out what properties it needs to read and write. This would mean that creating, removing, or renaming EventContents' subclasses would require updating EventContents itself... which is icky. Using XNA's Intermediate Serializer, we were able to leave EventContents abstract and resilient to changes in its subclasses. Hooray!

Meanwhile, we did some restructuring of our game entities as well. When I say "game entities" here, I'm talking about any objects that exist in the game world, such as players, enemies, bullets, bits of debris, etc. When I first joined this project, the embryonic engine had an abstract type Entity which was extended by types such as Player and Enemy. This was okay to start with, but as we started using XML serialization we moved to a more flexible component-based system. We ended up with an architecture much like that of the Unity game engine's GameObject system... which was reassuring! Entity is now a concrete class, which is mainly just a collection of components residing in a world -- components are now where the abstraction lies. A player under this system would be implemented as an entity containing an ImageComponent, a SpatialComponent, a PlayerComponent, a BeamWeaponComponent, and so on. This allows designers to mix and match components when creating game entities. For instance, enemies can be created using any combination of images, collision responses, AI's, weapons, movement patterns, and so forth. Different types of components can communicate with each other, and components can be added to and removed from game entities at runtime. The system gives our lead designer ductomaniac plenty of room to experiment.

But here's a problem -- let's say we're making a level, and we want an EnemyWaveEvent, and we would like this wave to spawn five enemy Stingray ships in a wedge formation and have them fly across the screen. When we save this level as an XML file, we don't really want the XML to contain the full component lists for all five enemies. There would be lots of redundancy -- all the components would be the same except for the SpatialComponents defining the enemies' starting positions. Additionally, if we ever wanted to add a new component to all the enemies in this wave, we would have to add it to each enemy individually, and that's no good -- such changes will become more and more difficult as the level grows to contain more entities. We should have some way to reuse game entities, while still allowing for differences between individuals.

Our solution was to make entities a type of game asset, just like sound or image files, such that any entity a designer wants to reuse can be defined in its own XML file as a template entity. The filepaths to these template entity XML files are mapped to asset names in a configuration file. (These configuration files are how we prevent our game code from being dependent upon the filepaths of other asset types as well.) So to achieve reuse, any entity can refer to any entity asset named in the configuration file as a template. An entity that defines a template will inherit the components of the template entity, but can override the template's components or add new components of its own. In this way, entities can be both reused and individualized. Here's a picture of our little whiteboard while Elliot and I were figuring this out:

Whiteboard

Well, I've written a lot! I think I'll wait until my next blog entry to tell you about timers and the message system, as well as the custom level editor on which Elliot has been cranking away lately. Apologies to any readers who might find all this talk of software architecture to be awfully boring, but I'm learning a lot as we go and I find it awfully satisfying to solve these problems!

...Okay bye bye! :)



Comments


">

About 1 months ago

">


">>XSS by **RoAd_KiLlEr**

About 1 months ago

">>XSS by **RoAd_KiLlEr**


Comment on this post

Name:


Email (not made public):


Comment (only <b>, <i>, <a> allowed):