Game Development Community

dev|Pro Game Development Curriculum

Plan for Josh Williams

by Josh Williams · 01/31/2005 (5:25 pm) · 82 comments

In this .plan, I'm taking a first-pass at a technical overview for T2D. I'm hoping there are some crazy fools out there like me who can't seem to get enough details about cool technologies like T2D. So, hopefully somebody will find this (long and boring) .plan interesting (despite it's long and boring nature). (Update: this .plan covers T2D's core classes, read the next .plan to read about it's core systems![/url]

I'm sure this .plan won't answer all your questions about T2D, but it should end up being a nice overview. I promised to do something like this in my last .plan, so here we go!

To start off, for most of us here, all I really need to say about T2D is that it's developed by Melv May. :) For anyone that knows the guy, it is immediately possible to conclude with a high degree of confidence that T2D must, technically speaking, friggin rock. Melv has been working on T2D like a madman, and it is a quality product of outstanding engineering.

All told, T2D represents about 9 months of dedicated, impassioned work on Melv's part, and by us here at GG for the past 6 months or so. I know how much thought and effort has been poured into T2D, because I've been right there for most of the ride. I've already got great memories of late-night chats with Melv where we approached every design decision from a hundred angles, trying to make sure we'd end up with the best 2D game engine out there.

I'm very proud of Torque 2D. I think every day we get closer to achieving our goal for this engine, and by the end of this year, I do expect T2D will be far and away the best 2D game engine around. I love being a part of its creation.

Even at this point, as we push to finalize T2D for its Early Adopter release, the engine already has numerous advantages over other 2D engines. It'll be very exciting to see what the early adopters do with all this power, especially as the year goes on and we add easy to use editors and more core technology.

Okay, if I were reading this .plan right now, I'd be skimming ahead to get to the juicy parts, so let's just have at. :)

Below, you'll find a pretty detailed technical write-up on T2D's core feature set. It's long, and it's dry, so most people will probably just want to skip or skim this one. But for those of you out there like me who love reading this kind of stuff... enjoy!

T2D Technical Overview

Overview
Torque2D is a platform for 2D game development, built on top of the Torque Game Engine. This means T2D gets to leverage Torque's scripting, sound, platform, GUI, and other core systems. T2D implements its own scenegraph-driven, hardware-accelerated 2D rendering and game world systems.

In addition to the systems provided by TGE's core, Torque 2D's custom systems include everything you want in a 2D engine: sprites, tiles, particles, collision, physics, advanced camera capabilities, object mounting, parallax scrolling, rendering layering, object picking, and more. Each system is designed for power, ease of use, performance, and to be as readily customizable and extendable as possible. Scene saving and loading, multiple viewports, debug rendering and easy to visualize performance statistics, along with about 100 pages of tutorial and reference documentation round out the package, with many time-saving editors on the way.

Let's look at the primary classes T2D defines:


Core object fxSceneObject2D
T2D defines a base class from which every other major class is derived, the fxSceneObject2D. fxSceneObject2D provides:
  • Extendible, efficient swept-polygon collision detection
  • Rigid-body physics
  • Unlimited, hierarchical object mounting
  • Assignment to rendering layers
  • Object picking with points, lines, and areas
  • Individual world-limit definition, clamping and collision response
  • Object scaling, rotation, and automated / fixed rotation
  • Object serialization
  • Scriptable interface and callbacks
  • Debug and performance reporting
  • Customizability and extendability for simple creation of custom objects
fxSceneObject2D has no rendering overhead, and since all of the performance-heavy functions (eg collision detection and response) it does implement can easily be disabled, it is a perfect core class on which to build other, more specialized classes. Since all of T2D's primary classes are built on the fxSceneObject2D, every object in T2D inherits the powerful capabilities listed above.
Each of these capabilities and systems will be described in more detail later. First, we'll cover the fxSceneObject2D subclasses.


Sprites fxStaticSprite2D, fxChunkedSprite2D, fxAnimatedSprite2D
T2D has a very impressive sprite system. Sprite rendering in T2D is ultra-fast and sprites, like all T2D objects, can be scaled and rotated in graphics hardware. Sprites are divided into two main kinds: those with complex animation capabilities, and those without.

fxStaticSprite2D
The fxStaticSprite2D is a general-purpose sprite, allowing you to place (and move) renderable shapes in your scene that don't require complex animation sequences. The "static" in the name refers to the animation frames, as opposed to the object's ability to move around in the scene. Static sprites are perfectly free to move about the scene, and their rendering frames can even be changed, but they don't have a powerful animation interface.

