Game Application Model Overview
I have always been a fond of a good framework which are easy to use and easy to understand by just taking a glance of it's framework overview, where you can already take a good grasp of how the framework logic flow goes, hopefully I can also bring that to JS/TS Z-GDK framework. now to kick things off, here's an early overview wherein I have layout the game application model overview using the Z-GDK framework.
Creating a new game project
In creating an HTML5 application/game there's two file type that needs to be included in the project the HMLT file which holds the Canvas element and the JavaScript/TypeScript file which contains the application main entry point and a class application/game.
A simple way to create a new application/game using the Z-GDK framework is to open up the empty project which contains a code templates that derives from Z-GDK framework, it has an application main entry point and class application/game templates ready to run and test a game logic routine,
Now let's take a look at the main HTML file and see what it look's like:
The HTML source file used by Empty Project Template:
|
<!DOCTYPE html>
<html>
<head>
<!-- ZGDK Framework -->
<script>
//
var __LIBPATH = "../../LIB/"; document.write("<script type='text/javascript' src='" + __LIBPATH + "ZGDK.js'><\/scr" + "ipt>");
//
</script>
<!-- ZGDK Components -->
<script>
// Includes component device and mouse only for this empty project
Z.GDK.Includes( "Device" ,__LIBPATH );
Z.GDK.Includes( "Mouse" ,__LIBPATH );
// Load app source
Z.GDK.LoadSource("Empty.js");
// Run on completed
Z.GDK.OnCompleteRun("__MAIN_BeginRun()");
</script>
<!-- Document styling -->
<title>TS/JS-ZGDK : Empty project</title>
<link rel="stylesheet" href="../../RES/mycss.css" />
</head>
<body onbeforeunload ="__MAIN_EndRun();" >
<!-- TEXT UPS / FPS -->
<div>
<font
id ="UpsFpsTextID"
size ="3"
face ="arial"
color ="yellow" >0
</font>
</div>
<!-- CANVAS -->
<div>
<canvas
width ="800"
height ="600"
id ="Canvas" >
</canvas>
</div>
</body>
</html>
|
Loading the Z-GDK library:
The first script tag declares a global variable identifiers named __LIBPATH where it assign the library directory path relative to the main HMLT file; and then loads the ZGDK.JS library script file.
Loading Z-GDK Components:
The seconds script tag is the interesting part where it can select what Z-GDK Component to be included in the application, because this library is huge and contains many JavaScript/TypeScript files, "It's no brainer to load everything from a library when the application only needs a few features"; it's like [ #include "filemane" ] in C++ or [ Imports/Using statement ] in VB/C# in .NET
Rather than loading the whole library, select only the components needed by the application by issuing Z.GDK.Includes( componentName, libPath ); as the example above it only includes the "Device" and "Mouse" component. The library have many component to be included in the application such as "Keyboard", "Touch", "Gamepad", "Audio", "GUI", "Screen2D", "Physics2d", "TileMap", "Screen3D", "Physics3d", "Network", "File" and "Dbf". which will be tackle one by one on my futue post.
Loading the Application/Game source file:
To load the application JavaScript source files, issuing Z.GDK.LoadSource( JsSourceFile ); assures it will be loaded first before running the application.
Finally running the Application/Game:
The
Z.GDK.OnCompleteRun( mainEntryFunctionName ); is responsible to run the application, when everything( components and source file ) loaded successfully it runs the main function from the main entry point in the application source file. Ala JQuery document.ready().
From here let's take look at Application/Game Source file and see what it looks like:
The TypeScript source file used by Empty Project Template:
| //=========================================================
//
// P R O G R A M I D
//
//---------------------------------------------------------
// Author : DEXTER Z (2016)
// File : Empty.ts
// Remarks : TS/JS Z-GDK : Empty project template
//=========================================================
//=========================================================
//
// M A I N E N T R Y
//
//---------------------------------------------------------
var __APP:Apps.Game = null;
//
var __MAIN_BeginRun = function() { __APP = new Apps.Game("__MAIN_Update" ); }
var __MAIN_Update = function(p) { __APP.Update(p); }
var __MAIN_EndRun = function() { __APP.EndRun(); __APP = null; }
//=========================================================
//
// M O D U L E
//
//---------------------------------------------------------
module Apps {
//=====================================================
//
// C L A S S
//
//-----------------------------------------------------
export class Game extends Z.Device {
//=================================================
//
// F I E L D S
//
//-------------------------------------------------
private _UpsFpsDomText:HTMLTextAreElement = null;
//=================================================
//
// C O N S T R U C T O R
//
//-------------------------------------------------
/**
* Game class constructor
*/
constructor( pMainUpdate:string ) {
// Create and initialize base device engine.
super( pMainUpdate, "Canvas", Z.Core.ProcessType.TimeOut, 60 );
// Let the game begin!
this.BeginRun();
}//End Constructor
//=================================================
//
// M E T H O D S
//
//-------------------------------------------------
/**
* Begin running the game or application.
*--------------------------------------------------
*/
public BeginRun() {
// DOM Text element for displaying UPS and FPS.
this._UpsFpsDomText = <HTMLTextAreaElement>document.getElementById("UpsTpsTextID");
// Entering base device on running state.
super.OnBeginRun();
}//EndMethod BeginRun
/**
* Update routine.
*--------------------------------------------------
*/
public Update(p) {
// Entering base device on begin/end update state.
if ( super.OnBeginUpdate(p) )
{
this.GameLogic(); // Run your game logic
this.Draw(); // Render draw on screen
}
super.OnEndUpdate(p);
}//EndMethod Update
/**
* Game logic routine
*--------------------------------------------------
*/
public GameLogic() {
// Game application logic code here,
}//EndMethod GameLogic
/**
* Render/Draw routine
*--------------------------------------------------
*/
public Draw() {
// Update DOM text UPS / FPS.
this._UpsFpsDomText.textContent = "UPS:"+this.Environment.UPS+" | FPS:"+this.Environment.FPS;
// Entering base device on draw state.
super.OnDraw();
}//EndMethod Draw
/**
* End running the game
*--------------------------------------------------
*/
public EndRun() {
// Entering base device on end running state.
super.OnEndRun();
}//EndMethod EndRun
}//EndClass Game
}//EndModule Apps
/* End of file */
|
The application logic flow
The application logic flow is simple after the Main Entry Point created the application it begins running the game by calling BeginRun method, the application Update and Draw method will be called by the device automagically, until the application EndRun is called to terminate the application.
Application methods:
BeginRun
Update
Draw
EndRun
The Main entry point
Any C# developers who has created a Winform project in .NET are familiar with "The main entry point for the application" where the application calls the form to run. In Z-GDK the Main Entry Point contains a global functions that called from HTML to run the application; as shown in HMLT source file above, it contains Z.GDK.OnCompleteRun("__MAIN_BeginRun()"); yep just like in JQuery $( document ).ready(function() to run the application when all JavaScript file needed in the application are loaded and completed.
Begin Running the Game
When the HMLT called __Main_BeginRun global function, it creates the application and call the application BeginRun method and automagically calls the application Update and calls and Draw multiples times a second until the EndRun is called by the application. The BeginRun methods is also a good place to initialize your game entities members.
The Game Loop
The application Update method is responsible for handling game logic flow, normally this is called by the device more frequently than the Draw methods method base on the process type use when creating the device which I will tackle on my next post; Process type game loop selection..
this._DEVICE = new Z.Device( pMainUpdate, "Canvas", Z.Core.ProcessType.TimeOut, 60 );
Drawing on Screen
The application Draw method is responsible for informing the game application that a screen refresh has been occurred or repainted. Draw method is a good place to count how many frames per second has been drawn. The *DEVICE.Environment.FPS can be called to display the actual frames per second of the game performed and *DEVICE.Environment.UPS displays the number of updates per second.
The rendering device depends on many factors which includes the total quantity of graphic content needed to be processed on each frame and of course the capabilities of the hardware, but still, the maximum target frames per second can be specified to the framework in device instance creation.
this._DEVICE = new Z.Device( pMainUpdate, "Canvas", Z.Core.ProcessType.TimeOut, 60 );
Ending or Quitting the Game
I’ll be a good citizen by cleaning up mess I put into someone’s computer, calling the device OnEndRun will end running the device gracefully and terminate all device-defined tasks associated with freeing, releasing and resetting framework's related resources. But on some other cases, like for example; if the user closes the web browser without ending the game or exiting the application normally; it’s a good practice to make sure that the game and device will also shutdown gracefully when this case occurs, a simple trick to do this is to call the main entry point __MAIN_EndRun global function from the HTMLT body onbeforeunload as shown below.
<body onbeforeunload ="__MAIN_EndRun();"
The CSS source file used by Empty Project Template:
1
2
3
4
5
| body
{
text-align: center;
background-color: rgb(0,0,0);
}
|
The empty project templates use a simple CSS style with text alignment centered and with black background.