Milady – Ludum Dare 48

Ludum Dare is a regular accelerated game development event. Participants develop games from scratch in 48hours, based on a theme suggested by community..

I was asked to developped a game in Haxe technology in such a way for a job application.

Play Milady at http://terra-ex-machina.com/blog/milady-ludum-dare-48/

Posted in Uncategorized | Tagged , , | Leave a comment

Audio Processing with Unity

Some Xp I made around Audio Processing and Terrain generation with Unity3D

Posted in Uncategorized | Tagged , , | Leave a comment

Scene Graffity (making an HTML5 Game Engine part 2)

This article is the second of an upcoming series called « Making an HTML5 Game Engine ». The series intends to give fundation information to create an evolutive game engine in javascript for HTML5 that can be used to build different game experiences. This means the articles will cover architecture concept of various subsystems that are typically implemented in industry.

Sources will be based on prototype framework as a plus-value for collection management.

Previous articleOf Games and Loops

Scene Graph: root of graphics

A scene is a composition of graphical objects (« I see a house, next to a car, behind a tree »). Objects are composed by sub-objects (i.e. « a car has four wheels »). Scene graphs are a data structures aiming to represente and arrange spatial entities each others. There are many different kind of scene graph, we will see a general implementation. But you must be aware on what you need and do not need, to make the right choise on some projects (You may be surprised to learn where all your cpu frame are going).

A scene graph can be qualified as a collection of node in a tree structure :

  • The root of the tree is the scene ;
  • A node can have a rendering asset ;
  • A node can have children ;
  • A node, except the root, has one parent ;
  • A node is linked to a geometrical transformation (combination of rotation, scaling, translation and alignement) with the effect of a parent applied to all its child nodes.

Transformation

As we see, each node is associated to a transform, enabling computation to convert coordinates to pixel positions on the screen. In fact, applying a series of transforms is chaining matrices : the various transformation functions of HTML5 just apply your specified values to the current transformation matrix.

Thus, if you rotate by 90 degrees and draw something, then all what you draw after that will be rotated by 90 degrees. This does not mean that you need to keep track of all your transformations to undo them back to a previous state. That’s where the HTML5 matrix stack functions come in, you can ‘save’ and ‘load’ previous matrices. A matrix stack is useful for constructing hierarchical models, in which complicated objects are constructed from simpler ones such in a Scene Graph.

On saving the matrix, we are memorising a local space coordinate of an object, the we can modify the matrix for sub-objects, then restoring the matrix to go back to the parent coordinate system.

For example, let’s take a foot at (x :10, y :10, angle :75) on the global space, the foot have a toe at (x: 3, y :-1, angle :0) on its local space, and so on for the other toe :

The pseudo-code would be:

  • Save Matrix
    • Transform at (x :10, y :10, angle :75)
    • Draw Plantar Surface
    • Save Matrix
      • Transform (x :3, y :-1, angle :0)
      • Draw Toe 1
    • Restore Matrix
    • [ idem toe 2]
    • [idem  toe 3]
    • [idem  toe 4]
    • [idem  toe 5]
  • Restore Matrix

Scene graph Implementation

Describe a node would tend to such a json format.

{name:"a graphic node",
      transform : {x:0, y:0, // position, 0 if not specified
                   z:0,  // layer, 0 if not specified
                   sx:1, sy:1, // scaling, 1 if not specified
                   ax:0, ay:0,  // alignment, 0 if not specified
                                //  = origin of the model + transform point
                   angle: 0}, // rotation, 0 if not specified
      renderer:{
                   img:"a picture reference",
                   clipping:{x:0, y:0, //0 if not specified
                             w: 32, h:32}, // full size if not specified
                   size :{w:64,  h :64}, // image size if not specified
                },
       children :[
       ]
}

Processing a scene Graph in HTML5

Ok ! That’s cool but actually this structure do nothing for our game and HTML5 Canvas. Well, need to improve the game engine.

1. Unzip the source on your disk

You may notice that I change some directories from the previous practive. It is done to cleary seperate of what would be the generic engine from what would be the elements of a specific game experience.

