GTCS Game Engine:
Tutorial 1: Basic Application Structure

Tutorial 0 <-- Tutorial 1 --> Tutorial 2
Main tutorial guide page


Introduction

In this tutorial, we will look at the basic building blocks and programming structure to build games. We look at the different types of objects we use and their respective roles with games. We will also gain an understanding of the operation of our game loop.

Covered Topics: Object TypesScene ObjectInitializationGame Loop

Demonstrations: Drawing a RenderableRenderable with Motion

Complete source code for all tutorials can be downloaded from here.


Object Types

In the GTCS Game Engine, we are concerned with 4 types of objects. Scene, camera, renderables and game objects. Each object type encapsulate different functionality.

We will look at each element by building a simple game scene to create a simple rectangle on our viewport as shown here.


Scene Object Structure

The scene is where game loop logic will reside. By overriding the engine's Scene class wth the functionality you want, you will have a runloop. By convention, this class will be defined in a file located in the src/MyGame/ path.

The HTML5 engine implements a runloop. When you setup a scene object, you must adhere to a certain structure to make sure the runloop executes as expected. The structure of a scene consists of four parts. Initialization, update, drawing and cleanup. A skeleton of the functions in a scene object are shown in the following code...

function MyGameScene() { };
gEngine.Core.inheritPrototype(MyGameScene, Scene);

MyGameScene.prototype.loadScene = function () { };

MyGameScene.prototype.unloadScene = function () { };

MyGameScene.prototype.initialize = function () { };

MyGameScene.prototype.update = function () { };

MyGameScene.prototype.draw = function () { };
Code snippet 1-1: Scene subclass skeleton

Your class needs to inherit from core Scene object type. This is done by the call to inheritPrototype(). You must make sure that the name of your subclass matches the class you created in Tutorial 0.


Initialization

Constructor

Before any game logic or rendering occurs, initialization occurs in three phases. The constructor gets called first. This is where you declare any instance variables that you intend to use in the game scene (Note: This is not for memory allocation or loading data from files.).

function MyGameScene() {
	this.mCamera = null;
	this.mRenderable = null;
	this.mGameObject = null;
};
gEngine.Core.inheritPrototype(MyGameScene, Scene);
Code snippet 1-2: Scene constructor

The code above declares three instance variables that will be used in our scene. We do not allocate RAM yet. We just declare and make sure that they are set to null.

loadScene()

The loadScene() function is called next. This is where you request any resources to be loaded into RAM. You would instruct the engine to load any data (such as images or audio files). We will look at loading resources in Tutorial 2.

initialization()

The initialization() function is called by the engine after all resources requested in loadScene() are in RAM and usable by your code and is only called once. This is where you will allocate RAM and setup your objects. In this example, we create our remaining core objects with simple values to aide in comprehension.

Camera and Viewport

The Camera object defines the viewport and is setup with 3 parameters. The position, the width and the location/size of the viewport.

this.mCamera = new Camera(vec2.fromValues(50, 40), 100, [0, 0, 500, 400]); this.mCamera.setBackgroundColor([0.8, 0.8, 0.8, 1]);

[Note: The camera height is not provided. The engine infers the height based on the width and the aspect ratio of the viewport.]


Renderable

The Renderable controls the "look" of objects in our game. The basic one we create in the above example renders only a solid rectangle. We set its color to red using RGB + Alpha values. We cannot make interesting games if our renderables are limited to making solid rectangles. In future tutorials, we will look at more advanced renderables that can draw textures, animate and respond to lighting effects. The key take away in this tutorial is that a renderable is just for defining the appearance of the object.

this.mRenderable = new Renderable();
this.mRenderable.setColor([1.0, 0.0, 0.0, 1.0]);

These lines will allocate a new renderable object and set it's look (in this case, color). The parameters for setColor() is a vector with RGB+Alpha values ranging from 0.0 to 1.0.


GameObject

The GameObject is created with a reference to our renderable. We give the GameObject it's size and location in the viewport. Once the renderable is fully configured and incorporated into our GameObject, we will keep the reference in case we need to access it directly to change the appearance. Often, you will subclass GameObject to encapsulate it's renderable upon allocation.

this.mGameObject = new GameObject(this.mRenderable);

The size and position are in WC space with the position being the center of the object. In this example, since our size is 16x16 and position is (30,50), this will set our red rectangle from (22,42) at the lower-left corner to (38,58) at the upper-right corner.

