Skip to content
erisco edited this page Oct 7, 2012 · 2 revisions

Classes

All classes should follow this basic format. Also, each class should be saved to its own file. In the case of the class MyClassName, it would be saved to the file MyClassName.js.

function MyClassName(arg1, arg2) {
    // instance initialization here
}

MyClassName.prototype = {

  // we define fields in the prototype so its clear
  // they are used. however, all read/write access
  // must be done via get and set methods to ensure
  // obvious errors occur from a typo or wrong reference.
  // use GFW_Property unless you need custom get and set
  // methods.
  __myField: null,

  myMethod1: function (arg1) {
    // definition for myMethod1
  },

  myMethod2: function (arg2) {
    // definition for myMethod2
  },

}

// the follow must occur after the prototype definition
// above.

// define auto-implemented properties here
GFW_Property(MyClassName, "MyProperty");

// then define mixins
GFW_mixin(MyClassName, SomeMixin);

Braces for Statement Blocks

For statement blocks, we are using same-line braces.

if (...) {
    stmt;
}

while (...) {
    stmt;
}

function foo() {
    stmt;
}

Indentation

Two spaces. No tabs.

Reading and Writing Object Value Members

Note: value members refer to members who's intended type is to be a non-function. A string, object reference, or integer would all be examples of value members.

JavaScript objects can have new members defined at any time. Worse, you can read any member from an object and, if it has no value assigned, it returns undefined. While this feature is powerful in some cases, it is very problematic for others. For example, simple mistakes such as typos (ex: you meant obj.position but you typed obj.positoin) can result in mysterious errors far down the line. Alternatively, you may think that obj has the member position, but because of a logical error earlier on, you actually have a reference to an object other than you were expecting; this also will cause mysterious errors.

To abate this problem, all object value members must be read by a get method and wrote by a set method. This is standard data encapsulation practice. If you only need a default getter and setter, you may use GFW_Property. In JavaScript, calling a non-existent function is an error, so typos will be caught at the exact line number and incorrect references will be caught closer to their source.

Garbage and Object Lifetime

Games are a real time application and have a fixed amount of time to respond. Typical refresh rates for games are 30Hz or 60Hz, which means the game can take up to a maximum of 33ms or 16ms respectively to produce a frame for display. Missing this deadline will cause the animation to skip and the input controls to feel sluggish; we need reasonable confidence that, given a certain grade of hardware, the game will produce frames quickly enough.

Managed languages, such as JavaScript, use a garbage collector. While this generally allows a programmer to forgo memory management, in real time applications this is no longer the case. This is because that when the garbage collector runs, it must freeze all activity for an unpredictable amount of time to free up unused memory. A single garbage collection will usually cause the game to miss one frame, but in worst cases can cause the game to miss multiple frames. This means we have to minimize the number of garbage collections that occur; if the garbage collector must run every couple seconds, the game play will be obnoxious if not impossible.

To minimize garbage collections we simply have to produce less garbage. In a perfect world, we will produce zero garbage and the garbage collector will never run. However, practically speaking, most of the serious problems can be fixed by eliminating object creations (anywhere the 'new' keyword is used) that happen on every or nearly every game loop. Keep this in mind when developing your code as it might be a strong influence.

The framework currently has GFW_RingBuffer which maintains a fixed-sized cyclic array of objects. Other object pooling methods can be added as needs arise.

For more information about garbage collection, Google is your friend.

Access Levels

JavaScript does not have a notion of public, protected, and private as seen in other languages, thought it is possible to hide data by using closures. We're preferring to use name prefixes to indicate the intended access level. It is the responsibility of the programmer to not use an object member in a way that violates it's indicated access level.

  • Private: prefix with double underscore (ex: __name).
  • Protected: prefix with single underscore (ex: _name).
  • Public: leave name unchanged (ex: name).