Source:

  • /index.html : a simple html file including required js file, asset files and declaring the game canvas
  • /assets/scene.js : a json file describing the hierarchy of a scene
  • /assets/img/*: image assets used by the engine
  • /TerraIncognita2D/GameEngine.js : declaration of the main game application class
  • /TerraIncognita2D/core/GraphicEngine.js : declaration of a graphic engine class
  • /TerraIncognita2D/core/ControllerEngine.js : declaration of the component managing user events
  • /TerraIncognita2D/util/EasyLife.js : a set of short function of mine simplifying game development
  • /TerraIncognita2D/util/EventBus.js : event bus lib, used to broadcast messages such as « RESOURCES LOADED »
  • /lib/prototype-1.6.0.2.js : prototype lib

2. Open index.html file

You can see a new block on this file.

<sprites>
   <sprite id="BACKGROUND"           src="assets/img/BACKGROUND.jpg" />
   <sprite id="BABEL_TOWER"          src="assets/img/GX_CONCRET_BIG_BABEL.png" />
   <sprite id="MEDIEVAL_TOWER"       src="assets/img/GX_CONCRET_BIG_TOWER.png" />
   <sprite id="ROCK"                 src="assets/img/GX_CONCRET_BIG_ROCK.png" />
   <sprite id="MEDIEVAL_TENT"        src="assets/img/GX_CONCRET_SMALL_KNIGHT_TENT.png" />
   <sprite id="BARREL"               src="assets/img/GX_CONCRET_SMALL_RHUM.png" />
   <sprite id="TOTEM"                src="assets/img/GX_CONCRET_SMALL_TOTEM.png" />
   <sprite id="CATAPULT"             src="assets/img/GX_CAR_FANTASY.png" />
</sprites>

They will be used as reference to load images later.

3. Open GameManager.js file

You can see some evolution in this file:

  • Now « init » function is registering a listener to the graphic engine to ensure when images are loaded (thank to EventBus lib) .
init:function( canvas_name, level_def )
{
  this.canvas = document.getElementById( canvas_name ) ;
  this.level_def = level_def ;

  new GraphicEngine() ;
  new InputManager() ;
  EventBus.addEventListener( GraphicEngine.singleton.EVENT_SPRITES_LOADED,
                               GameManager.singleton.loadGame, 
                               GameManager.singleton ) ;

  GraphicEngine.singleton.init( GameManager.singleton.canvas ) ;// attach rendering context
  InputManager.singleton.init( GameManager.singleton.canvas ) ;// attach input listening 
}
  • A loadGame function is now declared. It chains different loading process, and  finaly run the game when everything is ready.
loadGame:function()
{
  switch( GameManager.singleton.loading_step )
  {
    case "INIT":
    case "LOAD_SPRITES":
          GraphicEngine.singleton.loadSprites( "sprite" ) ;
          GameManager.singleton.loading_step = "LOAD_SCENE" ;
          break ; // break as this process is async
    case "LOAD_SCENE":
          GraphicEngine.singleton.createRootMdl( GameManager.singleton.level_def ) ;      
          GameManager.singleton.loading_step = "RUN" ;
          // no break as this process is sync
    case "RUN":
          GameManager.singleton.run() ;
          GameManager.singleton.loading_step = "COMPLETE" ;
   }
}
  • You can notice that all the scene graph is loaded by :
GraphicEngine.singleton.createRootMdl( GameManager.singleton.level_def ) ;

Ok… Now, we have the entry point to the Graphic Engine, it is time to watch its mechanic.

4. Open GraphicEngine.js file

Loading the assets

An important thing before rendering any scene is to load the resources mandatory to render that scene. HTML <image> tag load resources but display them as element of a web page. We need a way to load contents by javacript.

It could be with another json file or just by loading when the resource requirement was detected. Instead, let’s create a home-made tag called <sprite> as we see in index.html file. By a javascript process, we are able to parse the DOM tree to recover and load all necessary sprites.

pending_sprite_loading_req:0,
loadSprites:function( html_id )
{
  GraphicEngine.singleton.sprite_lib_by_id = new Hash() ;
  GraphicEngine.singleton.pending_sprite_loading_req = 0 ;

  var res = document.getElementsByTagName( html_id );
  var listOfAssetReq = new Array() ;
  for( var i = 0 ; i < res.length ; i++ )
  {
  //////////////////////////////////////////////////////////////////
  // Check Error Cases
    var _textAsMeta = res[i] ;
    if( _textAsMeta.id == "" )
       throw new Error( "LOAD_ASSETS(" +i+ "): Encounter "+ category + " without ID" ) ;
    if( _textAsMeta.attributes == null )
       throw new Error( "LOAD_ASSETS(" +i+ "): Encounter "+ category + " without settings" ) ;
    if( _textAsMeta.attributes.getNamedItem("src") == null )
       throw new Error( "LOAD_ASSETS(" +i+ "): Encounter "+ category + " without image indexing" ) ;
   ////////////////////////////////////////////////////                             
    listOfAssetReq.push( {_id:_textAsMeta.id, _file:_textAsMeta.attributes.getNamedItem("src").value} ) ;
  }

  GraphicEngine.singleton.nbImgAssets = listOfAssetReq.length ;
  for( var i = 0 ; i <listOfAssetReq.size() ; i++ )
  {
   /////////////////////////////////////
   // No Req in the loop to enable loading only of all element are well-specified
   GraphicEngine.singleton.loadSprite( listOfAssetReq[ i ]._id, listOfAssetReq[ i ]._file ) ;
  }
}

 

The process is splitted into 2  blocks :

  • DOM parsing : getting the list of file to load, and – more important – the number of  file to load ;
  • Request on burst : sending in a row all request to get the files.

A counter is used to ensure if all image requests were all-performed (completed or failed): If pending_sprite_loading_req is equal to 0, it means that the loading procedure is over.

loadSprite:function( id, file )
{
  var _self = GraphicEngine.singleton ;
  var v_image = new Image(); 

  v_image.onload = function()
                      {
                         _self.handleSpriteLoaded( id, v_image, file );
                      }
  v_image.onerror = function()
                      {
                           alert( "LOAD_ASSETS Error on id" ) ;
                           GraphicEngine.singleton.pending_sprite_loading_req-- ;
                      }

   GraphicEngine.singleton.pending_sprite_loading_req++ ;
   v_image.src = file ;
}
handleSpriteLoaded:function( id, image, file )
{
  GraphicEngine.singleton.sprite_lib_by_id.set( id, image ) ;
  GraphicEngine.singleton.pending_sprite_loading_req-- ;
  if( GraphicEngine.singleton.pending_sprite_loading_req == 0 )
  { // notitfy event that all textures are loaded
     EventBus.dispatch( GraphicEngine.singleton.EVENT_SPRITES_LOADED, GraphicEngine.singleton ) ;
  }
}

At each asset loaded, the Graphic Engine register it in a hashtable. It will be used as asset dictionary.

GraphicEngine.singleton.sprite_lib_by_id.set( id, image ) ;

When al image are loaded, an event is broadcasted (EVENT_SPRITES_LOADED), which will be read by GameManager. Then, the GameManager runs a new iteration of loadGame, but at « LOAD_SCENE » step.

EventBus.dispatch( GraphicEngine.singleton.EVENT_SPRITES_LOADED, GraphicEngine.singleton ) ;

Loading the scene

We have seen that each node of a scene is represented by a model, for instance (extract from scene.js) :

{
  name:"cata3",
    transform:
      {
         x:20, y:260, z:0,
         ax:32, ay:32,
         angle:0
      },
    renderer:
      {
         img:"CATAPULT",
         size:{w:64, h:32}
      }
}

It is quite simple for human-reading and quite simple to create tools to generate such a format, but nothing in it would render a scene!

We must upgrade the Graphic Engine to:

  • create a memory model for all of them from such descriptions ;
  • manage all of them ;
  • display all of them.

The first need is to have materials to handle. In the case, materials will be possible by creating models. Have a look at the basic model creation. The result would be a node without any rendering and setted at the origin transform.

createEmptyMdl:function( name )
{
  var a_transform = {  x:0,        y:0, z:0,
                       ax:0,  ay:0,
                       angle:0,
                       sx:1,  sy:1

                    } ;
   name = unNil( name, "#NONAME" ) ;
   return {
          name:name,
          fullname:name,
          parent:null,
          transform:a_transform,
          renderer:null,
          children:[],
          z_update_req:false,
          highestDepth:0,
          deepestDepth:0
     } ;
}

We can see that the memory model has some difference with the model description. That’s due to the memory model must manage runtime states.

A second function to create graphical model exists : createMdl. Considering a descriptor it will instantiate a memory graphic model of a node. If children are declared, this function will create children by recursive call. Each recursive result (a child node) will be registered to its parent by addChild function.

createMdl:function( model_descriptor )
{
  var new_mdl = GraphicEngine.singleton.createEmptyMdl( model_descriptor.name ) ;
  if( isNil( model_descriptor) )
     return new_mdl ;
  ///////////////////////////////////////////
  // Deep copy of potentially dyn elements from model_descriptor to avoid unexpected data share
  /////////////////////////////////////////
  // Renderer generation
  if( !isNil( model_descriptor.renderer ) )
  {
    var raw_data = GraphicEngine.singleton.sprite_lib_by_id.get( model_descriptor.renderer.img ) ;
    if( isNil( raw_data ) )
    {// gen an error img
      raw_data = GraphicEngine.singleton.debug_error_renderer(  model_descriptor.renderer ) ;
    }

    new_mdl.renderer = {
                img_id:model_descriptor.renderer.img,
                img_data:raw_data,
                size:{w:raw_data.width,h:raw_data.height},
                clipping:{x:0,y:0, w:raw_data.width, h:raw_data.height}
            } ;
    if( !isNil( model_descriptor.renderer.size ))
    {
      if( !isNil( model_descriptor.renderer.size.w ))
        new_mdl.renderer.size.w = model_descriptor.renderer.size.w ;
      if( !isNil( model_descriptor.renderer.size.h ))
        new_mdl.renderer.size.h = model_descriptor.renderer.size.h ;
    }

    if( !isNil( model_descriptor.renderer.clipping ))
    {
      if( !isNil( model_descriptor.renderer.clipping.x ))
        new_mdl.renderer.clipping.x = model_descriptor.renderer.clipping.x ;
      if( !isNil( model_descriptor.renderer.size.y ))
        new_mdl.renderer.clipping.y = model_descriptor.renderer.clipping.y ;
      if( !isNil( model_descriptor.renderer.clipping.w ))
        new_mdl.renderer.clipping.w = model_descriptor.renderer.clipping.w ;
      if( !isNil( model_descriptor.renderer.size.h ))
        new_mdl.renderer.clipping.h = model_descriptor.renderer.clipping.h ;
    }
  }
  /////////////////////////////////////////
  // Children loop generation
  if( !isNil( model_descriptor.children ) )
  {
    for( var i = 0 ; i < model_descriptor.children.size() ; i++ )
    {
      var curr_child = model_descriptor.children[i] ;
      var _x = 0 ;
      var _y = 0 ;
      var _z = 0 ;
      var _ax = 0 ;
      var _ay = 0 ;
      var _sx = 1 ;
      var _sy = 1 ;
      var _angle = 0 ;

      if( !isNil( curr_child.transform ) )
      {
        _x = unNil( curr_child.transform.x, 0 ) ;
        _y = unNil( curr_child.transform.y, 0 ) ;
        _z = unNil( curr_child.transform.z, new_mdl.highestDepth ) ;
        _ax = unNil( curr_child.transform.ax, 0 ) ;
        _ay = unNil( curr_child.transform.ay, 0 ) ;
        _sx = unNil( curr_child.transform.sx, 1 ) ;
        _sy = unNil( curr_child.transform.sy, 1 ) ;
        _angle = unNil( curr_child.transform.angle, 0 ) ;
      }
      // generate a child name if none specified
      curr_child.name = unNil( curr_child.name, new_mdl.name + "@"+i ) ;
      var child_mdl = GraphicEngine.singleton.addChild( new_mdl
                           ,GraphicEngine.singleton.createMdl( curr_child )
                           ,{x: _x, y: _y, z: _z,
                             ax: _ax, ay: _ay,
                             sx:_sx, sy:_sy,
                             angle: _angle
                            }) ;
    }

  }
  return new_mdl ;
}

AddChild applies a transform to the model and create the parent-to-child child-to-parent links : this function creates the tree !

addChild:function( parent, child, transform )
{
  if( parent == child )
    throw new Error( "AddChild Error: an mdl can't be as its own parent" ) ;
  if( isNil( parent ) )
    throw new Error( "AddChild Error: parent is null" ) ;
  if( isNil( child ) )
    throw new Error( "AddChild Error: child is null" ) ;
  ///////////////////////////////////////////
  // Deep copy of potentially dyn elements from model_descriptor to avoid unexpected data share
  child.transform.x = transform.x ;
  child.transform.y = transform.y ;
  child.transform.z = transform.z ;
  child.transform.ax = transform.ax ;
  child.transform.ay = transform.ay ;
  child.transform.angle = transform.angle ;
  child.transform.sx = transform.sx ;
  child.transform.sy = transform.sy ;
  ///////////////////////////////////////////
  parent.children.push( child ) ;
  child.parent = parent ;

  this.changeDepth( child, transform.z ) ;

  return child ;
}

Have a look on the z management (changeDepth call). If the z of the child is in the bound of the current highest and deepest depth, it means a new z-ordering must be sorted. It will be done when displaying the model.

changeDepth:function( mdl, depth )
{
  var extrem = false ;
  var parent = mdl.parent ;
  mdl.transform.z = depth ;

  if( parent.highestDepth <= mdl.transform.z )
  {
    parent.highestDepth = mdl.transform.z+1 ;
    extrem = true ;
  }
  if( parent.deepestDepth >= mdl.transform.z )
  {
    parent.deepestDepth = mdl.transform.z-1 ;
    extrem = true ;
  }
  if( extrem == true )
    parent.z_update_req = true ;// potentially a new z-order => ask computation at next display
}

Now! We have the model and the tree structure. Let’s have a look to the display function (called by GameManager at each frame) just asks for the display of the root graphical model.

display:function( dt )
{
  this.context.clearRect( 0 ,0 , this.canvas.width , this.canvas.height ) ;

  if( !isNil( this.scene ) )
  {
    this.displayGfxMdl( this.scene, dt ) ;
  }
  if( this.DEBUG != null )this.debug_display() ;
}

displayGfxMdl staff is to :

  • check if the z-order of children must be sorted or not) ;
  • save the matrix context of the parent system ;
  • apply transform operations of the model ;
  • display recursively all z-negative children ;
  • display the current model renderer ;
  • display recursively all z-positive children ;
  • restore the matrix context to get back to the parent coordinate system.
displayGfxMdl:function( mdl, dt )
{
  /////////////////////////////////
  // is the Z order deprecated and need an update?
  if( mdl.z_update_req )
  {
    mdl.children.sort( function sort_function( mdl_a, mdl_b )
           {
               var a = mdl_a.transform.z ;
               var b = mdl_b.transform.z ;
               return (a - b) ;
           }) ;
    mdl.z_update_req = false ;
  }

  var ctx = this.context ;
  ctx.save() ;
    ctx.translate( mdl.transform.x , mdl.transform.y ) ;
    ctx.rotate( -EF_Deg2Rad* mdl.transform.angle ) ;// ANTI-CLOCKWISE rot
    ctx.scale( mdl.transform.sx, mdl.transform.sy ) ;
    ctx.translate( -mdl.transform.ax , -mdl.transform.ay ) ;
    ////////////////////
    // display negative z children before the renderer
    var curr_child = 0 ;
    for( var i = curr_child; i < mdl.children.size() && mdl.children[i].transform.z < 0 ; i++,curr_child++ )
    {
      this.displayGfxMdl( mdl.children[i], dt ) ;
    }
    ///////////////////////
    // display the renderer (as z = 0 )
    if( !isNil( mdl.renderer ) )// assume .renderer <> null --> ..img <>null, ..size<>null, ..<>clipping<>null
    {
        ctx.drawImage( mdl.renderer.img_data,
                       // clipping part
                       mdl.renderer.clipping.x, mdl.renderer.clipping.y,
                       mdl.renderer.clipping.w, mdl.renderer.clipping.h, 
                       // destination = 0, 0 as the transform argument already do the translation
                       0, 0, 
                       // destination size
                       mdl.renderer.size.w, mdl.renderer.size.h ) ;

        if( this.DEBUG_DISPLAY )
            this.debug_box(0, 0, mdl.renderer.size.w, mdl.renderer.size.h, 'white' ) ;
    }
    ////////////////////////
    // display positive z children  after the renderer
    for( var i = curr_child ; i < mdl.children.size(); i++ )
    {
      this.displayGfxMdl( mdl.children[i], dt ) ;
    }
    if( this.DEBUG_DISPLAY )
    {
      this.debug_origin( mdl.transform.ax , mdl.transform.ay, 'white' ) ;
    }
  ctx.restore() ;
}

5. Executing the script

Now we are good with a minimal GraphicEngine. But, before going deeper on it (optimisation, new features…), the next article will focus on bringing activity and interactivity within the scene.

Previous article: Of Games and Loops

 

Posted in Canvas, HTML5, Javascript, Video Games | Tagged , , , , , | Leave a comment

This article is the first of an upcoming series called « Making an HTML5 Game Engine ». The series intends to give fundation information to create an evolutive game engine in javascript for HTML5 that can be used to build different game experiences. This means the articles will cover architecture concept of various subsystems that are typically implemented in industry.

Sources will be based on prototype framework as a plus-value for collection management.

next article: Scene Graffity

GameLoop: the heart beat of games

In software environment, the service are, in majority of uses, static. It waits for user or entries then respond to them and do nothing without it («I click on the button, then the application will run my request »).

In a computer science point of view, video games can be qualified as realtime interactive simulations. Meaning the state of the environment (game world) is fully dynamic and highly-versatile. Even without any user interactions, the content changes continualy (i.e. : « an ennemy is walking at me and shooting me even – if I don’t press any buttons – »).

That’s a key conceptual difference compared to most traditional software programs. That means a video game software must be able to use CPU during all the simulation. The mechanism behind this is called « game loop » : a core infinity loop in the game application, which check user entries, steps the simulation and draw the scene of the simulation on each cycle. Game Loops can be implemented in a number of ways – but at their core, they are based on this basic concept.

GameLoop

The number of cycle a game loop perfom per seconds is called « fps rate » (Frames Per Second). 30fps means 30 gameloop cycles per second, meaning an update granularity of 1/30 sec per simulation step. Many underlying processes, such as physic simulation and network processing, run at different or inconsistent frequencies.

FPS affect the experience in two ways: low FPS does not give the illusion of motion effectively and affects the user’s capacity to interact with the game, while FPS that vary substantially from one second to the next depending on computational load produce uneven, “choppy” movement or animation. So that’s important that the game locks its fps rate at lower but more constant levels to give consistently smooth motion.

Coding a gameloop in HTML5

Now, it’s time to practice the theory in a Canvas. Canvas element is part of HTML5 and allows for dynamic, scriptable rendering of 2D shapes and bitmap images. It is a low level, procedural model that updates a bitmap and does not have a built-in scene graph.

For this article, only the GameEngine.js file is important, as this file is declaring the gameloop process.

1. Unzip the source on your disk
Source: Download Gameloop.zip

  • /index.html : a simple html file including required js file and declaring the game canvas
  • /GameEngine.js : declaration of the main game application class
  • /core/GraphicEngine.js : declaration of a graphic engine class limited to a simple debug mode display
  • /core/ControllerEngine.js : declaration of the component managing user events
  • /util/EasyLife.js : a set of short function of mine simplifying game development
  • /lib/prototype-1.6.0.2.js : prototype lib

2. Open GameEngine.js file

This javascript file is quite simple, you can see a start function initiating the GameEngine creation and initialization, which will create the GraphicEngine and the ControllerManager services. As GameManager, GraphicEngine and ControllerManager are service-oriented, we can access them by singleton refs.

The gameloop is coded in game_loop function

game_loop:function()
////////////////////////////
// Game loop steping the game simulation at the inv_fps attribute value
{
	var _self = GameManager.singleton ;
	var clock = new Date() ;

	var start_of_frame_time = clock.getTime();

	///////////////////////////////////
	InputManager.singleton.processEntry( _self.inv_fps ) ;
	_self.update( _self.inv_fps );
	GraphicEngine.singleton.display( _self.inv_fps ) ;
	///////////////////////////////////

	clock = new Date() ;
	var end_of_frame_time = clock.getTime();
	var dt = ((end_of_frame_time - start_of_frame_time)/1000);// Used time for frame execution

	_self.frame_cpu = dt ;
	_self.next_frame = EL_clamp( _self.inv_fps-dt, 0, _self.inv_fps ) ;// clamp in case of lag

	setTimeout( _self.game_loop, _self.next_frame );		
}

As described in the first part of the article, at each frame, the game engine:

      1. reads the user inputs ;
      2. update the game world ;
      3. display the scene.
InputManager.singleton.processEntry( _self.inv_fps ) ;
_self.update( _self.inv_fps );
GraphicEngine.singleton.display( _self.inv_fps ) ;

The most interesting part is the piece of code managing a clock. In a naive approach, saying executing the gameloop with a fix inv_fps rate would be suffisant such as:

setTimeout( _self.game_loop, 1/30 );

But it means the internal processes of gameloop would be obmitted. For instance, if « frame 1″ costs 15ms for the processing, its next frame (« frame 2″) would be executed 1/30ms + 15ms (48.33 ms).if « frame 2″ costs 6ms for the processing, its next frame (« frame 3″) would be executed 1/30ms + 6 ms (36ms). As we said, it is important that the game locks its fps rate at constant levels to give consistently smooth motion.
*0___*1____*2____*3____*4___*5
[-]xxx[--]xxx[--]xxx[---]xxx[-]xxx[-]xxx

That’s why we must execute the next gameloop frame at a timeout deducted of the cpu-time consumed by the current frame.
*0__*1__*2__*3__*4__*5
[-]xx[--]x[--]x[---][-]xx[-]xx

clock = new Date() ;
var end_of_frame_time = clock.getTime();
var dt = ((end_of_frame_time - start_of_frame_time)/1000);// Used time for frame execution

_self.frame_cpu = dt ;
_self.next_frame = EL_clamp( _self.inv_fps-dt, 0, _self.inv_fps ) ;// clamp in case of lag

setTimeout( _self.game_loop, _self.next_frame );

setinterval function can be an easier solution as it tries to ensure the function it is running executes as close as possible to its scheduled times (interval clock is triggered a certain amount of time after the previous interval fire).

But, if an interval fires while JavaScript is already busy doing something (such as ending a frame), the interval is remembered, and happens as soon as the previous handler finishes and returns control to the browser. The browser will eat 100% CPU trying to service it, and may become less responsive at the browser UI (mouse and keyboard caption).

3. Executing the script

Even it is not a sexy graphical rendering, you can see the necessary perpetual process to execute video games : the GameLoop.

  • delta time: the cpu time allocated to a frame execution
  • cpu frame: the cpu time consumed by the frame execution
  • free frame: the remaining cpu time allocated for frame execution

next article: Scene Graffity

Posted on by Godio | Leave a comment

Godio’s Journey at http://learningwebgl.com

Learning WebGL: « Best. Résumé. Ever. Godio’s Journey is Steeven Plu’s, and he’s done it as an HTML5/WebGL platformer! »

Posted in Uncategorized | Tagged , , | Leave a comment

Making a HTML5 game in a nutshell

Dears,

I am preparing a set of « step by step » tutorials describing how to implement your own HTML5 game. Then, I will focus tutorials on WebGL for games…

Posted in Uncategorized | Tagged , , , , | Leave a comment

Terra Ex Machina is online

Posted in Uncategorized | Tagged | Leave a comment