Levels

A level specification is created to specify what is inside a game. This is used to tell the game engine the position, appearance and behaviour of any objects in each level.

Specifying Levels

A level specification is a normal Javascript object with particular properties. A level needs at minimum, a spawn location for the character and a camera. Gamma will provide defaults if these properties are not specified. This means that you can provide an empty object and Gamma will still be able to start a working level.

Note

The advanced topic on Level Parser describes what is provided on the level by default, and how to customise this behaviour.

Adding Spawn points

A spawn point is a location in 2D space with a label attached to it.

Spawn points are commonly used by Gamma to set the position of the character when a level is loaded. To do this, a level must specify a spawn point withthe label main. If no such location is specified, then one is added to the level at [0, 0].

Spawn points are specified as a hash that associates a label to a [x, y] co-ordinate.

var myLevel = {
    spawn : {
        main: [5,30],
        someOtherLocation : [20, 65]
    }
}

Note

As shown in the Initialising Levels section, it is possible to change which spawn point is used to spawn the character when the level is loaded

Customising the camera

To customise the camera, you may specify options under the camera label. All of the options provided by the GLGE Camera are available (look for the the set* functions).

To make an orthographic camera, 50 units from the origin:

var myLevel = {
    camera : {
        locZ : 50,
        type : GLGE.C_ORTHO
    }
}

Adding Lights

You can add lights to your level by specifying them inside a hash under the label light.

var myLevel = {
    light : {
        light1 : {},
        light2 : {},
        light3 : {}
    }
}

You can find all the options you can set by finding all the set* functions over here.

For example,

var myLevel = {

    light : {
        spotlight1 : {
            rotY : 1.54,
            locZ : -50,
            type : GLGE.L_POINT,

            color    : "#fff",
            rotOrder : GLGE.ROT_XZY,

            attenuationLinear    : 0.0,
            attenuationConstant  : 2.0,
            attenuationQuadratic : 0.00
        }
    },
}

Attaching Lights and Camera to the character

When specifying your camera and lights, you may also specify an attached option, which will cause that camera/light to follow some other entity. When you specify attached, you provide an array that contains at least a string specifying the entity to follow. You may then optionally specify x, y and z offsets.

For example,

var myLevel = {
    camera : {
        locZ : -50,
        attached : ['character']
    },

    light : {
        spotlight : {
            attached : ['character', 0, 3]
        }
    }
}

When you don’t specify x or y offsets, they will default to zero. If there is no z offset the z-position of the object will be set to locZ (which defaults to 0). So in the above example, the camera will follow the movement of the character (but 50 units towards the viewer) and the light will always be 3 units above where the character is.

Note

For now, Gamma only allows you to follow the character, but this may change in the future.

Adding Entities

Entities may be specified as a list of Gamma objects:

var myLevel = {
    entities : [
        gma.door({x:0, y:9, width:5, height:6}),
        gma.door({x:15, y:9, width:5, height:6}),
        gma.enemy({x:9, y:9, width:1, height:2}),
        gma.platform({left:-9, right:18, top:9, height:3})
    ]
};

This example creates a platform with an enemy and two doors sitting on it.

Note

Your character object should be attached to the manager, not the level. Therefore the following will break some functionality the manager provides:

var myLevel = {
    entities : [
        gma.character({x:0, y:9, width:5, height:6}),
    ]
};

Templates

By default, all entities will be rendered as a rectangular prism using gma.gma.unitCube. You can change the template used by setting the template property on the entity. Gamma provides 3 different templates for rendering as described in the appearance section. This example will render a gorilla collada file instead of the default unit cube:

var myGorilla = gma.colladaTemplate({
    collada : {
        document : 'gorilla.dae'
    }
});

var myLevel = {
    entities : [
        gma.enemy({x:0, y:9, width:5, height:6, template:myGorilla}),
    ]
};

Gamma also provides another default template, redcube. This will render a red cube instead of a blue cube.

var myLevel = {
    entities : [
        {left:19, right:30, top:9, height:3, template : 'redcube'}
    ]
};

Removing Repetition

Types

Types can be used to remove repetition when defining similar objects. A type is a specification of attributes, which can be associated with an object through it’s type property. For example to create a type shinyDoor that creates a gma.door with a width, height and depth of 4:

var myLevel = {
    types : {
        shinyDoor: ['door', {
            width    : 4,
            depth    : 4,
            height   : 4,
        }]
    }
};

To assign this type to two objects:

