Gamasutra: The Art & Business of Making Gamesspacer
The Components of a Platypus: An HTML5 Engine Mid-Mortem
Printer-Friendly VersionPrinter-Friendly Version
View All     RSS
April 23, 2014
arrowPress Releases
April 23, 2014
PR Newswire
View All





If you enjoy reading this site, you might also want to check out these UBM TechWeb sites:


 
The Components of a Platypus: An HTML5 Engine Mid-Mortem
by Todd Lewis on 12/16/13 01:55:00 pm   Featured Blogs

The following blog post, unless otherwise noted, was written by a member of Gamasutra’s community.
The thoughts and opinions expressed are those of the writer and not Gamasutra or its parent company.

 

The Platypus engine is Gopherwood's first foray into the world of component-based design. The engine has a long life ahead of it, but as a sort of mid-mortem we thought we'd take a second to share our reasoning for going the component-based route and how we feel about the results so far.

 

Components. Kinda like Legos, but less painful to step on.

When we first got the go ahead to put together an HTML5 engine for PBS Kids the first thing we did was fish around for a proper design template for the engine. When a talented programmer friend recommended we look into a component-based design, we did exactly that. For those unfamiliar with the model, the idea is that game entities are made of a simple object whose functionality is fleshed out by adding a collection of objects called components. These components are designed to function independently so that they can be added/removed/replaced with impunity. After a little research into the design we were convinced by a few arguments we found.

 

Arguments for Components

The first argument for a component-based design was an argument against using the more popular class-based design model with JavaScript. JavaScript is not a class-based language and doesn't lend itself to a traditional class-based design model without some finagling (that's a technical term). We felt that a component-based design fit more cleanly in JavaScript's design tenets. By starting out with a design model that better matched JavaScript's nature we felt that we would benefit by doing less working against the grain.

 

Another benefit we saw for avoiding a class-based design was to get away from the bloatedness (another technical term) of inheritance. With engines that use inheritance, you often inherit from several standard classes when you are creating a new entity. In the process you often inherit more than you need for what you're doing. This is because each new entity has special cases that requires small revisions and additions to the standard inherited classes until eventually these classes are bloated with functionality that is useless in most situations. Component-based design is in some ways a form of hyper-multiple-inheritance, in that each piece of functionality (logic, ai, physics, etc.) is 'inherited' from a component. The difference is that each component is designed to work discretely, meaning that special cases (and the bloating they tend to cause) can be dealt with using a unique component while the rest of the components remain standard issue.

 

Finally, because all of an entity's functionality is found in its components, the argument stood that it would be easy to quickly assemble new entities from existing components and reuse components.

 

The Good Side

You mean we aren't unique?!

So did it live up to all the promises? For the most part, yes. We've been very happy with the ease of developing in the component-based model. In particular, creating new entities from existing components has made the development process considerably quicker. In some cases, such as the playable characters in Wild Kratts: Monkey Mayhem, we are able to create entire entities without a single line of unique Javascript. And in most cases, we are able to reuse existing components to add large pieces of functionality to an entity without adding more functionality than we need. Designing entities is made easier by using JSON to assemble the components that will make up an object and give initial settings for those components. All of these things add up to the ability to make lean entities efficiently.

 

 

A good example of how easy it is to put together an entity from standard components is the ant entity in Monkey Mayhem. The ants in Monkey Mayhem behave like Goombas from the Mario series. To create their behavior we use four standard components: ai-pacer, logic-directional-movement, logic-gravity, and collision-basic. Collision-basic allows us to define what the ants will collide with. Logic-gravity will cause the ants to fall when they aren't supported by terrain or a solid entity. Logic-directional-movement tells the ant how to move each game tick (in the ants case it's defined to move horizontally at a steady pace). Finally ai-pacer works in conjunction with collision-basic and logic-directional-movement to tell the ant to reverse direction whenever it collides with a wall. While this is only one example, it's easy to imagine how by swapping out one of these components with a new one we can quickly create new types of enemies.

 

The Challenges

While many of the promises of a component-based design have come true, that's not to say there haven't been challenges.

 

There have been multiple systems that have strained against the restrictions of the component-based model, particularly the limitation that components should be discrete and ignorant of the inner-workings of one another. Our collision system is an example of a system that violates this principle. We found that some components needed to be more tightly coupled than was possible in a pure component model and so we opted to violate those principles instead of creating an unnecessarily complex workaround. Deciding when and where to do this in the engine has been a recurring question. As our experience with the engine grows we feel that the answers to when to break the rules will become clearer.

 