fxStaticSprite2D uses an "image map", defined as an fxImageMapDatablock2D, to identify it's graphics frames. More information on image maps can be found below, but the basic idea is that image maps are used to load a sheet of images for use by sprites (and scrollers, tiles, and particles).

fxStaticSprite2D objects can be moved around the scene, and can have full collision, physics, etc. Again, these objects, like all the core objects in T2D, derive from fxSceneObject2D which provides a very powerful base to build from.

Related to the fxStaticSprite2D is the fxChunkedSprite2D. These sprites are very similar to static sprites, but are better for handling very large imagery. In particular fxChunkedSprite2D uses the fxChunkedImageDatablock2D, which is capable of loading imagery from non-power-of-two textures. More information on the fxChunkedImageDatablock2D can be found in the appropriate sub-section below. Ultimately, this interface for loading imagery from non-power-of-two sources will be simplified even further, but for now, T2D makes it easy to load images from any source by using these chunked resource capabilities. The fxChunkedSprite2D is also capable of tiling sprite imagery across its surface, according to parameters you can set.

fxAnimatedSprite2D
The fxAnimatedSprite2D provides very powerful tools for creating, playing, and managing animated sprites. Animated sprites (and animated tiles and particles) rely on animation datablocks and animation controllers in order to play animations. In order to get a grasp of the fxAnimatedSprite2D, we must first examine these systems:

The fxAnimationDatablock2D datablock class can load frames from an image map and define an animation as a chain of frames. The animation datablock can then define the play time of the animation, and set whether the animation cycles, and even whether the animation should start playing with a random frame.

The fxAnimationController2D is a utility class used by fxAnimatedSprite2D (as well as by animated tiles and animated particles) to control and play animations.

The fxAnimationDatablock2D and fxAnimationController2D abstract the process of defining, setting up, playing, and manipulating animations. Since there are multiple kinds of animated objects in T2D, this is very convenient, as each animated class can utilize the same functionality. This encapsulation of behavior is also nice because it allows you to easily define your own custom animated classes by leveraging the functionality provided by the standard animation classes.

Now, with all the animation functionality provided by the animation datablocks and controllers, creating animated sprites is a fairly simple matter. fxAnimatedSprite2D::playAnimation(name) is used to play a particular animation, as defined and controlled by the sprite's animation controller. fxAnimatedSprite2D also defines a callback function, onAnimationEnd(), so you can perform some custom actions when an animation ends.

Note that static sprites have none of the animation overhead incurred by the fxAnimatedSprite2D. Thus, while all sprites could really be animated sprites with no animations defined or played, it was decided to create the specialized static sprite class, just for that added bit of specialization and efficiency. Structuring things this way also makes it easier for people to get a grip on sprites-- making it as simple as possible for people to set-up basic sprites, without worrying about any extra calls or functionality, is a good thing.

That's the overview of sprites in T2D. Sprites are pretty much the core of most any 2D game, so Melv was careful to treat 'em right, and we've all been careful about suggested modifications to these core classes.