var myLevel = {
    entities : [
        {type: 'shinyDoor', x:0, y:9}
        {type: 'shinyDoor', x:15, y:9}
    ],

    //Types same as above
    types : {
        shinyDoor: ['door', {
            width    : 4,
            depth    : 4,
            height   : 4,
        }]
    }
};

By default, specifications will have the default type, which creates a gma.platform, so a platform in our level could be specified as:

entities : [
    {left:-9, right:18, top:9, height:3}
];

You can also override attributes specified in the type. For example:

var myLevel = {
    types : {
        myEnemy : ['enemy', {width:1, height:4}]
    },

    entities : [
        {type:'myEnemy', x:9, y:9, height:2}
        //height is now 2
    ]
};

Replicating objects

Gamma provides the ability to replicate options on a list of objects through a replicateWith property.

ReplicateWith will create an object for each set of attributes in the array passed to it. This object will have these attributes as well as the attributes of the object replicateWith was defined in.

For example:

var myLevel = {
    entities : [
        {width:5, height:5, replicateWith : [
            {left:0, top:5},
            {left:7, top:5},
            {left:12, top:5},
            {left:17, top:5},
            {left:25, top:5}
        ]}
    ]
};

is equivalent to

var myLevel = {
    entities : [
        {width:5, height:5, left:0, top:5},
        {width:5, height:5, left:7, top:5},
        {width:5, height:5, left:12, top:5},
        {width:5, height:5, left:17, top:5},
        {width:5, height:5, left:25, top:5}
    ]
};

You can also replicateWith recursively. For example you could do the following:

var myObject = gma.utils.expandReplicateWith({
    entities : [
        {optionA : 5, optionB : 6, optionC : 7, replicateWith : [
            {optionD : 8, optionE : 10, replicateWith : [
                {optionF : 8, optionA : 5},
                {optionF : 10, optionG : 11}
            ]},
            {optionD : 9, replicateWith : [
                {optionF : 8},
                {optionF : 10}
            ]},
        ]}
    ]
})

Which is equivalent to:

var myObject = gma.utils.expandReplicateWith({
    entities : [
        {optionA : 5, optionB : 6, optionC : 7, replicateWith : [
            {optionD : 8, optionE : 10, optionF : 8, optionA : 5},
            {optionD : 8, optionE : 10, optionF : 10, optionG : 11},
            {optionD : 9, optionF : 8},
            {optionD : 9, optionF : 10}
        ]}
    ]
})

Which is equivalent to:

var myObject = gma.utils.expandReplicateWith({
    entities : [
        {optionB : 6, optionC : 7, optionD : 8, optionE : 10, optionF : 8, optionA : 5},
        {optionA : 5, optionB : 6, optionC : 7, optionD : 8, optionE : 10, optionF : 10, optionG : 11},
        {optionA : 5, optionB : 6, optionC : 7, optionD : 9, optionF : 8},
        {optionA : 5, optionB : 6, optionC : 7, optionD : 9, optionF : 10}
    ]
})

Adding Levels

Once you’ve created a gma.manager, adding levels is as simple as calling gma.manager.storeLevels with one or more level specifications

// We either call storeLevels with one level specification
manager.storeLevels(someSpecification);

// Or we call storeLevels with an array of one or more specifications and it will store them all
manager.storeLevels([levelSpecification1, levelSpecification2, levelSpecification3]);

Note

Storing a level does not load it. Loading levels is explaining in the Initialising Levels section below.

Initialising Levels

Once you’ve stored one or more levels on the manager using gma.manager.storeLevels, you can use gma.manager.loadLevel to load one of them.

For example

var manager = gma.manager();
manager.storeLevels({});
manager.loadLevel()

By default, gma.manager.loadLevel will load the first level that has been stored on the manager and will spawn the gma.manager.character at the spawn point with label main.

However, you can specify which level you wish to load, and at which spawn point.

// Create some level specifications
var level1 = {};
var level2 = {spawn : {other : [0, 9]}};
var level3 = {};

// Store the levels on manager
manager.storeLevels([level1, level2, level3])

// Load the second level
// Note that the levels are zero indexed
manager.loadLevel(1)

// Or we could load the second level, and spawn the character at the spawn point labelled "other"
manager.loadLevel(1, "other")

Note

The list of levels on the manager is zero indexed. This means the first level is at index 0, the second level is at index 1, etc.

Once you’ve loaded a level, gma.manager.twitch is started, and the Game Loop will cause a cycle of animating, removing “killed” entities, and rendering.