| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849 |
- /*
- * 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<gameQuery.frameTracker.length; i++){
- // Do we have anything to do?
- if(gameQuery.idleCounter[i] == gameQuery.animations[i].rate-1){
- // Does 'this' loops?
- if(gameQuery.animations[i].type & $.gameQuery.ANIMATION_ONCE){
- if(gameQuery.frameTracker[i] < gameQuery.animations[i].numberOfFrame-1){
- gameQuery.frameTracker[i] += gameQuery.frameIncrement[i];
- }
- } else {
- if(gameQuery.animations[i].type & $.gameQuery.ANIMATION_PINGPONG){
- if(gameQuery.frameTracker[i] == gameQuery.animations[i].numberOfFrame-1 && gameQuery.frameIncrement[i] == 1) {
- gameQuery.frameIncrement[i] = -1;
- } else if (gameQuery.frameTracker[i] == 0 && gameQuery.frameIncrement[i] == -1) {
- gameQuery.frameIncrement[i] = 1;
- }
- }
- gameQuery.frameTracker[i] = (gameQuery.frameTracker[i]+gameQuery.frameIncrement[i])%gameQuery.animations[i].numberOfFrame;
- }
- }
- gameQuery.idleCounter[i] = (gameQuery.idleCounter[i]+1)%gameQuery.animations[i].rate;
- }
- } else {
- // Do we have anything to do?
- if(gameQuery.idleCounter == gameQuery.animations.rate-1){
- // Does 'this' loops?
- if(gameQuery.animations.type & $.gameQuery.ANIMATION_ONCE){
- if(gameQuery.frameTracker < gameQuery.animations.numberOfFrame-1){
- gameQuery.frameTracker += gameQuery.frameIncrement;
- }
- } else {
- if(gameQuery.animations.type & $.gameQuery.ANIMATION_PINGPONG){
- if(gameQuery.frameTracker == gameQuery.animations.numberOfFrame-1 && gameQuery.frameIncrement == 1) {
- gameQuery.frameIncrement = -1;
- } else if (gameQuery.frameTracker == 0 && gameQuery.frameIncrement == -1) {
- gameQuery.frameIncrement = 1;
- }
- }
- gameQuery.frameTracker = (gameQuery.frameTracker+gameQuery.frameIncrement)%gameQuery.animations.numberOfFrame;
- }
- }
- gameQuery.idleCounter = (gameQuery.idleCounter+1)%gameQuery.animations.rate;
- }
- // Update the background of all active tiles
- $(this).find("."+$.gameQuery.tileCssClass).each(function(){
- if($.isArray(gameQuery.frameTracker)){
- var animationNumber = this.gameQuery.animationNumber
- if((gameQuery.animations[animationNumber].type & $.gameQuery.ANIMATION_VERTICAL) && (gameQuery.animations[animationNumber].numberOfFrame > 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 = $("<div class='"+$.gameQuery.spriteCssClass+"' style='position: absolute; display: block; overflow: hidden' />");
- var groupFragment = $("<div class='"+$.gameQuery.groupCssClass+"' style='position: absolute; display: block; overflow: hidden' />");
- var tilemapFragment = $("<div class='"+$.gameQuery.tilemapCssClass+"' style='position: absolute; display: block; overflow: hidden;' />");
- // 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("<div id='"+gQprefix+"scenegraph' style='visibility: hidden'/>");
- $.gameQuery.scenegraph = $("#"+gQprefix+"scenegraph");
- // Add the keyTracker to the gameQuery object:
- $.gameQuery.keyTracker = {};
- // We only enable the real tracking if the users wants it
- if(options.keyTracker){
- $(document).keydown(function(event){
- $.gameQuery.keyTracker[event.keyCode] = true;
- });
- $(document).keyup(function(event){
- $.gameQuery.keyTracker[event.keyCode] = false;
- });
- }
-
- // Add the mouseTracker to the gameQuery object:
- $.gameQuery.mouseTracker = {
- x: 0,
- y: 0};
- // We only enable the real tracking if the users wants it
- var scenegraphOffset = $.gameQuery.playground.offset();
- if(options.mouseTracker){
- $($.gameQuery.playground).mousemove(function(event){
- $.gameQuery.mouseTracker.x = event.pageX - scenegraphOffset.left;
- $.gameQuery.mouseTracker.y = event.pageY - scenegraphOffset.top;
- });
- $(document).mousedown(function(event){
- $.gameQuery.mouseTracker[event.which] = true;
- });
- $(document).mouseup(function(event){
- $.gameQuery.mouseTracker[event.which] = false;
- });
- }
- }
- return this;
- },
- /**
- * Starts the game.
- *
- * Resources from the resource manager are preloaded if necesary
- * Works only for the playground node.
- *
- * This is a non-destructive call
- */
- startGame: function(callback) {
- $.gameQuery.startCallback = callback;
- $.gameQuery.resourceManager.preload();
- return this;
- },
-
- /**
- * TODO
- */
- pauseGame: function() {
- $.gameQuery.state = STATE_PAUSED;
- $.gameQuery.scenegraph.css("visibility","hidden");
- return this;
- },
-
- /**
- * Resume the game if it was paused and call the callback passed in argument once the newly added ressources are loaded.
- */
- resumeGame: function(callback) {
- if($.gameQuery.state === STATE_PAUSED){
- $.gameQuery.startCallback = callback;
- $.gameQuery.resourceManager.preload();
- }
- return this;
- },
- /**
- * Removes all the sprites, groups and tilemaps present in the scenegraph
- */
- clearScenegraph: function() {
- $.gameQuery.scenegraph.empty()
- return this;
- },
-
- /**
- * Removes all the sprites, groups and tilemaps present in the scenegraph as well as all loaded animations and sounds
- */
- clearAll: function(callbackToo) {
- $.gameQuery.scenegraph.empty();
- $.gameQuery.resourceManager.clear(callbackToo)
- return this;
- },
- /**
- * Add a group to the scene graph. Works only on the scenegraph root or on another group
- *
- * This IS a destructive call and should be terminated with end()
- * to go back one level up in the chaining
- */
- addGroup: function(group, options) {
- options = $.extend({
- width: 32,
- height: 32,
- posx: 0,
- posy: 0,
- posz: 0,
- posOffsetX: 0,
- posOffsetY: 0,
- overflow: "visible",
- geometry: $.gameQuery.GEOMETRY_RECTANGLE,
- angle: 0,
- factor: 1,
- factorh: 1,
- factorv: 1
- }, options);
- var newGroupElement = groupFragment.clone().attr("id",group).css({
- overflow: options.overflow,
- height: options.height,
- width: options.width
- });
-
- if(this == $.gameQuery.playground){
- $.gameQuery.scenegraph.append(newGroupElement);
- } else if ((this == $.gameQuery.scenegraph)||(this.hasClass($.gameQuery.groupCssClass))){
- this.append(newGroupElement);
- }
- newGroupElement[0].gameQuery = options;
- newGroupElement[0].gameQuery.boundingCircle = {x: options.posx + options.width/2,
- y: options.posy + options.height/0,
- originalRadius: Math.sqrt(Math.pow(options.width,2) + Math.pow(options.height,2))/2};
- newGroupElement[0].gameQuery.boundingCircle.radius = newGroupElement[0].gameQuery.boundingCircle.originalRadius;
- newGroupElement[0].gameQuery.group = true;
- newGroupElement.transform();
- return this.pushStack(newGroupElement);
- },
- /**
- * Add a sprite to the current node. Works only on the playground or any of its sub-nodes
- *
- * This is a non-destructive call
- */
- addSprite: function(sprite, options) {
- options = $.extend({
- width: 32,
- height: 32,
- posx: 0,
- posy: 0,
- posz: 0,
- posOffsetX: 0,
- posOffsetY: 0,
- idleCounter: 0,
- currentFrame: 0,
- frameIncrement: 1,
- geometry: $.gameQuery.GEOMETRY_RECTANGLE,
- angle: 0,
- factor: 1,
- playing: true,
- factorh: 1,
- factorv: 1
- }, options);
- var newSpriteElem = spriteFragment.clone().attr("id",sprite).css({
- height: options.height,
- width: options.width,
- backgroundPosition: ((options.animation)? -options.animation.offsetx : 0)+"px "+((options.animation)? -options.animation.offsety : 0)+"px"
- });
-
- if(this == $.gameQuery.playground){
- $.gameQuery.scenegraph.append(newSpriteElem);
- } else {
- this.append(newSpriteElem);
- }
- // If the game has already started we want to add the animation's image as a background now
- if(options.animation){
- // The second test is a fix for default background (https://github.com/onaluf/gameQuery/issues/3)
- if($.gameQuery.state === STATE_RUNNING && options.animation.imageURL !== ''){
- newSpriteElem.css("background-image", "url("+options.animation.imageURL+")");
- }
- if(options.animation.type & $.gameQuery.ANIMATION_VERTICAL) {
- newSpriteElem.css("background-repeat", "repeat-x");
- } else if(options.animation.type & $.gameQuery.ANIMATION_HORIZONTAL) {
- newSpriteElem.css("background-repeat", "repeat-y");
- } else {
- newSpriteElem.css("background-repeat", "no-repeat");
- }
- }
- var spriteDOMObject = newSpriteElem[0];
- if(spriteDOMObject != undefined){
- spriteDOMObject.gameQuery = options;
- // Compute bounding Circle
- spriteDOMObject.gameQuery.boundingCircle = {x: options.posx + options.width/2,
- y: options.posy + options.height/2,
- originalRadius: Math.sqrt(Math.pow(options.width,2) + Math.pow(options.height,2))/2};
- spriteDOMObject.gameQuery.boundingCircle.radius = spriteDOMObject.gameQuery.boundingCircle.originalRadius;
- }
- newSpriteElem.transform();
- return this;
- },
- /**
- * Add a Tile Map to the selected element.
- *
- * This is a non-destructive call. The added sprite is NOT selected after a call to this function!
- */
- addTilemap: function(name, tileDescription, animationList, options){
- options = $.extend({
- width: 32,
- height: 32,
- sizex: 32,
- sizey: 32,
- posx: 0,
- posy: 0,
- posz: 0,
- posOffsetX: 0,
- posOffsetY: 0,
- angle: 0,
- factor: 1,
- factorh: 1,
- factorv: 1,
- buffer: 1
- }, options);
- var tileSet = tilemapFragment.clone().attr("id",name).css({
- height: options.height*options.sizey,
- width: options.width*options.sizex
- });
-
- if(this == $.gameQuery.playground){
- $.gameQuery.scenegraph.append(tileSet);
- } else {
- this.append(tileSet);
- }
-
- tileSet[0].gameQuery = options;
- var gameQuery = tileSet[0].gameQuery;
- gameQuery.tileSet = true;
- gameQuery.tiles = tileDescription;
- gameQuery.func = (typeof tileDescription === "function");
-
- if($.isArray(animationList)){
- var frameTracker = [];
- var idleCounter = [];
- var frameIncrement = [];
- for(var i=0; i<animationList.length; i++){
- frameTracker[i] = 0;
- idleCounter[i] = 0;
- frameIncrement[i] = 1;
- }
- gameQuery.frameTracker = frameTracker;
- gameQuery.animations = animationList;
- gameQuery.idleCounter = idleCounter;
- gameQuery.frameIncrement = frameIncrement;
- gameQuery.multi = false;
- } else {
- gameQuery.frameTracker = 0;
- gameQuery.frameIncrement = 1;
- gameQuery.animations = animationList;
- gameQuery.idleCounter = 0;
- gameQuery.multi = true;
-
- }
- // Get the tileSet offset (relative to the playground)
- var visible = visibleTilemapIndexes(tileSet);
- var buffered = bufferedTilemapIndexes(tileSet, visible);
- gameQuery.buffered = buffered;
- // For many simple animation
- for(var i = buffered.firstRow; i < buffered.lastRow; i++){
- for(var j = buffered.firstColumn; j < buffered.lastColumn ; j++) {
- addTile(tileSet, i, j);
- }
- }
- tileSet.transform()
- return this.pushStack(tileSet);
- },
-
- /**
- * This function imports a JSON file generated by Tiled (http://www.mapeditor.org/).
- * All the created tilemaps will be directly under the currently selected element.
- * Their name will be made of the provided prefix followed by a number starting at 0.
- *
- * Only layer of type "tilelayer" are supported for now. Only one single tileset
- * per layer is supported.
- *
- * After the call to this function the second argument will hold two new arrays:
- * - tiles: an arrays of tilemaps wraped in jQuery.
- * - animations: an arrays of animations
- *
- * This is a non-destructive call
- */
- importTilemaps: function(url, prefix, generatedElements){
- var animations = [];
- var tilemaps = [];
-
- var that = this;
-
- var tilemapJsonLoaded = function(json){
- var tilesetGID = [];
- for (var i = 0; i < json.tilesets.length; i++) {
- tilesetGID[i] = json.tilesets[i].firstgid;
- }
-
- var getTilesetIndex = function(index){
- var i = 0;
- while(index >= tilesetGID[i] && i < tilesetGID.length){
- i++;
- }
- return i-1;
- }
-
- var height = json.height;
- var width = json.width;
- var tileHeight = json.tileheight;
- var tileWidth = json.tilewidth;
-
- var layers = json.layers;
- var usedTiles = [];
- var animationCounter = 0;
- var tilemapArrays = [];
-
- // Detect which animations we need to generate
- // and convert the tiles array indexes to the new ones
- for (var i=0; i < layers.length; i++){
- if(layers[i].type === "tilelayer"){
- var tilemapArray = new Array(height);
- for (var j=0; j<height; j++){
- tilemapArray[j] = new Array(width);
- }
- for (var j=0; j < layers[i].data.length; j++){
- var tile = layers[i].data[j];
- if(tile === 0){
- tilemapArray[Math.floor(j / width)][j % width] = 0;
- } else {
- if(!usedTiles[tile]){
- animationCounter++;
- usedTiles[tile] = animationCounter;
- animations.push(new $.gameQuery.Animation({
- imageURL: json.tilesets[getTilesetIndex(tile)].image,
- offsetx: ((tile-1) % Math.floor(json.tilesets[getTilesetIndex(tile)].imagewidth / tileWidth)) * tileWidth,
- offsety: Math.floor((tile-1) / Math.floor(json.tilesets[getTilesetIndex(tile)].imagewidth / tileWidth)) * tileHeight
- }));
- }
- tilemapArray[Math.floor(j / width)][j % width] = usedTiles[tile];
- }
- }
- tilemapArrays.push(tilemapArray);
- }
- }
- // adding the tilemaps
- for (var i=0; i<tilemapArrays.length; i++){
- tilemaps.push(that.addTilemap(
- prefix+i,
- tilemapArrays[i],
- animations,
- {
- sizex: width,
- sizey: height,
- width: tileWidth,
- height: tileHeight
- }));
- }
- };
-
- $.ajax({
- url: url,
- async: false,
- dataType: 'json',
- success: tilemapJsonLoaded
- });
-
- if(generatedElements !== undefined){
- generatedElements.animations = animations;
- generatedElements.tilemaps = tilemaps;
- }
-
- return this;
- },
- /**
- * Stop the animation at the current frame
- *
- * This is a non-destructive call.
- */
- pauseAnimation: function() {
- this[0].gameQuery.playing = false;
- return this;
- },
- /**
- * Resume the animation (if paused)
- *
- * This is a non-destructive call.
- */
- resumeAnimation: function() {
- this[0].gameQuery.playing = true;
- return this;
- },
- /**
- * Changes the animation associated with a sprite.
- *
- * WARNING: no checks are made to ensure that the object is really a sprite
- *
- * This is a non-destructive call.
- */
- setAnimation: function(animation, callback) {
- var gameQuery = this[0].gameQuery;
- if(typeof animation == "number"){
- if(gameQuery.animation.type & $.gameQuery.ANIMATION_MULTI){
- var distance = gameQuery.animation.distance * animation;
- gameQuery.multi = distance;
- gameQuery.frameIncrement = 1;
- gameQuery.currentFrame = 0;
-
- if(gameQuery.animation.type & $.gameQuery.ANIMATION_VERTICAL) {
- this.css("background-position",""+(-distance-gameQuery.animation.offsetx)+"px "+(-gameQuery.animation.offsety)+"px");
- } else if(gameQuery.animation.type & $.gameQuery.ANIMATION_HORIZONTAL) {
- this.css("background-position",""+(-gameQuery.animation.offsetx)+"px "+(-distance-gameQuery.animation.offsety)+"px");
- }
- }
- } else {
- if(animation){
- gameQuery.animation = animation;
- gameQuery.currentFrame = 0;
- gameQuery.frameIncrement = 1;
- if (animation.imageURL !== '') {this.css("backgroundImage", "url('"+animation.imageURL+"')");}
- this.css({"background-position": ""+(-animation.offsetx)+"px "+(-animation.offsety)+"px"});
- if(gameQuery.animation.type & $.gameQuery.ANIMATION_VERTICAL) {
- this.css("background-repeat", "repeat-x");
- } else if(gameQuery.animation.type & $.gameQuery.ANIMATION_HORIZONTAL) {
- this.css("background-repeat", "repeat-y");
- } else {
- this.css("background-repeat", "no-repeat");
- }
- } else {
- this.css("background-image", "");
- }
- }
- if(callback != undefined){
- this[0].gameQuery.callback = callback;
- }
- return this;
- },
- /**
- * Register a callback funnction
- *
- * This is a non-destructive call
- *
- * @param {Function} fn the callback function.
- * @param {Number} rate time in milliseconds between calls.
- */
- registerCallback: function(fn, rate) {
- $.gameQuery.resourceManager.registerCallback(fn, rate);
- return this;
- },
- /**
- * Retrieve a list of objects in collision with the subject.
- *
- * If 'this' is a sprite or a group, the function will retrieve the list of sprites (not groups!!!) that touch it. For now all abject are considered to be boxes.
- *
- * This IS a destructive call and should be terminated with end() to go back one level up in the chaining.
- */
- collision: function(arg1, arg2){
- var filter, override;
- if ($.isPlainObject(arg1)){
- override = arg1;
- } else if (typeof arg1 === "string") {
- filter = arg1;
- }
- if ($.isPlainObject(arg2)){
- override = arg2;
- } else if (typeof arg2 === "string") {
- filter = arg2;
- }
-
- var resultList = [];
- // Retrieve 'this' offset by looking at the parents
- var itsParent = this[0].parentNode, offsetX = 0, offsetY = 0;
- while (itsParent != $.gameQuery.playground[0]){
- if(itsParent.gameQuery){
- offsetX += itsParent.gameQuery.posx;
- offsetY += itsParent.gameQuery.posy;
- }
- itsParent = itsParent.parentNode;
- }
- // Retrieve the playground's absolute position and size information
- var pgdGeom = {top: 0, left: 0, bottom: $.playground().height(), right: $.playground().width()};
- // Retrieve the gameQuery object and correct it with the override
- var gameQuery = jQuery.extend(true, {}, this[0].gameQuery);
- // Retrieve the BoundingCircle and correct it with the override
- var boundingCircle = jQuery.extend(true, {}, gameQuery.boundingCircle);
- if(override && override.w){
- gameQuery.width = override.w;
- }
- if(override && override.h){
- gameQuery.height = override.h;
- }
- boundingCircle.originalRadius = Math.sqrt(Math.pow(gameQuery.width,2) + Math.pow(gameQuery.height,2))/2
- boundingCircle.radius = gameQuery.factor*boundingCircle.originalRadius;
-
- if(override && override.x){
- boundingCircle.x = override.x + gameQuery.width/2.0;
- }
- if(override && override.y){
- boundingCircle.y = override.y + gameQuery.height/2.0;
- }
-
- gameQuery.boundingCircle = boundingCircle;
-
- // Is 'this' inside the playground ?
- if( (gameQuery.boundingCircle.y + gameQuery.boundingCircle.radius + offsetY < pgdGeom.top) ||
- (gameQuery.boundingCircle.x + gameQuery.boundingCircle.radius + offsetX < pgdGeom.left) ||
- (gameQuery.boundingCircle.y - gameQuery.boundingCircle.radius + offsetY > pgdGeom.bottom) ||
- (gameQuery.boundingCircle.x - gameQuery.boundingCircle.radius + offsetX > pgdGeom.right)){
- return this.pushStack(new $([]));
- }
- if(this !== $.gameQuery.playground){
- // We must find all the elements that touche 'this'
- var elementsToCheck = new Array();
- elementsToCheck.push($.gameQuery.scenegraph.children(filter).get());
- elementsToCheck[0].offsetX = 0;
- elementsToCheck[0].offsetY = 0;
- for(var i = 0, len = elementsToCheck.length; i < len; i++) {
- var subLen = elementsToCheck[i].length;
- while(subLen--){
- var elementToCheck = elementsToCheck[i][subLen];
- // Is it a gameQuery generated element?
- if(elementToCheck.gameQuery){
- // We don't want to check groups
- if(!elementToCheck.gameQuery.group && !elementToCheck.gameQuery.tileSet){
- // Does it touche the selection?
- if(this[0]!=elementToCheck){
- // Check bounding circle collision
- var distance = Math.sqrt(Math.pow(offsetY + gameQuery.boundingCircle.y - elementsToCheck[i].offsetY - elementToCheck.gameQuery.boundingCircle.y, 2) + Math.pow(offsetX + gameQuery.boundingCircle.x - elementsToCheck[i].offsetX - elementToCheck.gameQuery.boundingCircle.x, 2));
- if(distance - gameQuery.boundingCircle.radius - elementToCheck.gameQuery.boundingCircle.radius <= 0){
- // Check real collision
- if(collide(gameQuery, {x: offsetX, y: offsetY}, elementToCheck.gameQuery, {x: elementsToCheck[i].offsetX, y: elementsToCheck[i].offsetY})) {
- // Add to the result list if collision detected
- resultList.push(elementsToCheck[i][subLen]);
- }
- }
- }
- }
- // Add the children nodes to the list
- var eleChildren = $(elementToCheck).children(filter);
- if(eleChildren.length){
- elementsToCheck.push(eleChildren.get());
- elementsToCheck[len].offsetX = elementToCheck.gameQuery.posx + elementsToCheck[i].offsetX;
- elementsToCheck[len].offsetY = elementToCheck.gameQuery.posy + elementsToCheck[i].offsetY;
- len++;
- }
- }
- }
- }
- return this.pushStack($(resultList));
- }
- },
- /** ---------------------------------------------------------------------------------------------------------------------------------------------------------------- **/
- /** -- Sound related functions ------------------------------------------------------------------------------------------------------------------ **/
- /** ---------------------------------------------------------------------------------------------------------------------------------------------------------------- **/
- /**
- * Add the sound to the resourceManager for later use and
- * associates it to the selected dom element(s).
- *
- * This is a non-destructive call
- */
- addSound: function(sound, add) {
- // Does a SoundWrapper exist?
- if($.gameQuery.SoundWrapper) {
- var gameQuery = this[0].gameQuery;
- // Should we add to existing sounds?
- if(add) {
- // Do we have some sound associated with 'this'?
- var sounds = gameQuery.sounds;
- if(sounds) {
- // Yes, we add it
- sounds.push(sound);
- } else {
- // No, we create a new sound array
- gameQuery.sounds = [sound];
- }
- } else {
- // No, we replace all sounds with this one
- gameQuery.sounds = [sound];
- }
- }
- return this;
- },
- /**
- * Play the sound(s) associated with the selected dom element(s).
- *
- * This is a non-destructive call.
- */
- playSound: function() {
- $(this).each(function(){
- var gameQuery = this.gameQuery;
- if(gameQuery.sounds) {
- for(var i = gameQuery.sounds.length-1 ; i >= 0; i --) {
- gameQuery.sounds[i].play();
- }
- }
- });
- return this;
- },
- /**
- * Stops the sound(s) associated with the selected dom element(s) and rewinds them.
- *
- * This is a non-destructive call.
- */
- stopSound: function() {
- $(this).each(function(){
- var gameQuery = this.gameQuery;
- if(gameQuery.sounds) {
- for(var i = gameQuery.sounds.length-1 ; i >= 0; i --) {
- gameQuery.sounds[i].stop();
- }
- }
- });
- return this;
- },
- /**
- * Pauses the sound(s) associated with the selected dom element(s).
- *
- * This is a non-destructive call.
- */
- pauseSound: function() {
- $(this).each(function(){
- var gameQuery = this.gameQuery;
- if(gameQuery.sounds) {
- for(var i = gameQuery.sounds.length-1 ; i >= 0; i --) {
- gameQuery.sounds[i].pause();
- }
- }
- });
- return this;
- },
- /**
- * Mute or unmute the selected sound or all the sounds if none is specified.
- *
- * This is a non-destructive call.
- */
- muteSound: function(muted) {
- $(this).each(function(){
- var gameQuery = this.gameQuery;
- if(gameQuery.sounds) {
- for(var i = gameQuery.sounds.length-1 ; i >= 0; i --) {
- gameQuery.sounds[i].muted(muted);
- }
- }
- });
- return this;
- },
- /** ---------------------------------------------------------------------------------------------------------------------------------------------------------------- **/
- /** -- Transformation functions ----------------------------------------------------------------------------------------------------------------- **/
- /** ---------------------------------------------------------------------------------------------------------------------------------------------------------------- **/
- /**
- * Internal function doing the combined actions of rotate and scale.
- *
- * Please use .rotate() or .scale() instead since they are part of the supported API!
- *
- * This is a non-destructive call.
- */
- transform: function() {
- var gameQuery = this[0].gameQuery;
- if(cssTransform){
- var transform = "translate("+gameQuery.posx+"px, "+gameQuery.posy+"px) rotate("+gameQuery.angle+"deg) scale("+(gameQuery.factor*gameQuery.factorh)+","+(gameQuery.factor*gameQuery.factorv)+")";
- this.css(cssTransform,transform);
- } else {
- var angle_rad = Math.PI * 2 / 360 * gameQuery.angle;
- // try filter for IE
- // For ie from 5.5
- var cos = Math.cos(angle_rad) * gameQuery.factor;
- var sin = Math.sin(angle_rad) * gameQuery.factor;
- this.css("filter","progid:DXImageTransform.Microsoft.Matrix(M11="+(cos*gameQuery.factorh)+",M12="+(-sin*gameQuery.factorv)+",M21="+(sin*gameQuery.factorh)+",M22="+(cos*gameQuery.factorv)+",SizingMethod='auto expand',FilterType='nearest neighbor')");
- var newWidth = this.width();
- var newHeight = this.height();
- gameQuery.posOffsetX = (newWidth-gameQuery.width)/2;
- gameQuery.posOffsetY = (newHeight-gameQuery.height)/2;
- this.css("left", ""+(gameQuery.posx-gameQuery.posOffsetX)+"px");
- this.css("top", ""+(gameQuery.posy-gameQuery.posOffsetY)+"px");
- }
-
- return this;
- },
- /**
- * Rotate the element(s) clock-wise.
- *
- * @param {Number} angle the angle in degrees
- * @param {Boolean} relative or not
- *
- * This is a non-destructive call when called with a parameter. Without parameter it IS a destructive call since the return value is the current rotation angle!
- */
- rotate: function(angle, relative){
- var gameQuery = this[0].gameQuery;
-
- if(angle !== undefined) {
- if(relative === true){
- angle += gameQuery.angle;
- angle %= 360;
- }
- $.gameQuery.update(gameQuery,{angle: angle});
- return this.transform();
- } else {
- var ang = gameQuery.angle;
- return ang;
- }
- },
- /**
- * Change the scale of the selected element(s). The passed argument is a ratio:
- *
- * @param {Number} factor a ratio: 1.0 = original size, 0.5 = half the original size etc.
- * @param {Boolean} relative or not
- *
- * This is a non-destructive call when called with a parameter. Without parameter it IS a destructive call since the return value is the current scale factor!
- */
- scale: function(factor, relative){
- var gameQuery = this[0].gameQuery;
-
- if(factor !== undefined) {
- if(relative === true){
- factor *= gameQuery.factor;
- }
- $.gameQuery.update(gameQuery,{factor: factor});
- return this.transform();
- } else {
- var fac = gameQuery.factor;
- return fac;
- }
- },
- /**
- * Flips the element(s) horizontally.
- *
- * This is a non-destructive call when called with a parameter. Without parameter it IS a destructive call since the return value is the current horizontal flipping status!
- */
- fliph: function(flip){
- var gameQuery = this[0].gameQuery;
- if (flip === undefined) {
- return (gameQuery.factorh !== undefined) ? (gameQuery.factorh === -1) : false;
- } else if (flip) {
- gameQuery.factorh = -1;
- } else {
- gameQuery.factorh = 1;
- }
- return this.transform();
- },
- /**
- * Flips the element(s) vertically.
- *
- * This is a non-destructive call when called with a parameter. Without parameter it IS a destructive call since the return value is the current vertical flipping status!
- */
- flipv: function(flip){
- var gameQuery = this[0].gameQuery;
- if (flip === undefined) {
- return (gameQuery.factorv !== undefined) ? (gameQuery.factorv === -1) : false;;
- } else if (flip) {
- gameQuery.factorv = -1;
- } else {
- gameQuery.factorv = 1;
- }
- return this.transform();
- },
- /** ---------------------------------------------------------------------------------------------------------------------------------------------------------------- **/
- /** -- Position getter/setter functions --------------------------------------------------------------------------------------------------------- **/
- /** ---------------------------------------------------------------------------------------------------------------------------------------------------------------- **/
- /**
- * Main function to change the sprite/group/tilemap position on screen.
- * The three first agruments are the coordiate (double) and the last one is a flag
- * to specify if the coordinate given are absolute or relative.
- *
- * If no argument is specified then the functions act as a getter and return a
- * object {x,y,z}
- *
- * Please note that the z coordinate is just the z-index.
- *
- * This is a non-destructive call when called with a parameter. Without parameter it IS a destructive call.
- */
- xyz: function(x, y, z, relative) {
- if (x === undefined) {
- return this.getxyz();
- } else {
- return this.setxyz({x: x, y: y, z: z}, relative);
- }
- },
- /**
- * The following functions are all all shortcuts for the .xyz(...) function.
- *
- * @see xyz for detailed documentation.
- *
- * This is a non-destructive call when called with a parameter. Without parameter it IS a destructive call.
- */
- x: function(value, relative) {
- if (value === undefined) {
- return this.getxyz().x;
- } else {
- return this.setxyz({x: value}, relative);
- }
- },
- y: function(value, relative) {
- if (value === undefined) {
- return this.getxyz().y;
- } else {
- return this.setxyz({y: value}, relative);
- }
- },
- z: function(value, relative) {
- if (value === undefined) {
- return this.getxyz().z;
- } else {
- return this.setxyz({z: value}, relative);
- }
- },
- xy: function(x, y, relative) {
- if (x === undefined) {
- // we return the z too since it doesn't cost anything
- return this.getxyz();
- } else {
- return this.setxyz({x: x, y: y}, relative);
- }
- },
- /**
- * Main function to change the sprite/group/tilemap dimension on screen.
- * The two first arguments are the width and height (double) and the last one is a
- * flag to specify if the dimensions given are absolute or relative.
- *
- * If no argument is specified then the functions act as a getter and
- *
- * return an object {w,h}
- *
- * This is a non-destructive call when called with a parameter. Without parameter it IS a destructive call.
- */
- wh: function(w, h, relative) {
- if (w === undefined) {
- return this.getwh();
- } else {
- return this.setwh({w: w, h: h}, relative);
- }
- },
- /**
- * The following functions are all all shortcuts for the .wh(...) function.
- *
- * @see wh for detailed documentation.
- *
- * This is a non-destructive call when called with a parameter. Without parameter it IS a destructive call.
- */
- w: function(value, relative) {
- if (value === undefined) {
- return this.getwh().w;
- } else {
- return this.setwh({w: value}, relative);
- }
- },
- h: function(value, relative) {
- if (value === undefined) {
- return this.getwh().h;
- } else {
- return this.setwh({h: value}, relative);
- }
- },
- /**
- * The following four functions are 'private', and are not supposed to
- * be used outside of the library.
- * They are NOT part of the API and so are not guaranteed to remain unchanged.
- * You should really use .xyz() and .wh() instead.
- */
- getxyz: function() {
- var gameQuery = this[0].gameQuery;
- return {x: gameQuery.posx, y: gameQuery.posy, z: gameQuery.posz};
- },
- setxyz: function(option, relative) {
- var gameQuery = this[0].gameQuery;
- for (coordinate in option) {
- // Update the gameQuery object
- switch (coordinate) {
- case 'x':
- if(relative) {
- option.x += gameQuery.posx;
- }
- gameQuery.posx = option.x;
- this.transform();
-
- //update the sub tile maps (if any), this forces to recompute which tiles are visible
- this.find("."+$.gameQuery.tilemapCssClass).each(function(){
- $(this).x(0, true);
- });
- break;
- case 'y':
- if(relative) {
- option.y += gameQuery.posy;
- }
- gameQuery.posy = option.y;
- this.transform();
-
- //update the sub tile maps (if any), this forces to recompute which tiles are visible
- this.find("."+$.gameQuery.tilemapCssClass).each(function(){
- $(this).y(0, true);
- });
- break;
- case 'z':
- if(relative) {
- option.z += gameQuery.posz;
- }
- gameQuery.posz = option.z;
- this.css("z-index",gameQuery.posz);
- break;
- }
- }
- $.gameQuery.update(this, option);
- return this;
- },
- getwh: function() {
- var gameQuery = this[0].gameQuery;
- return {w: gameQuery.width, h: gameQuery.height};
- },
- setwh: function(option, relative) {
- var gameQuery = this[0].gameQuery;
- for (coordinate in option) {
- // Update the gameQuery object
- switch (coordinate) {
- case 'w':
- if(relative) {
- option.w += gameQuery.width;
- }
- gameQuery.width = option.w;
- this.css("width","" + gameQuery.width + "px");
- break;
- case 'h':
- if(relative) {
- option.h += gameQuery.height;
- }
- gameQuery.height = option.h;
- this.css("height","" + gameQuery.height + "px");
- break;
- }
- }
- $.gameQuery.update(this, option);
- return this;
- }
- }); // end of the extensio of $.fn
- // alias gameQuery to gQ for easier access
- $.extend({ gQ: $.gameQuery});
- })(jQuery);
|