If you are planning to extend or modify the Gamma framework or are, perhaps, simply curious it is desirable to understand the various patterns that were used whilst constructing the framework.
Reading this section, you will learn:
Eveything in Gamma exists under the gma namespace, which has been achieved using RequireJS.
Whether defining a new module with require.def or simply loading dependencies with require, you need to supply a list of dependencies that will be loaded before executing the supplied callback. RequireJS will then pass in all these dependencies into callback function when it loads. When defining a module, this callback function is expected to return the module and is called the Modules function.
require.def(newModule,
[
dependency1,
dependency2
],
function(dependency1, dependency2) {
// Modules function
return the_module;
}
);
Gamma uses the convention that each module has gma/base as the first dependency, then the gma namespace will be the first argument to the module's function. Then, each module will append it's contents straight onto the gma namespace. Therefore only the gma base object will return a module.
For example, gma.character is added to the gma namespace with the following code:
require.def(gma/entities/character,
[ gma/base, // Provides the gma namespace which
gma/entities/moveable, // is passed into the function
gma/utils/collisions // below.
],
function(gma) {
// Add gma.character
gma.character = function(spec) {
// character class goes here
};
}
);
Gamma was designed so that classes behave like building blocks, allowing objects to be created by applying many such "building blocks" to a JavaScript object.
This was achieved using the factory pattern. In this pattern, an object is created by a factory function that accepts an object and simply add more properties/methods to it.
We have designed all our building blocks to "respect" properties/methods already existing on any input object, by only setting such properties and methods if the object doesn't already have such a property. The building blocks ensure that a default set of properties/methods exist on objects, so that they may be "complete".
For example,
var myClass = function(spec) {
var self = spec || {};
// add properties and methods to self
self.y = self.y || 6
self.someFunction = self.someFunction || function() {
return hi there;
};
return self;
};
// Defaults to a new object if one isnt passed in
var myNewObject = myClass();
// Or we can apply the building block with some object
var myOtherNewObject = myClass({x:5});
myOtherNewObject.y; // <= 6
// Or just by calling the function on an existing object
var yetAnotherObject = {y:2};
myClass(yetAnotherObject);
yetAnotherObject.y; // <= 2
This allows the Gamma framework to imitate inheritance -- in the previous example yetAnotherObject inherits from myClass -- but it is possible to create an object that is built using a combination of unrelated blocks.
For example,
var myObject = {};
// There are no building blocks as shape, animateable or
// armed, but for examples sake
shape(myObject);
animateable(myObject);
armed(myObject);
Note
For all these examples to work, the factory must return the object it creates/edits at the bottom
The factory pattern also chosen because it allows our classes to have a closure, which allows us to imitate private variables.
var myClass = function(spec) {
var self = spec || {};
// Anything else that is vard is private
var secret = "Lalala";
// Private variable is only exposed through an accessor
self.someFunction = self.someFunction || function() {
return My secret is + secret;
};
return self;
};
The Gamma framework aims to disconnect the game logic from the visual logic. We have achieved this by making an interface that sits between Gamma and an arbitary rendering engine. This interface is collectively referred to as the Render Helpers. Theoretically we can define rendering helpers for many rendering engines, and perhaps even non-webgl engines. At this point we only have Render Helpers that use GLGE. You can find more about these here.
Gamma was designed to be with two main limitations to keep the code simple
Below is the list of places in the Gamma codebase that makes these assumptions
Gamma uses a very simple tags system to provide the ability to specify particular functionality on entities. This is explained in further detail on this page.