Advanced
Simple game engine
This is an example of a simple game engine (using the Graphic rendering engine module from the previous example):
<!DOCTYPE html>
<html>
<head>
<!-- This file belongs to a CrossBrowdy.com example, made by Joan Alba Maldonado. Creative Commons Attribution 4.0 International License. -->
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<link rel="canonical" href="https://crossbrowdy.com/examples/advanced/simple_game_engine/try" />
<title>Advanced: Simple game engine - Example</title>
<!-- Loads the needed CSS files: -->
<link rel="stylesheet" type="text/css" href="main.css" />
<!-- Loads FlashCanvas (Flash emulation) before CrossBrowdy. Needed also to use ExplorerCanvas (VML emulation) without problems: -->
<!-- Note: it is recommended to download CrossBrowdy instead of hotlinking the online version. This is just for the example! -->
<script src="https://crossbrowdy.com/CrossBrowdy/CrossBase/audiovisual/image/canvas/FlashCanvas/pro/bin/flashcanvas.js" type="text/javascript" language="javascript"></script><!-- FlashCanvas/ExplorerCanvas do not support lazy load. -->
<!-- Loads CrossBrowdy.js (main file): -->
<!-- Note: it is recommended to download CrossBrowdy instead of hotlinking the online version. This is just for the example! -->
<script src="https://crossbrowdy.com/CrossBrowdy/CrossBrowdy.js" type="text/javascript" language="javascript"></script><!-- "type" and "language" parameters for legacy clients. -->
<!-- Loads the other needed script files: -->
<script src="main.js" type="text/javascript" language="javascript"></script>
</head>
<body>
<span id="controls">
<button onClick="gameLoopStartStop();">Stops/starts game loop</button><br />
<button onClick="getGameData();">Gets game data</button><br />
<button onClick="getGameData(true);">Gets game data (stringified)</button>
</span>
<canvas id="my_canvas">if you read this, canvas is not working</canvas><!-- Some emulation methods will require the canvas element created in HTML (not dynamically by JavaScript). -->
<canvas id="my_canvas_buffer">if you read this, canvas is not working</canvas><!-- Some emulation methods will require the canvas element created in HTML (not dynamically by JavaScript). -->
<br />
<!-- The "CB_console" element will be used automatically in the case that the client does not support console: -->
<div id="CB_console" style="display:none; visibility:hidden; overflow:scroll;">
<span style="font-weight:bold;">Console:</span><br />
</div>
<div id="crossbrowdy_info"><a href="https://crossbrowdy.com/examples/advanced/simple_game_engine" target="_blank">CrossBrowdy.com example</a></div>
</body>
</html>
/* This file belongs to a CrossBrowdy.com example, made by Joan Alba Maldonado. Creative Commons Attribution 4.0 International License. */
body { background-color:#aaddee; word-wrap:break-word; }
#crossbrowdy_info { position:fixed; bottom:2px; right:2px; }
#crossbrowdy_info a { color:#00aadd; }
#crossbrowdy_info a:hover { color:#0033aa; }
#CB_console { width:460px; height:100px; background-color:#aaaaaa; color:#ddddff; }
span { color:#aa0000; }
#my_canvas { position:absolute; left:0px; top:0px; }
#my_canvas_buffer { position:absolute; left:0px; top:0px; visibility:hidden; display:none; }
#controls { position:absolute; right:10px; top:10px; z-index:99; }
/* This file belongs to a CrossBrowdy.com example, made by Joan Alba Maldonado. Creative Commons Attribution 4.0 International License. */
//Defines the needed properties:
CB_GEM.REM = CB_GEM.REM || null; //It will store the CB_REM object (Graphic Rendering Engine Module object).
CB_GEM.REM_renderGraphicScene_data = null; //It will store the "data" parameter when calling the 'CB_GEM.REM#renderGraphicScene' method internally.
CB_GEM.REM_renderGraphicScene_useBuffer = null; //It will store the "useBuffer" parameter when calling the 'CB_GEM.REM#renderGraphicScene' method internally.
CB_GEM.graphicSpritesSceneObject = null; //It will store the CB_GraphicSpritesScene object.
CB_GEM.CB_CanvasObject = null; //It will store the CB_Canvas element (the main canvas and the one for the buffer can be internally-alternated automatically if desired).
CB_GEM.CB_CanvasObjectContext = null; //It will store the context of the CB_Canvas element.
CB_GEM.CB_CanvasObjectBuffer = null; //It will store the CB_Canvas element used as the buffer (the main canvas and the one for the buffer can be internally-alternated automatically if desired).
CB_GEM.CB_CanvasObjectBufferContext = null; //It will store the context of the CB_Canvas element used as the buffer.
//Sets the desired options:
CB_GEM.options = CB_GEM.options || {};
CB_GEM.options.LOOP_REFRESH_RATE = CB_GEM.options.LOOP_REFRESH_RATE || 16; //A refresh rate of 16 is about 60 FPS (Frames Per Second) when the cycles per loop is set to 1.
CB_GEM.options.RENDERING_CYCLES_PER_LOOP = CB_GEM.options.RENDERING_CYCLES_PER_LOOP || 1; //The number of rendering cycles per loop. It will affect the FPS.
CB_GEM.options.FPS_SPRITE_DATA = //The 'data' object used by the 'CB_GraphicSprites.SPRITE_OBJECT' object to display the FPS:
CB_GEM.options.FPS_SPRITE_DATA ||
{
fontSize: "12px",
fontFamily: "courier",
style: "#aa5522",
fontStyle: "normal",
fontVariant: "normal",
fontWeight: "bold"
};
CB_GEM.options.canvasId = CB_GEM.options.canvasId || "my_canvas";
CB_GEM.options.canvasBufferId = CB_GEM.options.canvasBufferId || "my_canvas_buffer";
CB_GEM.options.contextMenuDisable = CB_GEM.options.contextMenuDisable === true || CB_GEM.options.contextMenuDisable === false ? CB_GEM.options.contextMenuDisable : true; //Disables the context menu (when pressing mouse's right button) by default.
CB_GEM.options.overwriteViewPort = CB_GEM.options.overwriteViewPort === true || CB_GEM.options.overwriteViewPort === false ? CB_GEM.options.overwriteViewPort : true; //Overwrites the view port ('viewport' meta-tag) by default.
//Sets some options:
var CB_OPTIONS = CB_OPTIONS || { CrossBrowdy: {} };
CB_OPTIONS.CrossBrowdy = CB_OPTIONS.CrossBrowdy || {};
CB_OPTIONS.CrossBrowdy.CB_console_ALLOW_ALERTS = false; //It will not show alerts in the browsers that doesn't have console.
//If desired, sets the needed options to force emulation:
if (CB_GEM.options.CANVAS_FORCED_EMULATION_METHOD) //Forces an emulation mode which can be 'SILVERLIGHT', 'FLASH', 'DHTML' or 'VML' (testing purposes). Use null or undefined to disable it.
{
CB_OPTIONS.CrossBase = CB_OPTIONS.CrossBase || {};
CB_OPTIONS.CrossBase.CB_Canvas_PREFERRED_EMULATION_METHODS = [ CB_GEM.options.CANVAS_FORCED_EMULATION_METHOD ];
if (CB_GEM.options.CANVAS_FORCED_EMULATION_METHOD === "SILVERLIGHT") { CB_OPTIONS.CrossBase.SLCANVAS_LOAD = true; }
else if (CB_GEM.options.CANVAS_FORCED_EMULATION_METHOD === "FLASH") { CB_OPTIONS.CrossBase.FLASHCANVAS_LOAD = true; } //Note: Flash emulation will not work if native canvas is supported.
else if (CB_GEM.options.CANVAS_FORCED_EMULATION_METHOD === "DHTML") { CB_OPTIONS.CrossBase.CANBOX_LOAD = true; }
else if (CB_GEM.options.CANVAS_FORCED_EMULATION_METHOD === "VML") { CB_OPTIONS.CrossBase.EXCANVAS_LOAD = CB_OPTIONS.CrossBase.CANVAS_TEXT_LOAD = true; }
}
//Main initialization function (internal usage only, it will be called automatically when the module loads and gets ready):
CB_GEM._init = function()
{
//If we want to, tries to keeps the screen awake and prevents it from turning off (must be executed through a user-driven event as onClick, etc.):
if (!CB_GEM.options.allowScreenSleep)
{
var keepAwakeEventExecuted = false;
var keepAwakeEvent = function()
{
if (!keepAwakeEventExecuted)
{
keepAwakeEventExecuted = true;
CB_Screen.keepAwake(function() { CB_console("[CB_GEM] Keep awake set successfully!"); }, function() { CB_console("[CB_GEM] Keep awake could not be set successfully!"); });
CB_Events.remove(document, "click", keepAwakeEvent, true);
CB_Events.remove(document, "touchstart", keepAwakeEvent, true);
}
};
CB_Events.add(document, "click", keepAwakeEvent, true, true, true);
CB_Events.add(document, "touchstart", keepAwakeEvent, true, true, true);
}
};
//Sets the desired options (not given ones will keep their current value):
CB_GEM.setOptions = function(optionsObject)
{
return CB_GEM.options = CB_combineArraysOrObjects
(
CB_GEM.options,
{
LOOP_REFRESH_RATE: 16, //A refresh rate of 16 is about 60 FPS (Frames Per Second) when the cycles per loop is set to 1. Default: 16.
RENDERING_CYCLES_PER_LOOP: 1, //The number of rendering cycles per loop. It will affect the FPS. Default: 1.
CANVAS_FORCED_EMULATION_METHOD: undefined, //Forces a canvas emulation mode which can be 'SILVERLIGHT', 'FLASH', 'DHTML' or 'VML' (testing purposes). Use null or undefined to disable it. Default: undefined.
canvasId: "my_canvas", //Identifier for the canvas element. Default: 'my_canvas'.
canvasBufferId: "my_canvas_buffer" //Identifier for the buffer canvas element. Default: 'my_canvas_buffer'.
}
);
}
//This function will be called when CrossBrowdy is ready:
CB_GEM.begin = function(onStart, onError, avoidLoopStart)
{
//If desired, overwrites the view port ('viewport' meta-tag):
if (CB_GEM.options.overwriteViewPort)
{
CB_console("[CB_GEM] Overwring/creating 'viewport' meta-tag...");
//Changes the viewport:
CB_Screen.setViewport
(
"device-width", //'width'. Optional.
"device-height", //'height'. Optional.
false, //'userScalable'. Optional.
"1.0", //'initialScale'. Optional.
"1.0", //'minimumScale'. Optional.
"1.0", //'maximumScale'. Optional.
"no" //'shrinkToFit'. Optional.
);
}
//Function to execute when a canvas is created:
var canvasLoaded = 0;
var onLoadCanvas = function()
{
if (CB_GEM.DEBUG_MESSAGES) { CB_console("[CB_GEM] Canvas '" + this.getId() + "' loaded! Mode used: " + this.getMode()); }
canvasLoaded++;
//Gets the "context" object to start working with the canvas:
var canvasContext = this.getContext();
if (!canvasContext)
{
CB_console("[CB_GEM] ERROR: canvas context could not be obtained! Drawing cannot be performed.");
if (typeof(onError) === "function") { onError.call(CB_GEM, "No canvas context found"); }
return;
}
//Prevents canvas dragging and default touch actions:
this.get().style.draggable = false;
this.get().style.touchAction = "none";
//Stores the canvas in the 'canvases' object:
canvases[this.getId()] = this;
//If both canvas (normal and buffer) have been created, proceeds with the rendering:
if (canvasLoaded >= 2)
{
//If desired, disables the context menu for both canvases:
if (CB_GEM.options.contextMenuDisable)
{
CB_console("[CB_GEM] Disabling context menu for different items...");
CB_Elements.contextMenuDisable(); //Affects 'document' (whole document).
CB_Elements.contextMenuDisable(canvases[CB_GEM.options.canvasId].get());
CB_Elements.contextMenuDisable(canvases[CB_GEM.options.canvasBufferId].get());
}
//Disables some undesired effects/behaviour:
if (document.body && document.body.style)
{
document.body.style.zoom = 1; //Disables zoom under some circumstances for some web clients.
document.body.style.touchAction = document.body.style.msTouchAction = "none"; //Prevents default touch actions for some web clients.
}
//Stores both canvases and their contexts:
CB_GEM.CB_CanvasObject = canvases[CB_GEM.options.canvasId];
CB_GEM.CB_CanvasObjectContext = CB_GEM.CB_CanvasObject.getContext();
CB_GEM.CB_CanvasObjectBuffer = canvases[CB_GEM.options.canvasBufferId];
CB_GEM.CB_CanvasObjectBufferContext = CB_GEM.CB_CanvasObjectBuffer.getContext();
//When the screen changes its size or its orientation, both canvases will be re-adapted:
var onResizeOrChangeOrientationTimeout = null;
var onResizeOrChangeOrientation = function()
{
clearTimeout(onResizeOrChangeOrientationTimeout);
onResizeOrChangeOrientationTimeout = setTimeout(CB_GEM.resizeCanvasesToScreenSize, 100); //NOTE: needs a delay as some clients on iOS update the screen size information in two or more steps (last step is the correct value).
};
CB_Screen.onResize(onResizeOrChangeOrientation);
//Resizes the canvases (Firefox Android fix):
onResizeOrChangeOrientation();
//Clears both canvas:
canvases[CB_GEM.options.canvasId].clear();
canvases[CB_GEM.options.canvasBufferId].clear();
//Disables anti-aliasing to avoid problems with adjacent sprites:
canvases[CB_GEM.options.canvasId].disableAntiAliasing();
canvases[CB_GEM.options.canvasBufferId].disableAntiAliasing();
//Creates the sprites groups:
CB_GEM.graphicSpritesSceneObject = CB_GEM._createSpritesGroups();
//Caches all needed images (performance purposes) and starts rendering sprites groups when all are loaded:
CB_GEM.REM = new CB_REM();
CB_GEM.REM.cacheImages
(
CB_GEM.graphicSpritesSceneObject, //CB_GraphicSpritesSceneObject.
undefined, //reload.
function(imagesLoaded) //onLoad.
{
//Sets the current time as the start time to start counting the FPS (erased each second automatically):
CB_GEM.REM._startTimeFPS = CB_Device.getTiming();
//Gets the 'CB_GraphicSprites.SPRITES_OBJECT' object used to display the FPS counter:
var FPSSprites = CB_GEM.graphicSpritesSceneObject.getById("fps_group").getById("fps");
//Calls the 'onStart' callback (if any):
if (typeof(onStart) === "function") { onStart.call(CB_GEM, CB_GEM.graphicSpritesSceneObject, canvases[CB_GEM.options.canvasId], canvases[CB_GEM.options.canvasBufferId], FPSSprites); }
//Show the FPS (Frames Per Second) every time there is a new value:
CB_GEM.REM.onUpdatedFPS(function(FPS) { FPSSprites.src = "FPS: " + FPS; });
//Creates the empty callbacks if they do not exist:
if (typeof(CB_GEM.onLoopStart) !== "function") { CB_GEM.onLoopStart = function() {}; }
if (typeof(CB_GEM.onLoopEnd) !== "function") { CB_GEM.onLoopEnd = function() {}; }
//If we do not want to avoid starting the game loop, starts it:
if (!avoidLoopStart) { CB_GEM.loopStart(); }
}
);
}
};
//Creates the canvases:
var canvases = {};
canvases[CB_GEM.options.canvasId] = new CB_Canvas
(
CB_GEM.options.canvasId, //canvasId. Unique required parameter.
"2d", //contextType. NOTE: some emulation methods only support "2d". Default: "2d".
CB_Screen.getWindowWidth(), //canvasWidth. Use 'CB_Screen.getWindowWidth()' for complete width. Default: CB_Canvas.WIDTH_DEFAULT.
CB_Screen.getWindowHeight(), //canvasHeight. Use 'CB_Screen.getWindowHeight()' for complete height. Default: CB_Canvas.HEIGHT_DEFAULT.
onLoadCanvas, //onLoad.
function(error) { CB_console("[CB_GEM] Canvas object problem! Error: " + error); if (typeof(onError) === "function") { onError.call(CB_GEM, error); } }, //onError.
undefined, undefined, !!CB_GEM.options.CANVAS_FORCED_EMULATION_METHOD, !!CB_GEM.options.CANVAS_FORCED_EMULATION_METHOD //Forces emulation method.
);
canvases[CB_GEM.options.canvasBufferId] = new CB_Canvas
(
CB_GEM.options.canvasBufferId, //canvasId. Unique required parameter.
"2d", //contextType. NOTE: some emulation methods only support "2d". Default: "2d".
CB_Screen.getWindowWidth(), //canvasWidth. Use 'CB_Screen.getWindowWidth()' for complete width. Default: CB_Canvas.WIDTH_DEFAULT.
CB_Screen.getWindowHeight(), //canvasHeight. Use 'CB_Screen.getWindowHeight()' for complete height. Default: CB_Canvas.HEIGHT_DEFAULT.
onLoadCanvas, //onLoad.
function(error) { CB_console("[CB_GEM] Canvas object problem! Error: " + error); if (typeof(onError) === "function") { onError.call(CB_GEM, error); } }, //onError.
undefined, undefined, !!CB_GEM.options.CANVAS_FORCED_EMULATION_METHOD, !!CB_GEM.options.CANVAS_FORCED_EMULATION_METHOD //Forces emulation method.
);
}
//Resizes both canvases (main and buffer one) to adapt them to the screen size:
CB_GEM.resizeCanvasesToScreenSize = function(avoidCallingOnResize, addedPixels)
{
addedPixels = addedPixels || 0;
//Resizes the canvas:
CB_GEM.CB_CanvasObject.setWidth(CB_Screen.getWindowWidth() + addedPixels);
CB_GEM.CB_CanvasObject.setHeight(CB_Screen.getWindowHeight());
CB_GEM.CB_CanvasObject.clear();
CB_GEM.CB_CanvasObject.disableAntiAliasing();
//Resizes the buffer canvas:
CB_GEM.CB_CanvasObjectBuffer.setWidth(CB_Screen.getWindowWidth() + addedPixels);
CB_GEM.CB_CanvasObjectBuffer.setHeight(CB_Screen.getWindowHeight());
CB_GEM.CB_CanvasObjectBuffer.clear();
CB_GEM.CB_CanvasObjectBuffer.disableAntiAliasing();
//Calls the 'onResize' event set, if any:
if (!avoidCallingOnResize && typeof(CB_GEM.onResize) === "function")
{
CB_GEM.onResize.call(CB_GEM, CB_GEM.graphicSpritesSceneObject, CB_GEM.REM_renderGraphicScene_data, CB_GEM.CB_CanvasObject, CB_GEM.CB_CanvasObjectBuffer);
}
}
//Creates the sprites groups:
CB_GEM._createSpritesGroups = function()
{
//Sanitizes sprites group data:
CB_GEM.spritesGroupsData = CB_GEM.spritesGroupsData || { id: "my_sprites_groups_1", srcWidth: 40, srcHeight: 40, data: { skipAfter: null, duration: null, timeResetAndEnableAfter: null, loop: true, clearPreviousFirst: false } };
CB_GEM.spritesGroupsData.spritesGroups = CB_GEM.spritesGroupsData.spritesGroups || [];
//Adds the sprites group to show the FPS (Frames Per Second):
CB_GEM.spritesGroupsData.spritesGroups[CB_GEM.spritesGroupsData.spritesGroups.length] =
//'fps_group' ('CB_GraphicSprites.SPRITES_OBJECT' object). Some missing or non-valid properties will will be inherited from the parent ('CB_GraphicSpritesScene.SPRITES_GROUPS_OBJECT' object):
{
id: "fps_group",
srcType: CB_GraphicSprites.SRC_TYPES.TEXT,
zIndex: Number.MAX_SAFE_INTEGER || 999999999999,
sprites:
[
//'fps' ('CB_GraphicSprites.SPRITE_OBJECT' object). Some missing or non-valid properties will be inherited from the sprites group:
{
id: "fps",
src: "FPS: Calculating...",
left: 0,
top: 0,
data: CB_GEM.options.FPS_SPRITE_DATA
}
]
};
//Creates the graphic sprites object:
return new CB_GraphicSpritesScene(CB_GEM.spritesGroupsData);
}
//Processes the sprites groups:
CB_GEM._processSpritesGroups_timer = null;
CB_GEM._processSpritesGroups = function(expectedCallingTime) //The "expectedCallingTime" parameter is received from the callback used in the 'CB_symmetricCall' function (first time will be zero). Also passed to the callbacks.
{
if (CB_GEM.stopped) { return; }
for (var x = 0; x < CB_GEM.options.RENDERING_CYCLES_PER_LOOP; x++)
{
//Executes the 'onLoopStart' callback (if any):
var skipRendering = CB_GEM.onLoopStart.call(CB_GEM, CB_GEM.graphicSpritesSceneObject, CB_GEM.REM_renderGraphicScene_data, expectedCallingTime);
if (skipRendering !== false)
{
//Renders the scene:
CB_GEM.REM.renderGraphicScene
(
CB_GEM.graphicSpritesSceneObject, //graphicSpritesSceneObject. Mandatory. The 'CB_GraphicSpritesScene' object to render.
CB_GEM.REM_renderGraphicScene_data, //data.
CB_GEM.REM_renderGraphicScene_useBuffer, //useBuffer. Optional. Default: false. Defines whether to use canvas buffer.
true //alternateBuffer. Optional. Default: false. Defines whether to alternate visibility between canvas or not (if not, it will copy the buffer canvas content to the visible canvas always).
);
//Executes the 'onLoopEnd' callback (if any):
CB_GEM.onLoopEnd.call(CB_GEM, CB_GEM.graphicSpritesSceneObject, CB_GEM.REM_renderGraphicScene_data, expectedCallingTime);
}
}
//Calls itself again:
CB_GEM._processSpritesGroups_timer = CB_symmetricCall //Note: we could also use 'requestAnimationFrame'.
(
function(expectedCallingTime) { CB_GEM._processSpritesGroups(expectedCallingTime); },
CB_GEM.options.LOOP_REFRESH_RATE,
"_processSpritesGroupsTimerId"
);
}
//Starts the game loop:
CB_GEM.loopStart = function()
{
//Defines the "data" used by the rendering engine:
CB_GEM.REM_renderGraphicScene_data =
{
"CB_CanvasObject": CB_GEM.CB_CanvasObject, //Main canvas. Mandatory.
"CB_CanvasObjectContext": CB_GEM.CB_CanvasObjectContext, //Context of the main canvas. Mandatory.
"CB_CanvasObjectBuffer": CB_GEM.CB_CanvasObjectBuffer, //Buffer canvas. Mandatory if "useBuffer" is set to true.
"CB_CanvasObjectBufferContext": CB_GEM.CB_CanvasObjectBufferContext //Context of the buffer canvas. Optional. Mandatory if "useBuffer" is set to true.
};
//Defines whether to use buffer or not:
CB_GEM.REM_renderGraphicScene_useBuffer = !CB_GEM.options.CANVAS_FORCED_EMULATION_METHOD && CB_REM.BUFFER_RECOMMENDED;
//Starts processing the sprites groups:
CB_GEM.stopped = false;
if (CB_GEM.DEBUG_MESSAGES) { CB_console("[CB_GEM] Starts processing graphic sprites scene ('CB_GraphicSpritesScene' object) constantly..."); }
CB_GEM._processSpritesGroups(0);
}
//Stops the game loop:
CB_GEM.loopStop = function()
{
//Stops processing the sprites groups:
clearTimeout(CB_GEM._processSpritesGroups_timer);
CB_GEM.stopped = true;
}
//Returns the current data of the game engine:
CB_GEM.getData_object = {};
CB_GEM.getData = function(stringify, avoidRenderingEngineData, avoidGraphicSpritesSceneData, propertiesToKeepGraphicSpritesSceneObject) //Note: to save/restore we should never forget the audio status.
{
//Updates the internal object with the data:
CB_GEM.getData_object.data = CB_GEM.data;
CB_GEM.getData_object.REM_data = avoidRenderingEngineData ? null : CB_GEM.REM.getData(false, CB_GEM.graphicSpritesSceneObject, avoidGraphicSpritesSceneData, propertiesToKeepGraphicSpritesSceneObject);
//Returns the data (stringified if desired):
return stringify ? JSON.stringify(CB_GEM.getData_object) : CB_GEM.getData_object; //It could be a good idea to stringify functions ('JSON.stringify' method does not).
}
//Restores the given data into the game engine:
CB_GEM.setData = function(getDataObject, graphicSpritesSceneObject, avoidGraphicSpritesSceneData)
{
if (typeof(getDataObject) === "undefined" || getDataObject === null || typeof(getDataObject) !== "object") { return false; }
//Restores the given data:
CB_GEM.data = getDataObject.data;
CB_GEM.REM.setData(getDataObject.REM_data, graphicSpritesSceneObject);
return true;
}
//TODO: A 'reset' method could be useful sometimes.
if (CB_GEM.DEBUG_MESSAGES) { CB_console("[CB_GEM] game_engine.js inserted in the document"); }
/* This file belongs to a CrossBrowdy.com example, made by Joan Alba Maldonado. Creative Commons Attribution 4.0 International License. */
//Constants and variables:
var CB_GEM = CB_this.CB_GEM || {}; //Game Engine Module object.
CB_GEM.PATH = CB_this.CB_GEM_PATH || ""; //Path to the game rendering engine module.
CB_GEM.REM_PATH = CB_GEM.REM_PATH || "../graphic_rendering_engine_files/"; //Path to the graphic rendering engine module.
CB_GEM.DEBUG_MESSAGES = !!CB_this.CB_GEM_DEBUG_MESSAGES; //Sets whether to show debug messages or not.
//Module basic configuration:
CB_Modules.modules["GAME_ENGINE_MODULE"] =
{
//Name of the module:
"name" : "GAME_ENGINE_MODULE",
//Status (UNKNOWN, UNLOADED, LOADING, LOADED, READY or FAILED):
"status" : CB_Modules.STATUSES.UNLOADED,
//Function to call as soon as the module is called (before loading its files):
"onCall" :
function(scriptPathGiven)
{
//Stores the desired options for the rendering engine:
CB_this.CB_REM_DEBUG_MESSAGES = CB_GEM.DEBUG_MESSAGES;
CB_this.CB_REM_PATH = CB_GEM.REM_PATH;
//If a 'CB_GEM.PATH' is given, updates the needed files and modules to search for them in the desired path:
if (CB_GEM.PATH)
{
CB_Modules.modules["GAME_ENGINE_MODULE"].neededFiles = {};
CB_Modules.modules["GAME_ENGINE_MODULE"].neededFiles[CB_GEM.PATH + "game_engine.js"] = { load: true, mandatory: true, absolutePath: true };
}
//If a 'CB_GEM.REM_PATH' is given, updates the needed files and modules to search for them in the desired path:
if (CB_GEM.REM_PATH)
{
//Adds the rendering engine module to the game engine module:
var CB_REM_MODULE_NEEDED_MODULES = {};
CB_REM_MODULE_NEEDED_MODULES[CB_GEM.REM_PATH + "rendering_engine_module.js"] = { load: true, mandatory: true, absolutePath: true };
CB_Modules.modules["GAME_ENGINE_MODULE"].neededModules = null;
CB_Modules.addNeededModule("GAME_ENGINE_MODULE", "RENDERING_ENGINE_MODULE", CB_REM_MODULE_NEEDED_MODULES);
}
if (CB_GEM.DEBUG_MESSAGES) { CB_console("[CB_GEM] GAME_ENGINE_MODULE called"); }
CB_Modules.setStatus("GAME_ENGINE_MODULE", CB_Modules.STATUSES.LOADED);
},
//Callback function to call when the module has been loaded successfully:
"onLoad" :
function(scriptPathGiven)
{
if (CB_GEM.DEBUG_MESSAGES) { CB_console("[CB_GEM] GAME_ENGINE_MODULE loaded"); }
//Sets the module ready when CrossBase module is ready:
var checkRenderingEngineReady =
function()
{
//If CrossBase module is not ready yet:
if (!CB_Modules.modules["RENDERING_ENGINE_MODULE"] || CB_Modules.modules["RENDERING_ENGINE_MODULE"].status !== CB_Modules.STATUSES.READY)
{
return setTimeout(checkRenderingEngineReady, 1); //Calls this checking function again.
}
//...otherwise, if CrossBase module is ready, proceeds:
else
{
CB_GEM._init(); //Calls initialization function.
//Applies the options set by the user (if any):
CB_applyOptions("CrossBrowdy");
CB_applyOptions("CrossBase");
CB_Modules.setStatus("GAME_ENGINE_MODULE", CB_Modules.STATUSES.READY); //Sets the GAME_ENGINE_MODULE as ready.
}
};
checkRenderingEngineReady();
},
//Callback function to call when the module is ready:
"onReady" :
function(scriptPathGiven)
{
if (CB_GEM.DEBUG_MESSAGES) { CB_console("[CB_GEM] GAME_ENGINE_MODULE ready"); }
},
//Needed files:
"neededFiles" :
{
//Filepaths:
"game_engine.js" : { load: true, mandatory: true, absolutePath: true } //Needs to be loaded. Mandatory. Relative path.
},
//Needed modules:
"neededModules" :
[
{
"name" : "RENDERING_ENGINE_MODULE",
"neededFiles" : { "rendering_engine_module.js" : { load: true, mandatory: true, absolutePath: true } }
}
],
//Credits:
"credits" : "[CB] - GAME_ENGINE_MODULE by Joan Alba Maldonado" //Credits will be shown in the console when loading.
};
if (CB_GEM.DEBUG_MESSAGES) { CB_console("[CB_GEM] game_engine_module.js (GAME_ENGINE_MODULE file) inserted in the document"); }
/* This file belongs to a CrossBrowdy.com example, made by Joan Alba Maldonado. Creative Commons Attribution 4.0 International License. */
//Defines whether to shows debug messages or not:
var CB_GEM_DEBUG_MESSAGES = true;
//Adds the game engine module to CrossBrowdy:
CB_Modules.addNeededModule(CB_NAME, "GAME_ENGINE_MODULE", { "game_engine_module.js" : { load: true, mandatory: true, absolutePath: true } });
CB_init(main); //It will call the "main" function when ready.
//This function will be called when CrossBrowdy is ready:
function main()
{
CB_console("CrossBrowdy and all needed modules loaded. Starting game engine example...");
//Sets the desired sprites scene data (can be modified dynamically):
var pandaLeftDefault = 100;
var pandaTopDefault = 100;
var pandaWidthDefault = 100;
var pandaHeightDefault = 100;
CB_GEM.spritesGroupsData =
{
//'my_sprites_groups_1' ('CB_GraphicSpritesScene.SPRITES_GROUPS_OBJECT' object). Some missing or non-valid properties will get a default value:
id: "my_sprites_groups_1", //Identifier of the sprites groups object (also used for the 'CB_GraphicSpritesScene' object). Optional but recommended. It should be unique. By default, it is generated automatically.
srcWidth: 40, //The value for the "srcWidth" property which will be used as default if not provided (or the provided one was wrong) in the given 'CB_GraphicSprites.SPRITES_OBJECT' objects. Default: CB_GraphicSprites.WIDTH_SOURCE_DEFAULT.
srcHeight: 40, //The value for the "srcHeight" property which will be used as default if not provided (or the provided one was wrong) in the given 'CB_GraphicSprites.SPRITES_OBJECT' objects. Default: CB_GraphicSprites.HEIGHT_SOURCE_DEFAULT.
data: { loop: true }, //Object with any additional data desired which can be any kind. Default: { 'that' : CB_GraphicSprites.SPRITES_OBJECT, 'getThis' = function() { return this.that; } }.
//Numeric array containing 'CB_GraphicSprites.SPRITES_OBJECT' objects with all the sprites groups that will be used (their "parent" property will be set to point the current 'CB_GraphicSpritesScene' object which contains them):
spritesGroups:
[
//'panda_sprites' ('CB_GraphicSprites.SPRITES_OBJECT' object). Some missing or non-valid properties will will be inherited from the parent ('CB_GraphicSpritesScene.SPRITES_GROUPS_OBJECT' object):
{
id: "panda_sprites", //Identifier of the sprites group (also used for the 'CB_GraphicSprites' object). Optional but recommended. It should be unique. If not provided, it will be calculated automatically.
left: pandaTopDefault, //Left (horizontal) position in the destiny (inside the sprites group). Unit agnostic (only numeric values allowed). Default: CB_GraphicSprites.LEFT_DEFAULT.
top: pandaTopDefault, //Top (vertical) position in the destiny (inside the sprites group). Unit agnostic (only numeric values allowed). Default: CB_GraphicSprites.TOP_DEFAULT.
width: pandaWidthDefault, //Width of the destiny. Unit agnostic (only numeric values allowed). Default: this.parent.width || CB_GraphicSprites.WIDTH_DEFAULT.
height: pandaHeightDefault, //Height of the destiny. Unit agnostic (only numeric values allowed). Default: this.parent.height || CB_GraphicSprites.HEIGHT_DEFAULT.
//Object with any additional data desired which can be any kind:
//NOTE: it will always have a "that" property pointing to the 'CB_GraphicSprites.SPRITES_OBJECT' object where it belongs to and a function in its "getThis" property returning the same value (added automatically).
data: { skipAfter: 500, positionAbsolute: true }, //Object with any additional data desired which can be any kind. Default: CB_combineJSON(this.parent.data, this.data) || this.parent.data || { 'that' : CB_GraphicSprites.SPRITES_OBJECT, 'getThis' = function() { return this.that; } }.
//Numeric array containing 'CB_GraphicSprites.SPRITE_OBJECT' objects with all the sprites that will be used:
sprites:
[
//'panda_sprites_sprite_1' ('CB_GraphicSprites.SPRITE_OBJECT' object). Some missing or non-valid properties will be inherited from the sprites group:
{
id: "panda_sprites_sprite_1", //Identifier for the sprite. Optional but recommended. It should be unique. If not provided, it will be calculated automatically.
src: "img/panda_1.gif" //Source of origin. Can be a path or identifier of an image, text, bitmap, 3D object, etc. Optional but recommended. Default: this.parent.src || "".
},
//'panda_sprites_sprite_2' ('CB_GraphicSprites.SPRITE_OBJECT' object). Some missing or non-valid properties will be inherited from the sprites group:
{
id: "panda_sprites_sprite_2", //Identifier for the sprite. Optional but recommended. It should be unique. If not provided, it will be calculated automatically.
src: "img/panda_2.gif" //Source of origin. Can be a path or identifier of an image, text, bitmap, 3D object, etc. Optional but recommended. Default: this.parent.src || "".
}
]
},
//'bird_sprites' ('CB_GraphicSprites.SPRITES_OBJECT' object). Some missing or non-valid properties will will be inherited from the parent ('CB_GraphicSpritesScene.SPRITES_GROUPS_OBJECT' object):
{
id: "bird_sprites", //Identifier of the sprites group (also used for the 'CB_GraphicSprites' object). Optional but recommended. It should be unique. If not provided, it will be calculated automatically.
src: "img/bird_sprites.gif", //Source of origin. Can be a path or identifier of an image, text, bitmap, 3D object, etc. Optional but recommended. Default: this.parent.src || "".
srcWidth: 38, //Width of the original source. Unit agnostic (only numeric values allowed). Default: this.parent.srcWidth || CB_GraphicSprites.WIDTH_SOURCE_DEFAULT.
srcHeight: 36, //Height of the original source. Unit agnostic (only numeric values allowed). Default: this.parent.srcHeight || CB_GraphicSprites.HEIGHT_SOURCE_DEFAULT.
left: 300, //Left (horizontal) position in the destiny (inside the sprites group). Unit agnostic (only numeric values allowed). Default: CB_GraphicSprites.LEFT_DEFAULT.
width: 190, //Width of the destiny. Unit agnostic (only numeric values allowed). Default: this.parent.width || CB_GraphicSprites.WIDTH_DEFAULT.
height: 160, //Height of the destiny. Unit agnostic (only numeric values allowed). Default: this.parent.height || CB_GraphicSprites.HEIGHT_DEFAULT.
//Object with any additional data desired which can be any kind:
//NOTE: it will always have a "that" property pointing to the 'CB_GraphicSprites.SPRITES_OBJECT' object where it belongs to and a function in its "getThis" property returning the same value (added automatically).
data: { skipAfter: 600, clearPreviousFirst: true, onlyUseInMap: false /* Set to true to only display in maps */ }, //Object with any additional data desired which can be any kind. Default: CB_combineJSON(this.parent.data, this.data) || this.parent.data || { 'that' : CB_GraphicSprites.SPRITES_OBJECT, 'getThis' = function() { return this.that; } }.
//Numeric array containing 'CB_GraphicSprites.SPRITE_OBJECT' objects with all the sprites that will be used:
sprites:
[
//'bird_sprite_1' ('CB_GraphicSprites.SPRITE_OBJECT' object). Some missing or non-valid properties will be inherited from the sprites group:
{
id: "bird_sprite_1", //Identifier for the sprite. Optional but recommended. It should be unique. If not provided, it will be calculated automatically.
//Numeric array containing 'CB_GraphicSprites.SUBSPRITE_OBJECT' objects with the sub-sprites that this sprite uses:
subSprites:
[
//'bird_sprite_1_subsprite_1' ('CB_GraphicSprites.SUBSPRITE_OBJECT' object). Some missing or non-valid properties will be inherited from the parent sprite:
{
id: "bird_sprite_1_subsprite_1", //Identifier for the sub-sprite. Optional but recommended. It should be unique. If not provided, it will be calculated automatically.
src: "img/sol.gif",
srcLeft: 0, //Left (horizontal) position in the original source (having in mind its real width and height). Unit agnostic (only numeric values allowed). Default: this.parent.srcLeft || CB_GraphicSprites.LEFT_SOURCE_DEFAULT.
srcTop: 0, //Top (vertical) position in the original source (having in mind its real width and height). Unit agnostic (only numeric values allowed). Default: this.parent.srcTop || CB_GraphicSprites.TOP_SOURCE_DEFAULT.
srcWidth: 80, //Width of the original source. Unit agnostic (only numeric values allowed). Default: this.parent.srcWidth || CB_GraphicSprites.WIDTH_SOURCE_DEFAULT.
srcHeight: 80, //Height of the original source. Unit agnostic (only numeric values allowed). Default: this.parent.srcHeight || CB_GraphicSprites.HEIGHT_SOURCE_DEFAULT.
left: 20, //Left (horizontal) position in the destiny (inside the sprite). Unit agnostic (only numeric values allowed). Default: CB_GraphicSprites.LEFT_DEFAULT.
top: 170, //Top (vertical) position in the destiny (inside the sprite). Unit agnostic (only numeric values allowed). Default: CB_GraphicSprites.TOP_DEFAULT.
width: 40, //Width of the destiny (inside the sprite). Unit agnostic (only numeric values allowed). Default: this.parent.width || CB_GraphicSprites.WIDTH_DEFAULT.
height: 40, //Height of the destiny (inside the sprite). Unit agnostic (only numeric values allowed). Default: this.parent.height || CB_GraphicSprites.HEIGHT_DEFAULT.
data: { duration: 200, timeResetAndEnableAfter: 200 },
zIndex: 2
},
//'bird_sprite_1_subsprite_2' ('CB_GraphicSprites.SUBSPRITE_OBJECT' object). Some missing or non-valid properties will be inherited from the parent sprite:
{
id: "bird_sprite_1_subsprite_2", //Identifier for the sub-sprite. Optional but recommended. It should be unique. If not provided, it will be calculated automatically.
src: "img/seta.gif",
srcLeft: 0, //Left (horizontal) position in the original source (having in mind its real width and height). Unit agnostic (only numeric values allowed). Default: this.parent.srcLeft || CB_GraphicSprites.LEFT_SOURCE_DEFAULT.
srcTop: 0, //Top (vertical) position in the original source (having in mind its real width and height). Unit agnostic (only numeric values allowed). Default: this.parent.srcTop || CB_GraphicSprites.TOP_SOURCE_DEFAULT.
srcWidth: 40, //Width of the original source. Unit agnostic (only numeric values allowed). Default: this.parent.srcWidth || CB_GraphicSprites.WIDTH_SOURCE_DEFAULT.
srcHeight: 40, //Height of the original source. Unit agnostic (only numeric values allowed). Default: this.parent.srcHeight || CB_GraphicSprites.HEIGHT_SOURCE_DEFAULT.
top: 200, //Top (vertical) position in the destiny (inside the sprite). Unit agnostic (only numeric values allowed). Default: CB_GraphicSprites.TOP_DEFAULT.
width: 12, //Width of the destiny (inside the sprite). Unit agnostic (only numeric values allowed). Default: this.parent.width || CB_GraphicSprites.WIDTH_DEFAULT.
height: 12, //Height of the destiny (inside the sprite). Unit agnostic (only numeric values allowed). Default: this.parent.height || CB_GraphicSprites.HEIGHT_DEFAULT.
data:
{
duration: null
}
}
]
},
//'bird_sprite_2' ('CB_GraphicSprites.SPRITE_OBJECT' object). Some missing or non-valid properties will be inherited from the sprites group:
{
id: "bird_sprite_2", //Identifier for the sprite. Optional but recommended. It should be unique. If not provided, it will be calculated automatically.
srcLeft: 38, //Left (horizontal) position in the original source (having in mind its real width and height). Unit agnostic (only numeric values allowed). Default: this.parent.srcLeft || CB_GraphicSprites.LEFT_SOURCE_DEFAULT.
//Numeric array containing 'CB_GraphicSprites.SUBSPRITE_OBJECT' objects with the sub-sprites that this sprite uses:
subSprites:
[
//'bird_sprite_2_subsprite_1' ('CB_GraphicSprites.SUBSPRITE_OBJECT' object). Some missing or non-valid properties will be inherited from the parent sprite:
{
id: "bird_sprite_2_subsprite_1", //Identifier for the sub-sprite. Optional but recommended. It should be unique. If not provided, it will be calculated automatically.
src: "img/sol.gif",
srcLeft: 0, //Left (horizontal) position in the original source (having in mind its real width and height). Unit agnostic (only numeric values allowed). Default: this.parent.srcLeft || CB_GraphicSprites.LEFT_SOURCE_DEFAULT.
srcTop: 0, //Top (vertical) position in the original source (having in mind its real width and height). Unit agnostic (only numeric values allowed). Default: this.parent.srcTop || CB_GraphicSprites.TOP_SOURCE_DEFAULT.
srcWidth: 80, //Width of the original source. Unit agnostic (only numeric values allowed). Default: this.parent.srcWidth || CB_GraphicSprites.WIDTH_SOURCE_DEFAULT.
srcHeight: 80, //Height of the original source. Unit agnostic (only numeric values allowed). Default: this.parent.srcHeight || CB_GraphicSprites.HEIGHT_SOURCE_DEFAULT.
left: 20, //Left (horizontal) position in the destiny (inside the sprite). Unit agnostic (only numeric values allowed). Default: CB_GraphicSprites.LEFT_DEFAULT.
top: 170, //Top (vertical) position in the destiny (inside the sprite). Unit agnostic (only numeric values allowed). Default: CB_GraphicSprites.TOP_DEFAULT.
width: 40, //Width of the destiny (inside the sprite). Unit agnostic (only numeric values allowed). Default: this.parent.width || CB_GraphicSprites.WIDTH_DEFAULT.
height: 40, //Height of the destiny (inside the sprite). Unit agnostic (only numeric values allowed). Default: this.parent.height || CB_GraphicSprites.HEIGHT_DEFAULT.
data: { duration: 200, timeResetAndEnableAfter: 200 },
zIndex: 2
},
//'bird_sprite_2_subsprite_1' ('CB_GraphicSprites.SUBSPRITE_OBJECT' object). Some missing or non-valid properties will be inherited from the parent sprite:
{
id: "bird_sprite_2_subsprite_2", //Identifier for the sub-sprite. Optional but recommended. It should be unique. If not provided, it will be calculated automatically.
src: "img/seta.gif",
srcLeft: 0, //Left (horizontal) position in the original source (having in mind its real width and height). Unit agnostic (only numeric values allowed). Default: this.parent.srcLeft || CB_GraphicSprites.LEFT_SOURCE_DEFAULT.
srcTop: 0, //Top (vertical) position in the original source (having in mind its real width and height). Unit agnostic (only numeric values allowed). Default: this.parent.srcTop || CB_GraphicSprites.TOP_SOURCE_DEFAULT.
srcWidth: 40, //Width of the original source. Unit agnostic (only numeric values allowed). Default: this.parent.srcWidth || CB_GraphicSprites.WIDTH_SOURCE_DEFAULT.
srcHeight: 40, //Height of the original source. Unit agnostic (only numeric values allowed). Default: this.parent.srcHeight || CB_GraphicSprites.HEIGHT_SOURCE_DEFAULT.
top: 200, //Top (vertical) position in the destiny (inside the sprite). Unit agnostic (only numeric values allowed). Default: CB_GraphicSprites.TOP_DEFAULT.
width: 12, //Width of the destiny (inside the sprite). Unit agnostic (only numeric values allowed). Default: this.parent.width || CB_GraphicSprites.WIDTH_DEFAULT.
height: 12, //Height of the destiny (inside the sprite). Unit agnostic (only numeric values allowed). Default: this.parent.height || CB_GraphicSprites.HEIGHT_DEFAULT.
data: { duration: null }
}
]
}
]
}
]
};
//Sets the desired options for the game engine module:
CB_GEM.setOptions
(
{
LOOP_REFRESH_RATE: 16, //A refresh rate of 16 is about 60 FPS (Frames Per Second) when the cycles per loop is set to 1. Default: 16.
RENDERING_CYCLES_PER_LOOP: 1, //The number of rendering cycles per loop. It will affect the FPS.
CANVAS_FORCED_EMULATION_METHOD: undefined, //Forces a canvas emulation mode which can be 'SILVERLIGHT', 'FLASH', 'DHTML' or 'VML' (testing purposes). Use null or undefined to disable it. Default: undefined.
canvasId: "my_canvas", //Identifier for the canvas element. Default: 'my_canvas'.
canvasBufferId: "my_canvas_buffer" //Identifier for the buffer canvas element. Default: 'my_canvas_buffer'.
}
);
//Defines the callbacks for the game loop:
CB_GEM.data = //Data stored in the game engine module (can be exported to save the game status):
{
pandaLeft: pandaLeftDefault,
pandaTop: pandaTopDefault,
pandaLeftPrevious: 0,
pandaTopPrevious: 0,
pandaWidth: pandaWidthDefault,
pandaHeight: pandaHeightDefault,
pixelsMovement: 5
};
var moving = false;
var panda = null;
CB_GEM.onLoopStart = function(graphicSpritesSceneObject, CB_REM_dataObject, expectedCallingTime) //When the game loop starts, before rendering the graphics (if it returns false, it will skip rendering in this loop):
{
//Moves the panda according to the input received through the keyboard (and controllers that fire keyboard events):
if (CB_Keyboard.isKeyDown(CB_Keyboard.keys.UP)) { CB_GEM.data.pandaTop -= CB_GEM.data.pixelsMovement; }
if (CB_Keyboard.isKeyDown(CB_Keyboard.keys.DOWN)) { CB_GEM.data.pandaTop += CB_GEM.data.pixelsMovement; }
if (CB_Keyboard.isKeyDown(CB_Keyboard.keys.LEFT)) { CB_GEM.data.pandaLeft -= CB_GEM.data.pixelsMovement; }
if (CB_Keyboard.isKeyDown(CB_Keyboard.keys.RIGHT)) { CB_GEM.data.pandaLeft += CB_GEM.data.pixelsMovement; }
panda = CB_GEM.graphicSpritesSceneObject.getById("panda_sprites");
if (CB_GEM.data.pandaLeft < 0) { CB_GEM.data.pandaLeft = 0; }
else if (CB_GEM.data.pandaLeft > CB_GEM.CB_CanvasObject.getWidth() - panda.getCurrent().width) { CB_GEM.data.pandaLeft = CB_GEM.CB_CanvasObject.getWidth() - panda.getCurrent().width; }
if (CB_GEM.data.pandaTop < 0) { CB_GEM.data.pandaTop = 0; }
else if (CB_GEM.data.pandaTop > CB_GEM.CB_CanvasObject.getHeight() - panda.getCurrent().height) { CB_GEM.data.pandaTop = CB_GEM.CB_CanvasObject.getHeight() - panda.getCurrent().height; }
moving = false;
if (CB_GEM.data.pandaLeft !== CB_GEM.data.pandaLeftPrevious) { panda.setPropertyCascade("left", CB_GEM.data.pandaLeft); moving = true; }
if (CB_GEM.data.pandaTop !== CB_GEM.data.pandaTopPrevious) { panda.setPropertyCascade("top", CB_GEM.data.pandaTop); moving = true; }
CB_GEM.data.pandaLeftPrevious = CB_GEM.data.pandaLeft;
CB_GEM.data.pandaTopPrevious = CB_GEM.data.pandaTop;
if (moving) { CB_GEM.data.pixelsMovement++ } //Accelerates.
else { CB_GEM.data.pixelsMovement = 5; } //Restores normal speed.
};
CB_GEM.onLoopEnd = function(graphicSpritesSceneObject, CB_REM_dataObject, expectedCallingTime) //When the game loop ends, after rendering the graphics (not executed if the 'CB_GEM.onLoopStart' function returned false):
{
//Changes the panda size according to whether it is moving or not:
if (moving)
{
CB_GEM.data.pandaWidth = panda.getCurrent().width - 1;
CB_GEM.data.pandaHeight = panda.getCurrent().height - 1;
}
else
{
CB_GEM.data.pandaWidth = pandaWidthDefault;
CB_GEM.data.pandaHeight = pandaHeightDefault;
}
panda.setPropertyCascade("width", CB_GEM.data.pandaWidth);
panda.setPropertyCascade("height", CB_GEM.data.pandaHeight);
};
//Sets some keyboard events (some controllers can also fire keyboard events):
CB_Keyboard.onKeyDown
(
function(e, keyCode)
{
//After pressing the ESC key, stops or starts the game loop (depending on its current status):
if (keyCode === CB_Keyboard.keys.ESC[0]) { gameLoopStartStop(); }
//...otherwise, after pressing the SPACEBAR key, it will show the current data in the console:
else if (keyCode === CB_Keyboard.keys.SPACEBAR[0]) { getGameData(); } //Not stringified.
}
);
//Starts the game engine module:
CB_GEM.begin
(
//onStart:
function(graphicSpritesSceneObject, CB_CanvasObject, CB_CanvasObjectBuffer, FPSSprites) //'FPSSprites' contains the 'CB_GraphicSprites.SPRITES_OBJECT' object used to display the FPS counter.
{
FPSSprites.setDisabled(false); //Set to true to hide FPS counter.
FPSSprites.getCurrent().data.fontSize = "18px"; //Sets the font size for the FPS counter.
FPSSprites.getCurrent().data.style = "#ff0000"; //Sets the font colour for the FPS counter.
},
//onError:
function(error) { CB_console("Error: " + error); }
);
}
//Starts the game loop if not started (is stopped) or stops it otherwise:
function gameLoopStartStop()
{
if (CB_GEM.stopped) { CB_console("Starting game loop..."); CB_GEM.loopStart(); }
else { CB_console("Stopping game loop..."); CB_GEM.loopStop(); }
}
//Function that prints the game data in the console:
function getGameData(stringified)
{
CB_console("Showing current data (" + (stringified ? "stringified" : "object") + "):");
var data = CB_GEM.getData(stringified);
CB_console(data);
alert(stringified ? data : JSON.stringify(data));
}
Additional files used (inside the "img" folder): bird_sprites.gif, panda_1.gif, panda_2.gif, seta.gif and sol.gif.
You can check the Guides & Tutorials category as well as the API documentation in the case you need more information.
All the examples together can be downloaded here.