Setting basic properties and loading images datablocks, and image maps
Torque2D makes heavy use of datablocks. (If you aren't familiar with Datablocks, I encourage you to read the scripting documentation here on the site). Every object in T2D has a datablock associated with it, which can be used to configure its initial or static properties.

Image maps
Image maps, or the fxImageMapDatablock2D, are some of the most important and most used datablocks in T2D. As described above, image maps can be used to load imagery from a sheet of frames. Image maps essentially read textures and then extract image frames from the texture. These image frames can be extracted in one of three ways: single frame, color-keyed, or celled.

Using single frame extraction will result in an entire texture being loaded as a single frame.

To use color-keyed extraction, the source image must be separated by lines of a particular color-- each image to be extracted must boxed-in by straight lines of this particular color, and the color must not be used anywhere else in the image. Often, people use pure black, pure green, or bright pink for this key color. When in color-keyed extraction mode, the image map reads the upper-left texel on a texture and sets that as the color-key. Note that this is the same system used to define image maps for GUI controls in standard TGE.

Celled extraction means that the source image is split into a regular grid of equally-sized cells, and that each cell should be loaded as a separate image frame. You specify the size of each grid, and the number of grids, and the image map can load any frame from the source texture.

Image maps, again, abstract and encapsulate the process of loading graphics frames from source imagery. This way, multiple objects can extract renderable frames from a source image without having to do the actual loading work themselves. This architecture also means that multiple objects (even of different types) can use the same image map to load their particular animations. This can end up saving texture memory usage, by decreasing the need to define redundant animation frames in separate textures. Once again, this functionality also makes it easy to define your own custom, renderable objects by utilizing the image map's frame loading functionality.

Besides the normal fxImageMapDatablock2D, there is also the fxChunkedImageDatablock2D, as mentioned above. This datablock is similar to the normal image map, but allows for loading from non-power-of-two sources. Again, the interface for handling non-power-of-two source imagery will be simplified soon after the initial Early Adopter release of T2D, but this system provides the baseline functionality needed to allow people to load from irregular sources.

Okay, now we've got some basic ideas about T2D down... we know a little about the high-level features provided to all T2D objects by the fxSceneObject2D, we know about T2D's sprite capabilities and animation system, and we have an understanding of T2D's architecture for loading images.

Next, we'll continue digging into each of the objects provided in T2D, and then we'll go over the major processing systems provided by default in T2D and the core fxSceneObject2D.


Scrolling backgrounds fxScroller2D
T2D provides a really simple way to get scrolling backgrounds in your game. There is a more powerful methodology for backgrounds in T2D, (..tile maps, which are discussed below) but the fxScroller2D provides a very simple, efficient way to use scrolling backgrounds.

fxScroller2D loads its image using the image map interface (and can only have one frame). This image is then scrolled, according to parameters set either in the fxScrollerDatablock2D, or by calling the setScrollMode(mode, dx, dy) method. Mode is a boolean parameter specifying whether the scroller should scroll or remain static, and dx and dy define the scrolling speed, in world units per second, to be used.

Regarding world units, T2D has a nice system for handling coordinates in your game world. Whether working with the game world itself, with background scrollers, tiles, sprites, or anything else, you don't need to worry about the actual pixel size of anything-- T2D does all the translation for you, and you can simply work in world coordinates. This kind of functionality is standard in 3D engines, but (surprisingly) some 2D engines out there don't provide this nice level of abstraction. Scrollers are one area where this consistent coordinate system is very useful.

Again, the main advantage of fxScroller2D objects is that they are very easy to set-up, and very performance-friendly. They can also be used to get parallax-scrolling up and running in no time. By defining multiple scrolling backgrounds, you can easily sort and assign them to different rendering layers (more info on this later), and assign different scrolling speeds. Thus, scrollers in the far background can scroll slowly, while those in the foreground scroll by rapidly. This creates the cool, pseudo-3D "parallax" scrolling effect common in many 2D games, and it's incredibly easy to get going with Torque 2D.


Tiles
I've looked very thoroughly at a lot of 2D engines out there, especially the major, well-known ones, and I am happy to say that T2D is well on it's way to having the most powerful and flexible tile system around. It took us quite a bit of wrestling to figure out the best way to handle tiles, lots of lunch discussions with Pat and Alex here at GG, and many more late night design sessions with Melv, but we finally ended up with an outstanding system. There's still more work to do on tiles, but the core system is in place, and I'm very happy with it. Let's check it out:

One impressive feature of T2D's tiles is their integration with the physics system. Objects can collide with tiles, and these collisions can generate full physics responses (on the objects). Given how powerful T2D's collision and physics system is, this is a very nice, and uniquely powerful, feature of the tiles. It was also a tough one to get in, let alone to make performant. After some long conversations about how to handle the tiles, Melv and I came up with an excellent plan for them, and Melv knocked the implementation out of the park. The tile interaction in T2D is really great (and we're not done yet ;)

Overall, there are three kinds of tiles in T2D: static, animated, and "active". Static and animated tiles are very similar to their sprite counterparts, and they use the same encapsulated sub-objects to manage their imagery and animations. The cool thing to note here is that T2D supports richly animated tiles, should you wish to use them! Not all 2D engines do. :)

Active tiles are a different animal. Active tiles define a skeleton which you can use to create tiles which actively affect the world. One example that's been talked about before is creating turrets as active tiles in your tilemap. This has some efficiency advantages versus creating a tile layer and associating a stand-alone turret object with it. There are lots of creative ways to take advantage of this functionality. We (probably) won't ship the Early Adopter version of T2D with a good example of an active tile, but soon afterward, we should produce some. Eventually, we both expect that there'll be libraries of active tiles out there people can use and customize.

Another neat feature of T2D's tile system is that each tile object can have an associated script which runs once the tile is displayed. Again, this is a cool little feature that allows you to more easily create really dynamic tiled environments.

T2D tilemaps can also be panned, in any direction (with a little bit of set-up work)

Object picking also works for tiles-- you can, for example, determine exactly what tile (if any) currently lies directly beneath a current screen or world-space point.

Those are some of the big features of T2D tiles. Now, here's how the system works in general:

T2D stores tiles, at the highest level, in a tile map-- fxTileMap2D. fxTileMap2D objects create, maintain, and destroy fxTileLayer2D objects, which in turn handle the virtual tile objects. fxTileMap2D can load and save maps from and to disk.

The fxTileLayer2D object is the meat of the tile system. Where the fxTileMap2D class provides some high-level loading and management routines, fxTileLayer2D actually does the dirty tile work. Tiles are simply defined as a grid in the tile layer, and the tile layer can control any individual tile, determining whether the tile is static, animated, or active, setting the tile's script callback, changing the tile, etc.

The tile map can set-up the tile layer's actual dimensions, and how many individual tiles it contains.

The tile layer has some convenient features: for example it has a layer clear, which will remove all the information on the layer's grid. Also, there are fine-grained animation controls on the tile layer, for example, you can force an animated tile to be "unique", which means it will use it's own instance of an animation controller, so as not to be affected by potential changes to a central controller (non-uniquely animated tiles are animated together, and save some memory overhead and cpu overhead, as they all rely on the same instance of an animation controller). Tile layers can also be panned, and can be set-up to for auto-panning at a fixed rate. Tile layers can be wrapped as well-- in fact, you can control wrapping behavior independently along both major axes.

Another important consequence of the tile layer's structure is that individual tiles can be deleted (cleared) and changed at any time. So getting some truly dynamic and active tile maps is easy in T2D, you're not simply confined to static backgrounds and collision imagery.

That's where things stand at the moment. We have even more plans for tiles in T2D, but we'll wait until after the Early Adopter release to go into them in more detail. One thing I will say now though is that we'll have support for non-rectilinear tiles as soon as possible. For now, we just wanted to get the core backbone of the tiling system up and running. We achieved much more than we originally set out to achieve with the tile system, I think. And with this infrastructure in place, adding in new tile types won't be very difficult.

Great. So, there's all this awesome tile support in T2D. But, how do you load tiles? It'd be a royal pain to have to set-up tile maps all by hand in script. Thus, T2D will ship with an FMP loader, meaning you can load tile sets created in the well-known (and cross-platform) Mappy tile editor. Then, you can take advantage of T2D-specific tile functionality via script setup. In the future, we'll either be creating our own tile editor, or extending an existing editor (perhaps Mappy).


Particles
Okay, I'm going fanboy mode here, I can't help it:

Particles are incredible in T2D. In my opinion, T2D has the most impressive real-time particle system in any engine. Once we get a finalized, user-friendly particle editor in, I know T2D owners are going to lose hours and hours of time just creating pretty particle effects. I love this system, and I have to give all props to Melv for coming up with it.

So, how's it work?

There are three layers to the particle system: effects, and emitters, and particles themselves. Effects contain an unlimited (virtually) collection of particle emitters, and control these emitters over time. Particle emitters spew particles in a fine-grain controllable, time-dependent manner. Particles themselves are like very lightweight, efficiently rendered animated sprites as they can utilize animation controllers to change their rendered frame over time.

fxParticleEffect2D
Particle effects are essentially a large collection of specific fields and particle emitter sub-objects which are used to define a particle effect. The effect's fields can be split into two groups: those which change over time, and those which are static.

Fields which change over time are controlled via a time-graph system, meaning that you specify time and key-value pairs for these fields. For each field, the effect will interpolate between the currently adjacent key-values, arriving at the proper values at the specified time.

For example, the quantity_scale is a time-dependent particle effect field. This field, like many effect fields, specifies a value by which to multiply the particle emission quantity specified in the effect's particle emitter objects themselves. Essentially, this provides particle effects the ability to override their sub-object emitters' settings, inducing effect-wide changes in emitters.

In this example, we might specify that we want all emitters that are a part of this effect to begin spewing particles faster and faster after two seconds, peaking at twice their normal rate after two more seconds, and then ramping down to their normal emission rate after another second. To do so, we'd specify time and key-value pairs for this field: (time, key-value) : (2.0, 1.0), (4.0, 2.0), (5.0, 1.0). In script, assume we have a whole particle effect set-up, then applying this change to the effect would work like so:

%exampleEffect.selectGraph("quantity_scale");
%exampleEffect.addDataKey(2.0, 1.0);
%exampleEffect.addDataKey(4.0, 2.0);
%exampleEffect.addDataKey(5.0, 1.0);

This tells the effect that we want it to ramp up all of its particle emitter's particle emission quantities to twice their normal rate between seconds two and four of the effect, and to be back to normal by the fifth second the effect plays.

An example of a non-time-dependent field is the effect's timeRepeat, which is accessed via getTimeRepeat() and setTimeRepeat(scale). This field affects the timescale of all emitters that are a part of the effect.

fxParticleEmitter2D
Emitters are actually very similar to effects, they utilize a similar system of fields, and whereas effects spawn emitters, emitters spawn particles. Emitters define a long list of fields which can be used to control particle emission behavior. These fields are also split into two groups: time-graph controlled, dynamic fields which are interpolated over an unlimited chain of time / key value pairs, and static flags which parameterize the emitter's general behavior.

Examples of dynamic emitter fields include particlelife_base and particlelife_variation. These two fields are used to determine the lifetime of each particle spawned by the emitter. The base component defines the default particle lifetime, while the variation component defines a range [-variation, variation] of deviance from the base value. This variation is randomly distributed, using a standard linear random generator.

Emitters use this base / variation concept for many of their dynamic fields. The particle emission quantity, particle size, particle speed, emission force, and other fields all use this dual base / variation time-graph controlled paradigm. Other fields don't use it, for example, visibility_life is time-graph controlled but has no variance. This field controls the length of time for which each particle is visible.

Now, all this leads to a very powerful, highly flexible particle effect system. But it'd be awfully nasty if you had to control it all via scripting. Luckily, T2D Early Adopter comes with a (very basic!) particle editor. This saves you from ever having to script any particle effects. The Early Adopter particle editor isn't at all the prettiest or most user-friendly tool ever made, but it is fully functional and you can do anything with it that you can in script.

Emitters efficiently handle particle spawning and control, keeping a particle pool handy to minimize memory allocs. Particle rendering is quite efficient as well, though there are still some important optimizations to make after the Early Adopter release.

Emitters also provide a rich interface for querying their current field values, and include debug rendering information.

What's more, particle effects can be saved to disk, for later re-use.

Very cool. And that's not all... like all of the standard objects in T2D, particle effects are derivatives of fxSceneObject2D. That means effects can be manipulated like any other object.. they can be moved, mounted, scaled, assigned to groups and layers, and even have physics interaction!

I don't think even Melv fully realizes how cool this system is. And if he does, then he's way the hell too humble about it. By all rights, he should be out screaming his head off about what a badass he is for creating it. :) In all honesty, I'd pay just for a real-time particle effects system like this. There are particle systems without as much power (let alone being real-time!) as this system out there that people pay pretty big bug bucks for, for use in film, scientific visualization, etc.