Pew! Pew! Pewpew!

Another challenge was developing a means of communicating between components. It took some iteration before we found solutions that felt natural. For communication within an entity we used an event-based model. For those unfamiliar with this model it is somewhat similar to how a satellite relay works. A component that wants to send a message to another component broadcasts the message to its owner entity (the satellite). Which then rebroadcasts the messages to any listening components. This worked well for communication within an entity, but didn't scale to communicating between entities because there was no simple way to specify which entities would receive the message. Instead, we came up with a couple solutions that were useful for different situations. The first, and most direct, was to let a component listen for when other entities were added to the current scene. If an entity is of interest, the component can retain a reference and then communicate to that specific entity. A second solution was to set up a modified event-based system using our 'entity-linker' component. With this system an entity can link to a particular 'channel'. The entity will receive any messages broadcast on that channel. Similarly the entity can broadcast its own messages on the channel for other entities to receive. 

 

In addition to these challenges, there is also a general mental shift needed to switch from traditional inheritance oriented design to a component-based model. Thinking about each component as discrete, determining the proper means of interfacing with other components, deciding when to generalize a component or keep it specific, etc. All of these are questions that occur repeatedly as we work on Platypus. These aren't bad questions, just different.

 

We Like It, Now You Try It

In summing up, we are really happy with how Platypus has come together and continue to believe that going the component-based route was the right choice for the engine. If you want to form an opinion for yourself, feel free to check out the engine here on GitHub.


Related Jobs

Square Enix Co., Ltd.
Square Enix Co., Ltd. — Tokyo, Japan
[04.23.14]

Programmers
Treyarch / Activision
Treyarch / Activision — Santa Monica, California, United States
[04.23.14]

Production Coordinator (temporary) - Treyarch
Vicarious Visions / Activision
Vicarious Visions / Activision — Albany, New York, United States
[04.23.14]

Senior Software Engineer-Vicarious Visions
Chukong Technologies
Chukong Technologies — Menlo Park, California, United States
[04.22.14]

Developer Relations Engineer






Comments


Thomas Happ
profile image
I've never used HTML5, but I rather like the component model for games; it lends itself particularly well to building completely new creatures/weapons/etc. from existing building blocks.

Jeremy Helgevold
profile image
Thats what I thought when reading that. Proceduraly generated opponents with abilities and behavior that varies given certain parameters sounds like a fun thing to explore.

Mattias Olsson
profile image
It strikes me as odd of using a system where you have to break rules to do what you want, instead of using a system that works with your methods.

I would recommend researching MDSoC (Multi-Dimensional Separation of Concerns) in how to get ideas for a working system with component-based design. In MDSoC you are freely allowed to structure your data within each concern on each dimension.

I have programmed a unity3d turnbased rts game with MDSoC as the basic guide. Creating three dimensions: System, gameplay, dataclasses. Each dimension is a folder hierarchy.

Every unity3d object is a component which contains one data class from the dataclasses concerns, often one file from there is often one file per systemconcern. Often one file per feature in the gameplay dimension and often no files from the system dimension. The system dimensions files are often static or are singletons to a special component. On initialisation all the files on any given component bind to each other and to the global system files.

In the gameplay dimension the folders hierarchy is done by gameplay features ( such as movement, combat, economy etc etc) where in each such feature folder there might exist inheritance chains to solve different unit-types needs, and often each inheritance chain implement every concern from the system dimension, such as gui and end start turn. The dataclass also implements concerns such as gui, save/load and highlight.

With tools such as partial classes each concern can be totally self contained. If you have a new feature, for example save/load, you simply create a save load folder in each dimension. Here you make partial classes of the classes you want to affect. In javascript this should be easy to get the same effect of with its prototype inheritance model.

Derek Detweiler
profile image
I realize he put it this way, but I'm not sure I would consider what Todd mentioned to really be "breaking rules". In designing specific components, sometimes there is a strong co-dependency between several components, in that they require each other to perform appropriately. Using the Lego brick analogy, these co-dependent components would be the Technic ball-joints compared to more self-contained components being a traditional Lego brick. Their functionality is provided in the way they work together with another component, not just in how they generically connect to create the entity.

Lennard Feddersen
profile image
A few lines of code to show how the ant was implemented would have helped me get a better feel for what you are doing.

Inter entity communication is prone to subtle issues when the entities "party" on each other directly. I'd suggest a messaging system that accumulates messages for end of tick processing to avoid subtle issues that occur when updates happen mid-tick, affecting some entities yet to be processed yet missing other already processed entities of the same type until next tick.


none
 
Comment: