/* * gameQuery rev. 0.7.1 * * Copyright (c) 2012 Selim Arsever (http://gamequeryjs.com) * licensed under the MIT-License */ // This allows use of the convenient $ notation in a plugin (function($) { // CSS Feature detection from: Craig Buckler (http://www.sitepoint.com/detect-css3-property-browser-support/) var cssTransform = false; var detectElement = document.createElement("detect"), CSSprefix = "Webkit,Moz,O,ms,Khtml".split(","), All = ("transform," + CSSprefix.join("Transform,") + "Transform").split(","); for (var i = 0, l = All.length; i < l; i++) { if (detectElement.style[All[i]] === "") { cssTransform = All[i]; } } // This prefix can be use whenever needed to namespace CSS classes, .data() inputs aso. var gQprefix = "gQ_"; // Those are the possible states of the engine var STATE_NEW = 0; // Not yet started for the first time var STATE_RUNNING = 1; // Started and running var STATE_PAUSED = 2; // Paused /** * Utility function that returns the radius for a geometry. * * @param {object} elem DOM element * @param {float} angle the angle in degrees * @return {object} .x, .y radius of geometry */ var proj = function (elem, angle) { switch (elem.geometry){ case $.gameQuery.GEOMETRY_RECTANGLE : var b = angle*Math.PI*2/360; var Rx = Math.abs(Math.cos(b)*elem.width/2*elem.factor)+Math.abs(Math.sin(b)*elem.height/2*elem.factor); var Ry = Math.abs(Math.cos(b)*elem.height/2*elem.factor)+Math.abs(Math.sin(b)*elem.width/2*elem.factor); return {x: Rx, y: Ry}; } }; /** * Utility function that checks for collision between two elements. * * @param {object} elem1 DOM for the first element * @param {float} offset1 offset of the first element * @param {object} elem2 DOM for the second element * @param {float} offset2 offset of the second element * @return {boolean} if the two elements collide or not */ var collide = function(elem1, offset1, elem2, offset2) { // test real collision (only for two rectangles...) if((elem1.geometry == $.gameQuery.GEOMETRY_RECTANGLE && elem2.geometry == $.gameQuery.GEOMETRY_RECTANGLE)){ var dx = offset2.x + elem2.boundingCircle.x - elem1.boundingCircle.x - offset1.x; var dy = offset2.y + elem2.boundingCircle.y - elem1.boundingCircle.y - offset1.y; var a = Math.atan(dy/dx); var Dx = Math.abs(Math.cos(a-elem1.angle*Math.PI*2/360)/Math.cos(a)*dx); var Dy = Math.abs(Math.sin(a-elem1.angle*Math.PI*2/360)/Math.sin(a)*dy); var R = proj(elem2, elem2.angle-elem1.angle); if((elem1.width/2*elem1.factor+R.x <= Dx) || (elem1.height/2*elem1.factor+R.y <= Dy)) { return false; } else { var Dx = Math.abs(Math.cos(a-elem2.angle*Math.PI*2/360)/Math.cos(a)*-dx); var Dy = Math.abs(Math.sin(a-elem2.angle*Math.PI*2/360)/Math.sin(a)*-dy); var R = proj(elem1, elem1.angle-elem2.angle); if((elem2.width/2*elem2.factor+R.x <= Dx) || (elem2.height/2*elem2.factor+R.y <= Dy)) { return false; } else { return true; } } } else { return false; } }; /** * Utility function computes the offset relative to the playground of a gameQuery element without using DOM's position. * This should be faster than the standand .offset() function. * * Warning: No non-gameQuery elements should be present between this element and the playground div! * * @param {jQuery} element the jQuery wrapped DOM element representing the gameQuery object. * @return {object} an object {x:, y: } containing the x and y offset. (Not top and left like jQuery's .offset()) */ var offset = function(element) { // Get the tileSet offset (relative to the playground) var offset = {x: 0, y: 0}; var parent = element[0]; while(parent !== $.gameQuery.playground[0] && parent.gameQuery !== undefined) { offset.x += parent.gameQuery.posx; offset.y += parent.gameQuery.posy; parent = parent.parentNode; } return offset } /** * Utility function computes the index range of the tiles for a tilemap. * * @param {jQuery} element the jQuery wrapped DOM element representing the tilemap. * @param {object} offset an object holding the x and y offset of the tilemap, this is optional and will be computed if not provided. * @return {object} an object {firstColumn: , lastColumn: , fristRow: , lastRow: } */ var visibleTilemapIndexes = function (element, elementOffset) { if (elementOffset === undefined) { elementOffset = offset(element); } var gameQuery = element[0].gameQuery; // Activate the visible tiles return { firstRow: Math.max(Math.min(Math.floor(-elementOffset.y/gameQuery.height), gameQuery.sizey), 0), lastRow: Math.max(Math.min(Math.ceil(($.gameQuery.playground[0].height-elementOffset.y)/gameQuery.height), gameQuery.sizey), 0), firstColumn: Math.max(Math.min(Math.floor(-elementOffset.x/gameQuery.width), gameQuery.sizex), 0), lastColumn: Math.max(Math.min(Math.ceil(($.gameQuery.playground[0].width-elementOffset.x)/gameQuery.width), gameQuery.sizex), 0) } } /** * Utility function thast computes the buffered zone of a tilemap * * @param {jQuery} element the jQuery wrapped DOM element representing the tilemap. * @param {object} visible an object describing the visible zone * @return {object} an object {firstColumn: , lastColumn: , fristRow: , lastRow: } */ var bufferedTilemapIndexes = function (element, visible) { var gameQuery = element[0].gameQuery; return { firstRow: Math.max(Math.min(visible.firstRow - gameQuery.buffer, gameQuery.sizey), 0), lastRow: Math.max(Math.min(visible.lastRow + gameQuery.buffer, gameQuery.sizey), 0), firstColumn: Math.max(Math.min(visible.firstColumn - gameQuery.buffer, gameQuery.sizex), 0), lastColumn: Math.max(Math.min(visible.lastColumn + gameQuery.buffer, gameQuery.sizex), 0) } } /** * Utility function that creates a tile in the given tilemap * * @param {jQuery} tileSet the jQuery element representing the tile map * @param {integer} row the row index of the tile in the tile map * @param {integer} column the column index of the tile in the tile map */ var addTile = function(tileSet, row, column) { var gameQuery = tileSet[0].gameQuery; var name = tileSet.attr("id"); var tileDescription; if(gameQuery.func) { tileDescription = gameQuery.tiles(row,column)-1; } else { tileDescription = gameQuery.tiles[row][column]-1; } var animation; if(gameQuery.multi) { animation = gameQuery.animations; } else { animation = gameQuery.animations[tileDescription]; } if(tileDescription >= 0){ tileSet.addSprite($.gameQuery.tileIdPrefix+name+"_"+row+"_"+column, {width: gameQuery.width, height: gameQuery.height, posx: column*gameQuery.width, posy: row*gameQuery.height, animation: animation}); var newTile = tileSet.find("#"+$.gameQuery.tileIdPrefix+name+"_"+row+"_"+column); if (gameQuery.multi) { newTile.setAnimation(tileDescription); } else { newTile[0].gameQuery.animationNumber = tileDescription; } newTile.removeClass($.gameQuery.spriteCssClass); newTile.addClass($.gameQuery.tileCssClass); newTile.addClass($.gameQuery.tileTypePrefix+tileDescription); } } // Define the list of object/function accessible through $. $.extend({ gameQuery: { /** * This is the Animation Object */ Animation: function (options, imediateCallback) { // private default values var defaults = { imageURL: "", numberOfFrame: 1, delta: 0, rate: 30, type: 0, distance: 0, offsetx: 0, offsety: 0 }; // options extends defaults options = $.extend(defaults, options); // "public" attributes: this.imageURL = options.imageURL; // The url of the image to be used as an animation or sprite this.numberOfFrame = options.numberOfFrame; // The number of frames to be displayed when playing the animation this.delta = options.delta; // The distance in pixels between two frames this.rate = options.rate; // The rate at which the frames change in miliseconds this.type = options.type; // The type of the animation.This is a bitwise OR of the properties. this.distance = options.distance; // The distance in pixels between two animations this.offsetx = options.offsetx; // The x coordinate where the first sprite begins this.offsety = options.offsety; // The y coordinate where the first sprite begins // Whenever a new animation is created we add it to the ResourceManager animation list $.gameQuery.resourceManager.addAnimation(this, imediateCallback); return true; }, /** * "constants" for the different types of an animation */ ANIMATION_VERTICAL: 1, // Generated by a vertical offset of the background ANIMATION_HORIZONTAL: 2, // Generated by a horizontal offset of the background ANIMATION_ONCE: 4, // Played only once (else looping indefinitely) ANIMATION_CALLBACK: 8, // A callback is exectued at the end of a cycle ANIMATION_MULTI: 16, // The image file contains many animations ANIMATION_PINGPONG: 32, // At the last frame of the animation it reverses (if used in conjunction with ONCE it will have no effect) // "constants" for the different type of geometry for a sprite GEOMETRY_RECTANGLE: 1, GEOMETRY_DISC: 2, // basic values refreshRate: 30, /** * An object to manage resource loading */ resourceManager: { animations: [], // List of animations / images used in the game sounds: [], // List of sounds used in the game callbacks: [], // List of the functions called at each refresh loadedAnimationsPointer: 0, // Keep track of the last loaded animation loadedSoundsPointer: 0, // Keep track of the last loaded sound /** * Load resources before starting the game. */ preload: function() { // Start loading the images for (var i = this.animations.length-1 ; i >= this.loadedAnimationsPointer; i --){ this.animations[i].domO = new Image(); this.animations[i].domO.src = this.animations[i].imageURL; } // Start loading the sounds for (var i = this.sounds.length-1 ; i >= this.loadedSoundsPointer; i --){ this.sounds[i].load(); } $.gameQuery.resourceManager.waitForResources(); }, /** * Wait for all the resources called for in preload() to finish loading. */ waitForResources: function() { // Check the images var imageCount = 0; for(var i=this.loadedAnimationsPointer; i < this.animations.length; i++){ if(this.animations[i].domO.complete){ imageCount++; } } // Check the sounds var soundCount = 0; for(var i=this.loadedSoundsPointer; i < this.sounds.length; i++){ var temp = this.sounds[i].ready(); if(temp){ soundCount++; } } // Call the load callback with the current progress if($.gameQuery.resourceManager.loadCallback){ var percent = (imageCount + soundCount)/(this.animations.length + this.sounds.length - this.loadedAnimationsPointer - this.loadedSoundsPointer)*100; $.gameQuery.resourceManager.loadCallback(percent); } if(imageCount + soundCount < (this.animations.length + this.sounds.length - this.loadedAnimationsPointer - this.loadedSoundsPointer)){ imgWait=setTimeout(function () { $.gameQuery.resourceManager.waitForResources(); }, 100); } else { this.loadedAnimationsPointer = this.animations.length; this.loadedSoundsPointer = this.sounds.length; // All the resources are loaded! We can now associate the animation's images to their corresponding sprites $.gameQuery.scenegraph.children().each(function(){ // recursive call on the children: $(this).children().each(arguments.callee); // add the image as a background if(this.gameQuery && this.gameQuery.animation){ $(this).css("background-image", "url("+this.gameQuery.animation.imageURL+")"); // we set the correct kind of repeat if(this.gameQuery.animation.type & $.gameQuery.ANIMATION_VERTICAL) { $(this).css("background-repeat", "repeat-x"); } else if(this.gameQuery.animation.type & $.gameQuery.ANIMATION_HORIZONTAL) { $(this).css("background-repeat", "repeat-y"); } else { $(this).css("background-repeat", "no-repeat"); } } }); // Launch the refresh loop if($.gameQuery.state === STATE_NEW){ setInterval(function () { $.gameQuery.resourceManager.refresh(); },($.gameQuery.refreshRate)); } $.gameQuery.state = STATE_RUNNING; if($.gameQuery.startCallback){ $.gameQuery.startCallback(); } // Make the scenegraph visible $.gameQuery.scenegraph.css("visibility","visible"); } }, /** * This function refresh a unique sprite here 'this' represent a dom object */ refreshSprite: function() { // Check if 'this' is a gameQuery element if(this.gameQuery != undefined){ var gameQuery = this.gameQuery; // Does 'this' has an animation ? if(gameQuery.animation){ // Do we have anything to do? if ( (gameQuery.idleCounter == gameQuery.animation.rate-1) && gameQuery.playing){ // Does 'this' loops? if(gameQuery.animation.type & $.gameQuery.ANIMATION_ONCE){ if(gameQuery.currentFrame < gameQuery.animation.numberOfFrame-1){ gameQuery.currentFrame += gameQuery.frameIncrement; } else if(gameQuery.currentFrame == gameQuery.animation.numberOfFrame-1) { // Does 'this' has a callback ? if(gameQuery.animation.type & $.gameQuery.ANIMATION_CALLBACK){ if($.isFunction(gameQuery.callback)){ gameQuery.callback(this); gameQuery.callback = false; } } } } else { if(gameQuery.animation.type & $.gameQuery.ANIMATION_PINGPONG){ if(gameQuery.currentFrame == gameQuery.animation.numberOfFrame-1 && gameQuery.frameIncrement == 1) { gameQuery.frameIncrement = -1; } else if (gameQuery.currentFrame == 0 && gameQuery.frameIncrement == -1) { gameQuery.frameIncrement = 1; } } gameQuery.currentFrame = (gameQuery.currentFrame+gameQuery.frameIncrement)%gameQuery.animation.numberOfFrame; if(gameQuery.currentFrame == 0){ // Does 'this' has a callback ? if(gameQuery.animation.type & $.gameQuery.ANIMATION_CALLBACK){ if($.isFunction(gameQuery.callback)){ gameQuery.callback(this); } } } } // Update the background if((gameQuery.animation.type & $.gameQuery.ANIMATION_VERTICAL) && (gameQuery.animation.numberOfFrame > 1)){ if(gameQuery.multi){ $(this).css("background-position",""+(-gameQuery.animation.offsetx-gameQuery.multi)+"px "+(-gameQuery.animation.offsety-gameQuery.animation.delta*gameQuery.currentFrame)+"px"); } else { $(this).css("background-position",""+(-gameQuery.animation.offsetx)+"px "+(-gameQuery.animation.offsety-gameQuery.animation.delta*gameQuery.currentFrame)+"px"); } } else if((gameQuery.animation.type & $.gameQuery.ANIMATION_HORIZONTAL) && (gameQuery.animation.numberOfFrame > 1)) { if(gameQuery.multi){ $(this).css("background-position",""+(-gameQuery.animation.offsetx-gameQuery.animation.delta*gameQuery.currentFrame)+"px "+(-gameQuery.animation.offsety-gameQuery.multi)+"px"); } else { $(this).css("background-position",""+(-gameQuery.animation.offsetx-gameQuery.animation.delta*gameQuery.currentFrame)+"px "+(-gameQuery.animation.offsety)+"px"); } } } gameQuery.idleCounter = (gameQuery.idleCounter+1)%gameQuery.animation.rate; } } return true; }, /** * This function refresh a unique tile-map, here 'this' represent a dom object */ refreshTilemap: function() { // Check if 'this' is a gameQuery element if(this.gameQuery != undefined){ var gameQuery = this.gameQuery; if($.isArray(gameQuery.frameTracker)){ for(var i=0; i 1)){ $(this).css("background-position",""+(-gameQuery.animations[animationNumber].offsetx)+"px "+(-gameQuery.animations[animationNumber].offsety-gameQuery.animations[animationNumber].delta*gameQuery.frameTracker[animationNumber])+"px"); } else if((gameQuery.animations[animationNumber].type & $.gameQuery.ANIMATION_HORIZONTAL) && (gameQuery.animations[animationNumber].numberOfFrame > 1)) { $(this).css("background-position",""+(-gameQuery.animations[animationNumber].offsetx-gameQuery.animations[animationNumber].delta*gameQuery.frameTracker[animationNumber])+"px "+(-gameQuery.animations[animationNumber].offsety)+"px"); } } else { if((gameQuery.animations.type & $.gameQuery.ANIMATION_VERTICAL) && (gameQuery.animations.numberOfFrame > 1)){ $(this).css("background-position",""+(-gameQuery.animations.offsetx-this.gameQuery.multi)+"px "+(-gameQuery.animations.offsety-gameQuery.animations.delta*gameQuery.frameTracker)+"px"); } else if((gameQuery.animations.type & $.gameQuery.ANIMATION_HORIZONTAL) && (gameQuery.animations.numberOfFrame > 1)) { $(this).css("background-position",""+(-gameQuery.animations.offsetx-gameQuery.animations.delta*gameQuery.frameTracker)+"px "+(-gameQuery.animations.offsety-this.gameQuery.multi)+"px"); } } }); } return true; }, /** * Called periodically to refresh the state of the game. */ refresh: function() { if($.gameQuery.state === STATE_RUNNING) { $.gameQuery.playground.find("."+$.gameQuery.spriteCssClass).each(this.refreshSprite); $.gameQuery.playground.find("."+$.gameQuery.tilemapCssClass).each(this.refreshTilemap); var deadCallback= new Array(); for (var i = this.callbacks.length-1; i >= 0; i--){ if(this.callbacks[i].idleCounter == this.callbacks[i].rate-1){ var returnedValue = this.callbacks[i].fn(); if(typeof returnedValue == 'boolean'){ // If we have a boolean: 'true' means 'no more execution', 'false' means 'keep on executing' if(returnedValue){ deadCallback.push(i); } } else if(typeof returnedValue == 'number') { // If we have a number it re-defines the time to the next call this.callbacks[i].rate = Math.round(returnedValue/$.gameQuery.refreshRate); this.callbacks[i].idleCounter = 0; } } this.callbacks[i].idleCounter = (this.callbacks[i].idleCounter+1)%this.callbacks[i].rate; } for(var i = deadCallback.length-1; i >= 0; i--){ this.callbacks.splice(deadCallback[i],1); } } }, /** * Add an animation to the resource Manager */ addAnimation: function(animation, callback) { if($.inArray(animation,this.animations)<0){ //normalize the animation rate: animation.rate = Math.round(animation.rate/$.gameQuery.refreshRate); if(animation.rate==0){ animation.rate = 1; } this.animations.push(animation); switch ($.gameQuery.state){ case STATE_NEW: case STATE_PAUSED: // Nothing to do for now break; case STATE_RUNNING: // immediatly load the animation and call the callback if any this.animations[this.loadedAnimationsPointer].domO = new Image(); this.animations[this.loadedAnimationsPointer].domO.src = animation.imageURL; if (callback !== undefined){ this.animations[this.loadedAnimationsPointer].domO.onload = callback; } this.loadedAnimationsPointer++; break; } } }, /** * Add a sound to the resource Manager */ addSound: function(sound, callback){ if($.inArray(sound,this.sounds)<0){ this.sounds.push(sound); switch ($.gameQuery.state){ case STATE_NEW: case STATE_PAUSED: // Nothing to do for now break; case STATE_RUNNING: // immediatly load the sound and call the callback if any sound.load(); // TODO callback.... this.loadedSoundsPointer++; break; } } }, /** * Register a callback * * @param {function} fn the callback * @param {integer} rate the rate in ms at which the callback should be called (should be a multiple of the playground rate or will be rounded) */ registerCallback: function(fn, rate){ rate = Math.round(rate/$.gameQuery.refreshRate); if(rate==0){ rate = 1; } this.callbacks.push({fn: fn, rate: rate, idleCounter: 0}); }, /** * Clear the animations and sounds */ clear: function(callbacksToo){ this.animations = []; this.loadedAnimationsPointer = 0; this.sounds = []; this.loadedSoundsPointer = 0; if(callbacksToo) { this.callbacks = []; } } }, /** * This is a single place to update the underlying data of sprites/groups/tiles after a position or dimesion modification. */ update: function(descriptor, transformation) { // Did we really receive a descriptor or a jQuery object instead? if(!$.isPlainObject(descriptor)){ // Then we must get real descriptor if(descriptor.length > 0){ var gameQuery = descriptor[0].gameQuery; } else { var gameQuery = descriptor.gameQuery; } } else { var gameQuery = descriptor; } // If we couldn't find one we return if(!gameQuery) return; if(gameQuery.tileSet === true){ // We have a tilemap var visible = visibleTilemapIndexes(descriptor); var buffered = gameQuery.buffered; // Test what kind of transformation we have and react accordingly for(property in transformation){ switch(property){ case "x": if(visible.lastColumn > buffered.lastColumn) { // Detach the tilemap var parent = descriptor[0].parentNode; var tilemap = descriptor.detach(); var newBuffered = bufferedTilemapIndexes(descriptor, visible); for(var i = gameQuery.buffered.firstRow; i < gameQuery.buffered.lastRow; i++){ // Remove the newly invisible tiles for(var j = gameQuery.buffered.firstColumn; j < Math.min(newBuffered.firstColumn, gameQuery.buffered.lastColumn); j++) { tilemap.find("#"+$.gameQuery.tileIdPrefix+descriptor.attr("id")+"_"+i+"_"+j).remove(); } // And add the newly visible tiles for(var j = Math.max(gameQuery.buffered.lastColumn,newBuffered.firstColumn); j < newBuffered.lastColumn ; j++) { addTile(tilemap,i,j); } } gameQuery.buffered.firstColumn = newBuffered.firstColumn; gameQuery.buffered.lastColumn = newBuffered.lastColumn; // Attach the tilemap back tilemap.appendTo(parent); } if(visible.firstColumn < buffered.firstColumn) { // Detach the tilemap var parent = descriptor[0].parentNode; var tilemap = descriptor.detach(); var newBuffered = bufferedTilemapIndexes(descriptor, visible); for(var i = gameQuery.buffered.firstRow; i < gameQuery.buffered.lastRow; i++){ // Remove the newly invisible tiles for(var j = Math.max(newBuffered.lastColumn,gameQuery.buffered.firstColumn); j < gameQuery.buffered.lastColumn ; j++) { tilemap.find("#"+$.gameQuery.tileIdPrefix+descriptor.attr("id")+"_"+i+"_"+j).remove(); } // And add the newly visible tiles for(var j = newBuffered.firstColumn; j < Math.min(gameQuery.buffered.firstColumn,newBuffered.lastColumn); j++) { addTile(tilemap,i,j); } } gameQuery.buffered.firstColumn = newBuffered.firstColumn; gameQuery.buffered.lastColumn = newBuffered.lastColumn; // Attach the tilemap back tilemap.appendTo(parent); } break; case "y": if(visible.lastRow > buffered.lastRow) { // Detach the tilemap var parent = descriptor[0].parentNode; var tilemap = descriptor.detach(); var newBuffered = bufferedTilemapIndexes(descriptor, visible); for(var j = gameQuery.buffered.firstColumn; j < gameQuery.buffered.lastColumn ; j++) { // Remove the newly invisible tiles for(var i = gameQuery.buffered.firstRow; i < Math.min(newBuffered.firstRow, gameQuery.buffered.lastRow); i++){ tilemap.find("#"+$.gameQuery.tileIdPrefix+descriptor.attr("id")+"_"+i+"_"+j).remove(); } // And add the newly visible tiles for(var i = Math.max(gameQuery.buffered.lastRow, newBuffered.firstRow); i < newBuffered.lastRow; i++){ addTile(tilemap,i,j); } } gameQuery.buffered.firstRow = newBuffered.firstRow; gameQuery.buffered.lastRow = newBuffered.lastRow; // Attach the tilemap back tilemap.appendTo(parent); } if(visible.firstRow < buffered.firstRow) { // Detach the tilemap var parent = descriptor[0].parentNode; var tilemap = descriptor.detach(); var newBuffered = bufferedTilemapIndexes(descriptor, visible); for(var j = gameQuery.buffered.firstColumn; j < gameQuery.buffered.lastColumn ; j++) { // Remove the newly invisible tiles for(var i = Math.max(newBuffered.lastRow, gameQuery.buffered.firstRow); i < gameQuery.buffered.lastRow; i++){ tilemap.find("#"+$.gameQuery.tileIdPrefix+descriptor.attr("id")+"_"+i+"_"+j).remove(); } // And add the newly visible tiles for(var i = newBuffered.firstRow; i < Math.min(gameQuery.buffered.firstRow, newBuffered.lastRow); i++){ addTile(tilemap,i,j); } } gameQuery.buffered.firstRow = newBuffered.firstRow; gameQuery.buffered.lastRow = newBuffered.lastRow; // Attach the tilemap back tilemap.appendTo(parent); } break; case "angle": //TODO break; case "factor": //TODO break; } } } else { var refreshBoundingCircle = $.gameQuery.playground && !$.gameQuery.playground.disableCollision; // Update the descriptor for(property in transformation){ switch(property){ case "x": if(refreshBoundingCircle){ gameQuery.boundingCircle.x = gameQuery.posx+gameQuery.width/2; } break; case "y": if(refreshBoundingCircle){ gameQuery.boundingCircle.y = gameQuery.posy+gameQuery.height/2; } break; case "w": case "h": gameQuery.boundingCircle.originalRadius = Math.sqrt(Math.pow(gameQuery.width,2) + Math.pow(gameQuery.height,2))/2 gameQuery.boundingCircle.radius = gameQuery.factor*gameQuery.boundingCircle.originalRadius; break; case "angle": //(in degrees) gameQuery.angle = parseFloat(transformation.angle); break; case "factor": gameQuery.factor = parseFloat(transformation.factor); if(refreshBoundingCircle){ gameQuery.boundingCircle.radius = gameQuery.factor*gameQuery.boundingCircle.originalRadius; } break; } } } }, // State of the engine state: STATE_NEW, // CSS classes used to mark game element spriteCssClass: gQprefix + "sprite", groupCssClass: gQprefix + "group", tilemapCssClass: gQprefix + "tilemap", tileCssClass: gQprefix + "tile", // Prefix for CSS Ids or Classes tileTypePrefix: gQprefix + "tileType_", tileIdPrefix: gQprefix + "tile_" }, /** * Mute (or unmute) all the sounds. */ muteSound: function(muted){ for (var i = $.gameQuery.resourceManager.sounds.length-1 ; i >= 0; i --) { $.gameQuery.resourceManager.sounds[i].muted(muted); } }, /** * Accessor for the currently defined playground as a jQuery object */ playground: function() { return $.gameQuery.playground }, /** * Define a callback called during the loading of the game's resources. * * The function will recieve as unique parameter * a number representing the progess percentage. */ loadCallback: function(callback){ $.gameQuery.resourceManager.loadCallback = callback; } }); // end of the extensio of $ // fragments used to create DOM element var spriteFragment = $("
"); var groupFragment = $("
"); var tilemapFragment = $("
"); // Define the list of object/function accessible through $("selector"). $.fn.extend({ /** * Defines the currently selected div to which contains the game and initialize it. * * This is a non-destructive call */ playground: function(options) { if(this.length == 1){ if(this[0] == document){ // Old usage detected, this is not supported anymore throw "Old playground usage, use $.playground() to retreive the playground and $('mydiv').playground(options) to set the div!"; } options = $.extend({ height: 320, width: 480, refreshRate: 30, position: "absolute", keyTracker: false, mouseTracker: false, disableCollision: false }, options); // We save the playground node and set some variable for this node: $.gameQuery.playground = this; $.gameQuery.refreshRate = options.refreshRate; $.gameQuery.playground[0].height = options.height; $.gameQuery.playground[0].width = options.width; // We initialize the display of the div $.gameQuery.playground.css({ position: options.position, display: "block", overflow: "hidden", height: options.height+"px", width: options.width+"px" }) .append("