From: dsc Date: Wed, 24 Nov 2010 03:20:16 +0000 (-0800) Subject: AH HA. Finally found the random nested YCollection bug, which in turn fixed line... X-Git-Url: http://git.less.ly:3516/?a=commitdiff_plain;h=8996cc8fca79771369acc71239bbad349308c06e;p=tanks.git AH HA. Finally found the random nested YCollection bug, which in turn fixed line-of-sight targeting (well, along wiht a lot of code). --- diff --git a/css/lttl.css b/css/lttl.css index 051d12c..23b3e57 100644 --- a/css/lttl.css +++ b/css/lttl.css @@ -21,7 +21,7 @@ table.grid, table.grid td { /* outline:1px solid rgba(255,255,255,0.1); */ color:transparent; font: 18pt monospace; margin:0; padding:0; white-space:nowrap; overflow:hidden; } -.gridShowCoords table.grid td:hover { color:rgba(255,255,255,0.1); } +.showGridCoords table.grid td:hover { color:rgba(255,255,255,0.1); } .bigblue { position:fixed; width:100%; top:50%; margin-top:-200px; z-index:101; } .bigblue .box { width:400px; margin:0 auto; padding:1em; color:#000; background-color:#2992C5; diff --git a/src/Y/y-array.js b/src/Y/y-array.js index 7871abe..8b72596 100644 --- a/src/Y/y-array.js +++ b/src/Y/y-array.js @@ -3,7 +3,8 @@ YArray = Y.YArray = YCollection.subclass('YArray', function(YArray){ this.init = function(o){ - YCollection.init.call(this, o || []); + // YCollection.init.call(this, o || []); + this._o = o || []; }; this.merge = @@ -11,16 +12,20 @@ YCollection.subclass('YArray', function(YArray){ function concat( donor ){ var A = this._o; new Y(arguments).forEach(function( donor ){ - A = A.concat(donor); + A = A.concat(donor instanceof Y.YArray ? donor.end() : donor); }); return Y(A); }; this.remove = function remove(v){ - var idx = this.indexOf(v); - if ( idx != -1 ) - this.splice(idx, 1); + if (arguments.length > 1) + Y(arguments).forEach(this.remove, this); + else { + var idx = this.indexOf(v); + if ( idx != -1 ) + this.splice(idx, 1); + } return this; }; diff --git a/src/Y/y-class.js b/src/Y/y-class.js index 2922230..5c7aea0 100644 --- a/src/Y/y-class.js +++ b/src/Y/y-class.js @@ -176,10 +176,22 @@ YBase = Y.YBase = new Class("YBase", { /// Other Class Utilities /// +function bindName(v, k){ + if ( isFunction(v) ) + this[k] = Y(this[k]).bind(this); +} +// bindName = Y(bindName).curry(); + Y.bindAll = bindAll; -function bindAll(o){ - for (var k in o) - if (isFunction(o[k])) o[k] = o[k].bind(o); +function bindAll(o, names){ + var names = new Y(arguments, 1); + Y(names.size() ? names.generate(Y.op.get(o)) : o).forEach( bindName, o ); + + // if ( names.size() ){ + // names.forEach(binder); + // } else + // for (var k in o) binder(k); + return o; } diff --git a/src/Y/y-collection.js b/src/Y/y-collection.js index 9e7ee7b..f027877 100644 --- a/src/Y/y-collection.js +++ b/src/Y/y-collection.js @@ -17,7 +17,7 @@ YBase.subclass('YCollection', { this._o = o; }, - 'attr' : function(k, v, def){ + 'attr' : function attr(k, v, def){ var r = Y.attr(this._o, k, v, def); if (r === this._o) return this; @@ -28,9 +28,9 @@ YBase.subclass('YCollection', { 'merge' : extendY, 'concat' : extendY, - 'end' : function(){ return this._o; }, + 'end' : function end(){ return this._o; }, - 'reduce' : function( fn, acc, context ){ + 'reduce' : function reduce( fn, acc, context ){ var o = this._o || this, acc = acc || new o.constructor(); for ( var name in o ) @@ -38,20 +38,20 @@ YBase.subclass('YCollection', { return acc; }, - 'map' : function( fn, context ){ + 'map' : function map( fn, context ){ var o = this._o, acc = new o.constructor(); for ( var name in o ) acc[name] = fn.call( context || this, o[name], name, o ); return acc; }, - 'forEach' : function( fn, context ){ + 'forEach' : function forEach( fn, context ){ var o = this._o; for ( var name in o ) fn.call( context || this, o[name], name, o ); }, - 'filter' : function( fn, context ){ + 'filter' : function filter( fn, context ){ var o = this._o, acc = new o.constructor(); for ( var name in o ) if ( fn.call( context || this, o[name], name, o ) ) @@ -59,7 +59,7 @@ YBase.subclass('YCollection', { return acc; }, - 'indexOf' : function( value ){ + 'indexOf' : function indexOf( value ){ var o = this._o; for ( var name in o ) if ( o[name] === value ) @@ -67,57 +67,65 @@ YBase.subclass('YCollection', { return -1; }, - 'has' : function( value ){ + 'has' : function has( value ){ return ( this.indexOf(value) !== -1 ); }, - 'clone' : function(){ + 'clone' : function clone(){ return Y({}).extend(this); }, - 'remove' : function(v){ - var o = this._o; + 'remove' : function remove(v){ + var o = this._o + , toRemove = new Y(arguments); + for (var k in o) { - if (o[k] !== v) continue; - delete o[k]; - break; + var v = o[k]; + if ( toRemove.has(v) ) { + delete o[k]; + toRemove.remove(v); + } } return this; }, - 'every' : function( fn ){ + 'every' : function every( fn ){ var self = this, fn = fn || bool; return this.reduce(function(acc, v, k, o){ return acc && fn.call(self, v, k, o); }, true); }, - 'any' : function( fn ){ + 'any' : function any( fn ){ var self = this, fn = fn || bool; return this.reduce(function(acc, v, k, o){ return acc || fn.call(self, v, k, o); }, false); }, - 'zip' : function(){ + 'zip' : function zip(){ var sequences = new Y(arguments).map( Y.limit(1) ).unshift(this); return this.map(function(_, k){ return sequences.invoke('attr', k); }).invoke('end'); }, - 'pluck' : function(key){ + 'pluck' : function pluck(key){ return this.map(function(v){ return v && (isFunction(v.attr) ? v.attr(key) : v[key]); }); }, - 'invoke' : function(name){ + 'invoke' : function invoke(name){ var args = Y(arguments), name = args.shift(); return this.map(function(o){ return o && o[name].apply(o, args); }); + }, + + 'apply' : function apply(name, args){ + return this[name].apply(this, args); } }); diff --git a/src/Y/y-function.js b/src/Y/y-function.js index fe1b668..6f1e873 100644 --- a/src/Y/y-function.js +++ b/src/Y/y-function.js @@ -166,24 +166,24 @@ function splat(fn, x){ var _bind = _Function.prototype.bind; YFunction.prototype.bind = -function bind(context, args){ - var bound = _bind.apply(this, arguments); - bound[WRAPS] = this; - return Y(bound); -}; + function bind(context, args){ + var bound = _bind.apply(this, arguments); + bound[WRAPS] = this; + return Y(bound); + }; // Remembers arguments but obeys current context YFunction.prototype.partial = -function partial(){ - var fn = this - , args = Y(arguments) - , partially = function(){ - return fn.apply( this, args.concat(Y(arguments)) ); - }; - partially[WRAPS] = fn; - return Y(partially); -}; + function partial(){ + var fn = this + , args = Y(arguments) + , partially = function(){ + return fn.apply( this, args.concat(Y(arguments)) ); + }; + partially[WRAPS] = fn; + return Y(partially); + }; // Only works for arguments whose toString is unique and stateless (for example, primitives, but not closures). diff --git a/src/portal/math/vec.js b/src/portal/math/vec.js index 7d5a2e0..d0035a0 100644 --- a/src/portal/math/vec.js +++ b/src/portal/math/vec.js @@ -120,9 +120,9 @@ Y.extend(math.Vec, { // }, manhattan: function manhattan(x1,y1, x2,y2) { - if (x1 instanceof math.Vec && y1 instanceof math.Vec) { - y2 = y1.y; x2 = y1.x; - y1 = x1.y; x1 = x1.x; + if (x1 instanceof Array && y1 instanceof Array) { + y2 = y1[1]; x2 = y1[0]; + y1 = x1[1]; x1 = x1[0]; } var d1 = Math.abs(x2 - x1) , d2 = Math.abs(y2 - y1) ; diff --git a/src/tanks/config.js b/src/tanks/config.js index 39b1897..e8987c9 100644 --- a/src/tanks/config.js +++ b/src/tanks/config.js @@ -1,7 +1,8 @@ // -*- mode: JavaScript; tab-width: 4; indent-tabs-mode: nil; -*- tanks.config = { - debug : { - gridShowCoords : false + ui : { + showGridCoords : false, + showCountdown : false }, pathing : { overlayPathmap : false, diff --git a/src/tanks/game/game.js b/src/tanks/game.js similarity index 95% rename from src/tanks/game/game.js rename to src/tanks/game.js index a8a9950..b3cf024 100644 --- a/src/tanks/game/game.js +++ b/src/tanks/game.js @@ -1,8 +1,9 @@ tanks.Game = new Y.Class('Game', { + overlayPathmap : false, + init : function init(viewport){ Y.bindAll(this); - tanks.resetGlobals(); this.byId = {}; @@ -33,7 +34,10 @@ tanks.Game = new Y.Class('Game', { this.fire('ready', this); }, - + destroy : function destroy(){ + this.stop(); + tanks.resetGlobals(); + }, draw : function draw(){ this.root.draw(); @@ -129,7 +133,7 @@ tanks.Game = new Y.Class('Game', { return unit; }, - moveAgentTo : function moveAgentTo(agent, x,y){ + moveUnitTo : function moveUnitTo(agent, x,y){ this.pathmap.removeBlocker(agent); agent.setLocation(x,y); this.pathmap.addBlocker(agent); @@ -138,6 +142,9 @@ tanks.Game = new Y.Class('Game', { + /** + * @obsolete + */ resize : function resize(){ var ratio = COLUMNS / ROWS , el = this.el diff --git a/src/tanks/map/level.js b/src/tanks/map/level.js index 8909eff..17308f9 100644 --- a/src/tanks/map/level.js +++ b/src/tanks/map/level.js @@ -6,7 +6,7 @@ Level = Rect.subclass('Level', { this.canvas.remove(); this.game = game; - this.walls = []; + this.walls = Y([]); this.pathmap = new PathMap(this, 0,0, w, h, CAPACITY); game.addEventListener('ready', this.setup.bind(this)); @@ -34,10 +34,11 @@ Level = Rect.subclass('Level', { addWall : function addWall(x,y, w,h, isBoundary){ var wall = new Level.Wall(x,y, w,h, isBoundary); - this.walls.push(wall); this.pathmap.addBlocker(wall); - this.append( wall.render(this).shape ); + + if (!isBoundary) + this.walls.push(wall); return wall; }, diff --git a/src/tanks/map/loc.js b/src/tanks/map/loc.js index 6024481..3f65d91 100644 --- a/src/tanks/map/loc.js +++ b/src/tanks/map/loc.js @@ -104,14 +104,14 @@ Y(Loc).extend({ Loc.Rect = new Y.Class('Rect', [], { init : function initRect(x1,y1, x2,y2){ - if (x1 instanceof Loc && y1 instanceof Loc) { - y2 = y1.y; x2 = y1.x; - y1 = x1.y; x1 = x1.x; + if (x1 instanceof Array && y1 instanceof Array) { + y2 = y1[1]; x2 = y1[0]; + y1 = x1[1]; x1 = x1[0]; } // init : function initRect(_x1,_y1, _x2,_y2){ - // if (_x1 instanceof Loc && _y1 instanceof Loc) { - // _y2 = _y1.y; _x2 = _y1.x; - // _y1 = _x1.y; _x1 = _x1.x; + // if (_x1 instanceof Array && _y1 instanceof Array) { + // _y2 = _y1[1]; _x2 = _y1[0]; + // _y1 = _x1[1]; _x1 = _x1[0]; // } // var x1 = Math.min(_x1,_x2), x2 = Math.max(_x1,_x2) // , y1 = Math.min(_y1,_y2), y2 = Math.max(_y1,_y2); @@ -159,7 +159,7 @@ Loc.Rect = new Y.Class('Rect', [], { } }); -Loc.BoundingBox = new Y.Class('BoundingBox', Loc.Rect, { +Loc.BoundingBox = Loc.Rect.subclass('BoundingBox', { init : function initBoundingBox(x1,y1, x2,y2){ Loc.Rect.init.call(this, x1,y1, x2,y2); diff --git a/src/tanks/map/pathmap.js b/src/tanks/map/pathmap.js index 665f2df..5ab4c17 100644 --- a/src/tanks/map/pathmap.js +++ b/src/tanks/map/pathmap.js @@ -31,12 +31,15 @@ PathMap = QuadTree.subclass('PathMap', { this.boundaryWalls = Y.map(BWs, 'this.level.addWall.apply(this.level, _)', this); }, - wallObstructs : function wallObstructs(line, w,h){ + wallObstructs : function wallObstructs(line){ + // var walls = this.walls; + // for (var i=0, L=walls.length, w=walls[i]; i= bb.y1 && line.calcY(bb.x2) <= bb.y2 ) - || ( line.calcX(bb.y1) >= bb.x1 && line.calcX(bb.y2) <= bb.x2 ) ; + return wall.boundingBox.intersects(line); }, this); }, diff --git a/src/tanks/map/trajectory.js b/src/tanks/map/trajectory.js index 0521f90..038864c 100644 --- a/src/tanks/map/trajectory.js +++ b/src/tanks/map/trajectory.js @@ -5,6 +5,8 @@ Trajectory = math.Line.subclass('Trajectory', { init : function initTrajectory(owner, x1,y1, x2,y2, tdist){ + Y.bindAll(this, 'cmp', 'closer'); + this.owner = owner; this.game = owner.game; this.pathmap = this.game.pathmap; @@ -13,6 +15,12 @@ Trajectory = math.Line.subclass('Trajectory', { }, reset : function reset(x1,y1, x2,y2, tdist){ + if (x1 instanceof Array && y1 instanceof Array) { + tdist = x2; + y2 = y1[1]; x2 = y1[0]; + y1 = x1[1]; x1 = x1[0]; + } + // init with raw numbers to do calculations math.Line.init.call(this, x1,y1, x2,y2, tdist || this.tdist); @@ -44,6 +52,87 @@ Trajectory = math.Line.subclass('Trajectory', { return this; }, + /** + * Compares how distant in the future two objects are on this trajectory. + * Objects that have been passed are always further away than those in the future, + * but otherwise the comparison is performed by absolute distance. + * @returns -1 if a closer b, 1 if a further b, 0 if a same as b + */ + cmp : function cmp(a, b){ + if (a instanceof Thing) a = a.midpoint; + if (b instanceof Thing) b = b.midpoint; + + var abs = Math.abs + // , cur = this.owner.midpoint + // , t = this.iparametric(cur.x, cur.y) + , t = this.elapsed + + , xa = this.calcX(a.y), ya = this.calcY(a.x) + , ta = this.iparametric(xa,ya) + , da = (ta.x + ta.y)/2 - t + // , da = (ta.x - t.x + ta.y - t.y)/2 + // , dxa = ta.x - t.x, dya = ta.y - t.y + + , xb = this.calcX(b.y), yb = this.calcY(b.x) + , tb = this.iparametric(xb,yb) + , db = (tb.x + tb.y)/2 - t + // , db = (tb.x - t.x + tb.y - t.y)/2 + // , dxb = tb.x - t.x, dyb = tb.y - t.y + ; + + // If one has passed, return the other + if ( da < 0 && db >= 0 ) + return 1; + if ( db < 0 && da >= 0 ) + return -1; + + return Y.op.cmp(abs(da), abs(db)); + }, + + closer : function closer(o1, o2){ + return this.cmp(o1,o2) === 1 ? o2 : o1; + }, + + closest : function closest(o1, o2){ + return new Y(arguments).sort( this.cmp ).shift(); + }, + + comesWithin : function comesWithin(pt, w,h){ + if ( !this.owner.midpoint ) + return false; + + if (pt instanceof Thing) pt = pt.midpoint; + + if ( w === undefined ){ + w = 0; h = 0; + } else if ( Y.isNumber(w.width) ){ + h = w.height; w = w.width; + } + + var cur = this.owner.midpoint + , fx = this.calcX(pt.y), fy = this.calcY(pt.x) + , t = this.iparametric(cur.x, cur.y) + , ft = this.iparametric(fx,fy) + , dw = Math.abs(fx - pt.x), dh = Math.abs(fy - pt.y) + ; + return ( t.x <= ft.x && t.y <= ft.y + && ( dw <= w || dh <= h ) ); + }, + + pathBlocked : function pathBlocked(obj, ignore){ + var blockers = + this.pathmap.walls + .concat( this.game.units ) + .apply('remove', Y(ignore || []).concat([this.owner]).end()) + .sort( this.cmp ) + + , blocker = blockers.shift() + ; + + return (blocker === obj ? false : blocker); + }, + + step : function step(dt){ this.halt = false; @@ -118,25 +207,6 @@ Trajectory = math.Line.subclass('Trajectory', { return to; }, - willComeWithin : function willComeWithin(pt, w,h){ - if ( !this.owner.midpoint ) - return false; - - if ( !Y.isNumber(w) ){ - h = w.height; w = w.width; - } - - var cur = this.owner.midpoint - , fx = this.calcX(pt.y), fy = this.calcY(pt.x) - , t = this.iparametric(cur.x, cur.y) - , ft = this.iparametric(fx,fy) - , dw = Math.abs(fx - pt.x), dh = Math.abs(fy - pt.y) - ; - return ( t.x <= ft.x && t.y <= ft.y - && ( dw <= w || dh <= h ) - && !this.pathmap.wallObstructs(this, w,h) ); - }, - toString : function toString(){ return 'T['+this.p1+', '+this.p2+', slope='+this.slope.toFixed(3)+']'; } diff --git a/src/tanks/thing/bullet.js b/src/tanks/thing/bullet.js index 1d3dc9b..331aa9d 100644 --- a/src/tanks/thing/bullet.js +++ b/src/tanks/thing/bullet.js @@ -69,7 +69,7 @@ Bullet = Thing.subclass('Bullet', { var to = this.trajectory.step( ELAPSED ); if (!this.dead) - this.game.moveAgentTo(this, to.x, to.y); + this.game.moveUnitTo(this, to.x, to.y); return this; }, diff --git a/src/tanks/thing/player.js b/src/tanks/thing/player.js index efb9caf..cd7827c 100644 --- a/src/tanks/thing/player.js +++ b/src/tanks/thing/player.js @@ -87,7 +87,7 @@ PlayerTank = Tank.subclass('PlayerTank', { ; if ( !blockers.size() ) - this.game.moveAgentTo(this, x,y); + this.game.moveUnitTo(this, x,y); }, diff --git a/src/tanks/thing/tank.js b/src/tanks/thing/tank.js index 1429cd2..1e8bcec 100644 --- a/src/tanks/thing/tank.js +++ b/src/tanks/thing/tank.js @@ -125,18 +125,21 @@ Tank = Thing.subclass('Tank', { willCollide : function willCollide(bullets, wiggle){ wiggle = wiggle || 0; - var bb = this.boundingBox, mid = this.midpoint + var tank = this, bb = this.boundingBox , w = (bb.width+wiggle)/2, h = (bb.height+wiggle)/2 ; return bullets.filter(function(b){ - return !b.dead && b.willComeWithin(mid, w,h); + var trj = b.trajectory; + return ( !b.dead + && trj.comesWithin(tank, w,h) + && !trj.pathBlocked(tank) ); }); }, continueMove : function continueMove(){ if ( !this.currentMove || this.currentMoveLimit <= NOW ){ var t = this.findNearEnemies(10000).shift(); - this.calculatePath(t.midpoint); + if (t) this.calculatePath(t.midpoint); } var to = this.currentMove; @@ -213,10 +216,9 @@ Tank = Thing.subclass('Tank', { , pm = this.game.pathmap ; return this.findNearLike(ticks, function(agent){ var am = agent.midpoint; - return agent.align !== this.align - && Y.is(Tank, agent) - && !(wallObs - && pm.wallObstructs(new Trajectory(this, mid.x,mid.y, am.x,am.y), 6,6)); + return ( agent.align !== this.align + && Y.is(Tank, agent) + && !(wallObs && new Trajectory(this,mid,am).pathBlocked(agent)) ); }); }, @@ -307,7 +309,7 @@ Tank = Thing.subclass('Tank', { ; if ( !blockers.size() ) - this.game.moveAgentTo(this, to.x, to.y); + this.game.moveUnitTo(this, to.x, to.y); return this; }, diff --git a/src/tanks/thing/thing.js b/src/tanks/thing/thing.js index 4fcd2ab..82fcfbc 100644 --- a/src/tanks/thing/thing.js +++ b/src/tanks/thing/thing.js @@ -123,22 +123,10 @@ Thing = new Evt.Class('Thing', { return Math.atan2(y0,x0); }, - willComeWithin : function willComeWithin(pt, w,h){ + comesWithin : function comesWithin(pt, w,h){ if ( !(this.trajectory && this.midpoint) ) return false; - - if ( !Y.isNumber(w) ){ - h = w.height; w = w.width; - } - var trj = this.trajectory - , cur = this.midpoint - , fx = trj.calcX(pt.y), fy = trj.calcY(pt.x) - , t = trj.iparametric(cur.x, cur.y) - , ft = trj.iparametric(fx,fy) - , dw = Math.abs(fx - pt.x), dh = Math.abs(fy - pt.y) - ; - return ( t.x <= ft.x && t.y <= ft.y - && ( dw <= w || dh <= h ) ); + return this.trajectory.comesWithin(pt, w,h); }, diff --git a/src/tanks/main.js b/src/tanks/ui/main.js similarity index 90% rename from src/tanks/main.js rename to src/tanks/ui/main.js index 6944542..d966db4 100644 --- a/src/tanks/main.js +++ b/src/tanks/ui/main.js @@ -1,4 +1,7 @@ +tanks.ui = {}; + (function(){ + jQuery(main); this.main = main; @@ -80,7 +83,7 @@ function setupGame(){ } function teardownGame(){ - LBT.stop(); + LBT.destroy(); $('#viewport').empty(); } @@ -122,11 +125,11 @@ function startGame(evt){ $(document).unbind('keydown', startGame); $('#welcome').hide(); - countdownToStart(3, function(){ - $('#overlay').hide(); - $(document).bind('keydown', 'return', pauseGame); - toggleGame(); - }); + + if ( tanks.config.ui.showCountdown ) + countdownToStart(3, readyToStart); + else + readyToStart(); } function pauseGame(evt){ @@ -173,8 +176,8 @@ function initConfig(){ $('#config [name=aipaths]').attr('checked', p.overlayAIPaths); $('#config [name=trajectories]').attr('checked', p.traceTrajectories); - $('#config [name=gridCoords]').attr('checked', c.debug.gridShowCoords); - $('#viewport .layer.grid')[(c.debug.gridShowCoords ? 'add' : 'remove')+'Class']('gridShowCoords'); + $('#config [name=gridCoords]').attr('checked', c.ui.showGridCoords); + $('#viewport .layer.grid')[(c.ui.showGridCoords ? 'add' : 'remove')+'Class']('showGridCoords'); } function updateConfig(evt){ @@ -186,8 +189,8 @@ function updateConfig(evt){ p.overlayAIPaths = $('#config [name=aipaths]').attr('checked'); p.traceTrajectories = $('#config [name=trajectories]').attr('checked'); - c.debug.gridShowCoords = $('#config [name=gridCoords]').attr('checked'); - $('#viewport .layer.grid')[(c.debug.gridShowCoords ? 'add' : 'remove')+'Class']('gridShowCoords'); + c.ui.showGridCoords = $('#config [name=gridCoords]').attr('checked'); + $('#viewport .layer.grid')[(c.ui.showGridCoords ? 'add' : 'remove')+'Class']('showGridCoords'); } // Update performance info periodically @@ -263,6 +266,14 @@ function countdownToStart(n, fn){ tickDown(); } +function readyToStart(){ + $('#overlay').hide(); + $(document).bind('keydown', 'return', pauseGame); + toggleGame(); +} + + + -})(); +}).call(tanks.ui); diff --git a/tanks.php b/tanks.php index 6177a46..9a3054d 100644 --- a/tanks.php +++ b/tanks.php @@ -11,10 +11,11 @@ class Tanks { static $mainScripts = array( - "src/tanks/main.js" - // "src/tanks/main-ui.js" + "src/tanks/ui/main.js" ); + + static $srcScripts = array( "src/tanks/tanks.js", "src/tanks/globals.js", @@ -34,9 +35,11 @@ class Tanks { "src/tanks/ui/grid.js", - "src/tanks/game/game.js" + "src/tanks/game.js" ); + + static $libScripts = array( "lib/jquery-1.4.3.js", "lib/jquery.sparkline.min.js",