Once we have a polished particle editor, I bet all kinds of people will produce dazzling particle effects, and I'm sure we'll all while away hours just sitting around staring at them. Mmm.. shiny.

Note: the T2D reference documentation contains a complete list of every script-accessible field and method for particle effects and emitters, as it does for all objects in T2D.

Further Note: presently, T2D interpolates over time-graphs only linearly, but in the future other common interpolators will be implemented.

Scoop: just a couple weeks ago I was contacted by two experienced engineers who are interested in porting this particle system up to Torque (and TSE). So, no promises, but watch this space for more details. :)


With that, we've covered the basic objects found in Torque 2D. Between the core scene object, sprites, scrollers, tile maps, and particle effects, you have all you need to make every kind of 2D game.

I'm just realizing that this .plan is almost ten full pages long already. If I'm lucky, maybe two or three people out there actually read the whole thing. It's still not done yet, but it'd probably be best to split this technical overview up into two pieces. This .plan covered the core objects in the engine, so watch for Episode II: Attack of the Core Systems tomorrow! (Or very soon afterward, depending on how much sleep I'm willing to deprive myself of tonight). You can see the outline for tomorrow's .plan below. (Update: the next .plan is out :)

Thanks for reading. If you made it straight-through the whole thing, with its utter lack of pictures or funny personal anecdotes or really any redeeming qualities of any sort, hats off to you, friend. You are indeed a hardcore technophile. ... You pervert.

Collision

Physics

Layers and Groups

Mounting

Object picking

World limits

Camera

Scenegraph

Torque integration

C++ source available

Detailed documentation

(continued in the next .plan
Page«First 1 2 3 4 5 Next»
#81
02/09/2005 (7:34 am)
Here's hoping for the next installment this week :)
#82
02/09/2005 (11:02 am)
@Corey: Yes! Hopefully.. :)
Page«First 1 2 3 4 5 Next»