this.mGameObject.getXform().setSize(16, 16);
this.mGameObject.getXform().setPosition(30, 50);

We also set a front direction. This identifies the direction that the game object will move when given a speed value (not to be confused with rotation). We use a vector (1,0) indicating that it is pointing to the right. We set a speed of 0.5. This will allow the game object to modify it's location by 0.5 units horizontally every update cycle.

this.mGameObject.setCurrentFrontDir(vec2.fromValues(1, 0));
this.mGameObject.setSpeed(0.5);

[Note: understanding different coordinate spaces is beyond the scope of these tutorials]

MyGameScene.prototype.initialize = function () {
	this.mCamera = new Camera(
		vec2.fromValues(50, 40),    // position of the camera
		100,                        // camera width
		[0, 0, 500, 400]            // viewport (orgX, orgY, width, height)
	);
	// set the background color of our view to medium grey
	this.mCamera.setBackgroundColor([0.8, 0.8, 0.8, 1.0]);
    
	// create a new renderable object
	this.mRenderable = new Renderable();
	this.mRenderable.setColor([1.0, 0.0, 0.0, 1.0]);
    
	// create a new game object with the new renderable
	this.mGameObject = new GameObject(this.mRenderable);
	this.mGameObject.getXform().setSize(16, 16);
	this.mGameObject.getXform().setPosition(30, 50);
	this.mGameObject.setCurrentFrontDir(vec2.fromValues(1, 0));
	this.mGameObject.setSpeed(0.5);
};
Code snippet 1-3: Initialization function including Renderable and GameObject code

Game Loop

Updating

The update() function is called by the engine 60 times a second. This is where you will check for user interaction (ie: keyboard presses and mouse clicks), check for collisions among GameObjects, update object locations etc. If another process or calculation delays execution, the game engine will compensate for the delay by looking at the current time and executing the update routine multiple times until updates have caught up with current time.

MyGameScene.prototype.update = function () {
	// Check status of our objects and update them
	if(this.mGameObject.getXform().getPosition()[0] > 92) {
		this.mGameObject.setCurrentFrontDir(vec2.fromValues(-1, 0));
	}
	if(this.mGameObject.getXform().getPosition()[0] < 8) {
		this.mGameObject.setCurrentFrontDir(vec2.fromValues(1, 0));
	}
        
	//this.mGameObject.update();
};
Code snippet 1-4: Update

In this example, we want our GameObject to move left and right across our game screen. We have two if statements that determine if we hit the edge. At each point, we change the current "front direction" of the object towards the opposite direction. Note that setting the speed and direction does not change the position. With these parameters set, calling update() on our GameObject will update the position. We have commented this line out for the time being so we can inspect our renderable.

[Note: In a complete game, we would want to be able to end the game. You would trigger the engine to stop the game loop by calling gEngine.GameLoop.stop() within the update() function.]

Drawing

The draw() function is called by the after the update cycle is complete. On an unencumbered system, this should be 60 times a second. If there are delays, multiple updates can occur before the draw routine is called.

MyGameScene.prototype.draw = function () {
	// Clear the screen
	gEngine.Core.clearCanvas([0.8, 0.8, 0.8, 1.0]);
    
	// Activate our camera
	this.mCamera.setupViewProjection();
    
	// Draw our objects
	this.mGameObject.draw(this.mCamera);
};
Code snippet 1-5: Draw

In our draw function, we clear the screen, activate our camera for rendering and draw all of our objects (which is only one at this stage). We send a reference to our camera into the game object which will pull out the information it needs for behavior and send the camera to the enclosed renderable so that it can extract what it needs for drawing. Click here to see the results.

To activate motion, uncomment the last line in the update() function. The rectangle should oscillate left and right across the screen. To view this with motion, click here.

When viewing this in a web browser, you should see the following...

figure 1-1: Renderable

You will also notice that the coloring is darker than you were probably expecting. Our renderable object responds to a "virtual light source". By default, our only light source is ambient lighting and it is very dim so as not to interfere with other light sources you may define. We will look at adjusting ambient lighting in the next tutorial.


Conclusion

We have learned about the structure of the scene object and create a very basic scene with a single renderable.

In tutorial 2, we will look at accepting user input and utilizing game resources such as bitmap images and audio. We will build on the renderable concept and look at new types of renderable objects that support bitmap textures.


Tutorial 0 <-- Tutorial 1 --> Tutorial 2

2/11/2016 - David Watson, Proofread by Adedayo Odesile & Jeb Pavleas