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.
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.
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 with the 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
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
}
}
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
}
},
}
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.
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}),
]
};
By default, all entities will be rendered as a rectangular prism using 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}
]
};
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
]
};
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}
]
})
Once you've created a gma.manager, adding levels is as simple as calling 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.
Once you've stored one or more levels on the manager using storeLevels, you can use loadLevel to load one of them.
For example
var manager = gma.manager();
manager.storeLevels({});
manager.loadLevel()
By default, loadLevel will load the first level that has been stored on the manager and will spawn the 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, twitch is started, and the Game Loop will cause a cycle of animating, removing "killed" entities, and rendering.