melonJS: Anatomy of a Game Object

Game Objects

A game object is an instantiation of some base class which provides some common functionality for the game engine. In melonJS there are two methods which every game object must implement:

update()

This is the method called by the game engine when it is time for the object to update its internal state. This is usually the time for handling things like player input processing, movement, collision detection, animation, etc. Invisible objects (either explicitly made invisible or objects outside of the viewport) are never updated. This method should return boolean true to signal to the game engine that the object is requesting a redraw. Which leads us to the second required method;

draw(context, rect)

This method accepts two arguments; a CanvasContext2d, and a rectangle indicating the area of the context to be redrawn.

The rect is only important if you are doing incremental updates, i.e. you have me.sys.dirtyRegion enabled. Since this feature is not fully implemented, it is not recommended to use, so ignore the rect argument for now. 🙂 [Update 2013-08-29: dirtyRegion has been removed entirely from melonJS as of version 0.9.9.)

The context is where you can do all kinds of magic directly on the canvas using its APIs. Rotate the context, set drawing opacity, set line width, create complex paths, stroke and fill, draw images; everything that the HTML5 canvas API supports can be done at this point. And it will all nicely occur at the proper Z-level, because game objects are sorted.

The Base Classes

Any object (including an empty one) can be used as a base class for game objects. melonJS provides a few different classes that you can use directly or even extend with more functionality. The most popular of these is the me.ObjectEntity class. This class implements methods and properties that are quite useful for platformers, such as doJump() and canBreakTile. These are less useful for other game genres like puzzles and shooters.

The next base classes to consider are me.GUI_Object and the similar (but strangely very different) me.HUD_Object. What’s very special about these classes is that they both enable a special flag to inform the engine of how to interpret the position of the object when drawing (or when interacting with the object through the mouse/touch interface). The property is called floating, and it is a boolean that determines whether the position should be treated in world coordinates (false) or screen coordinates (true). (See the section below on world coordinates vs screen coordinates.)

All of these base classes, for reasons of convenience, inherit from me.Rect; the rectangle class. This is the same class passed to the draw() method in the rect argument. It handles the object’s position (using a position vector; which is an object instantiated from the me.Vector2d class), width, and height. It also has a lot of useful geometry methods for comparing and moving rectangles in 2D space.

World Coordinates vs. Screen Coordinates

“World coordinates” defines the space consumed by a full map in your game. Often, your maps will be far too large to fit entirely inside the viewport (AKA the “screen”). “Screen coordinates” defines the space that is actually visible within the viewport. The distinction becomes apparent when you consider two different types of game object that you might add to the game: An NPC object is probably going to live within world coordinate space, because it can move around within the world, and scrolls with the world as the viewport moves. And a score counter, which is probably going to be anchored to one corner of the screen, and will not scroll around with the map.

So an object using world coordinates will have its position vector interpreted as being relative to the upper left corner of the map (the “world”). And an object using screen coordinates will have its position vector interpreted as being relative to the upper left corner of the screen.

The blue arrows indicate a HUD item (lives counter) that is using screen coordinates, and the red arrows indicate the player object (Master Higgins) that is using world coordinates. The pink outline represents the viewport (the “screen”) and the darkened areas are typically not viewable.

The floating property manages all of the complexity for us; we just set it to true or false, and the engine does the rest.

Writing Your Own Game Objects

As I mentioned earlier, it is possible to use any base class to create a game object. It is sometimes desirable to extend a more heavyweight object like me.ObjectEntity, and sometimes you would rather have more control over what the object is capable of.

One particularly good example is used in the last game demo I built, Mini Sim Hotel. When you touch the screen to scroll the viewport, I have a simple indicator dot that appears where you are touching. This was really awesome for the presentation I gave, where the video was projected, and viewers could see exactly what I was interacting with.

The touch indicator was built with me.ObjectEntity, but I could have just as easily used a lower level object, like the new me.Renderable class. The update method returns true when there is a touch in progress, and the draw method draws a circle using the canvas API. That’s it!

Some less obvious patterns you can use game objects for includes synchronizing melonJS with other libraries, like physics engines. I did this originally with Chipmunk-js, but this use of game objects has mostly been supplanted with the plugin API (which deserves its very own blog post!) These kinds of objects only need to implement the update method, and always return false (nothing to draw).

Another example is the me.Tween module. This module creates private game objects to keep tweened animations synchronized with the engine. This practice could be extended to keyframe animations, cool-down timers, and a load of other nifty utilities.

Next Steps

melonJS is still fairly young, and actively developed. But the simplicity (only two methods required for game objects) is here to stay; one of the goals of the engine is to remain very lightweight. If a feature requires additional states for a game object apart from update phase and draw phase, that feature will be scaled down or entirely redesigned until it fits neatly inside the melonJS paradigm.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s