Fixes teleporting bullet issue.
authordsc <david.schoonover@gmail.com>
Wed, 17 Nov 2010 06:55:09 +0000 (22:55 -0800)
committerdsc <david.schoonover@gmail.com>
Wed, 17 Nov 2010 06:55:09 +0000 (22:55 -0800)
16 files changed:
notes.md
src/portal/layer.js
src/portal/math/line.js
src/portal/math/math.js
src/portal/math/oldline.js [new file with mode: 0644]
src/portal/util/tree/quadtree.js
src/tanks/config.js
src/tanks/main-ui.js [deleted file]
src/tanks/main.js
src/tanks/map/collision.js [new file with mode: 0644]
src/tanks/map/loc.js
src/tanks/map/pathmap.js
src/tanks/map/trajectory.js [new file with mode: 0644]
src/tanks/thing/bullet.js
src/tanks/thing/thing.js
tanks.php

index fcc68f9..4961760 100644 (file)
--- a/notes.md
+++ b/notes.md
@@ -9,6 +9,7 @@
 # TODOs
 - Move game objects into namespace `tanks`
 - Move portal into namespace (ideas: `portal`, canvas tools... `easel`, or `ezl`)
+- Classes should have generalize()-ed version of instance methods on them.
 
 
 # Notes
index a3e2523..ebf2f50 100644 (file)
@@ -43,7 +43,7 @@ Layer = new Y.Class('Layer', {
         this.negBleed = new Loc(0,0);
         this.posBleed = new Loc(0,0);
         
-        this.boundingBox = new Loc.Rect(0,0, 0,0);
+        this.boundingBox = new Loc.BoundingBox(0,0, 0,0);
         
         this.transform = {
             origin    : new Loc('50%','50%'), // rotational origin
@@ -348,9 +348,13 @@ Layer = new Y.Class('Layer', {
     
     invoke : function invoke(name){
         var args = Y(arguments,1);
-        
+        // this[name].apply(this, args);
+        // this.children.invoke.apply(this.children, ['invoke', name].concat(args));
+        return this._invoke(name, args);
+    },
+    _invoke : function _invoke(name, args){
         this[name].apply(this, args);
-        this.children.invoke.apply(this.children, ['invoke', name].concat(args));
+        this.children.invoke('_invoke', name, args);
         return this;
     },
     
index e213436..e6b5172 100644 (file)
@@ -1,6 +1,7 @@
 (function(){
 
-var 
+var
+Vec = math.Vec,
 HALF_PI = Math.PI/2,
 SIN_HALF_PI = Math.sin(HALF_PI),
 COS_HALF_PI = Math.cos(HALF_PI);
@@ -11,21 +12,23 @@ COS_HALF_PI = Math.cos(HALF_PI);
  */
 math.Line = new Y.Class('Line', math.Vec, {
     
-    init : function init(x1,y1, x2,y2, tdist){
+    init : function initLine(x1,y1, x2,y2, tdist){
         this.x1 = x1; this.y1 = y1;
         this.x2 = x2; this.y2 = y2;
         
-        var xdelta = x2-x1, ydelta = y2-y1
-        ,    m = this.slope  =  ydelta/xdelta
+        var x0 = x2-x1
+        ,   y0 = y2-y1
+        
+        ,    m = this.slope  =  y0/x0
         ,   yi = this.yint   = -x1*m + y1
         ,   xi = this.xint   = -y1/m + x1
         ;
-        math.Vec.init.call(this, xdelta, ydelta);
+        math.Vec.init.call(this, x0,y0);
         
         this.p1 = new math.Vec(x1,y1);
         this.p2 = new math.Vec(x2,y2);
         
-        this.theta = Math.atan2(ydelta, xdelta);
+        this.theta = Math.atan2(y0, x0);
         this._cos  = Math.cos(this.theta);
         this._sin  = Math.sin(this.theta);
         
@@ -36,32 +39,7 @@ math.Line = new Y.Class('Line', math.Vec, {
         return new math.Line(this.x1,this.y1, this.x2,this.y2, this.tdist);
     },
     
-    equals : function equals(line){
-        return ( this.slope === line.slope
-            && this.x1 === line.x1 && this.y1 === line.y1
-            && this.x2 === line.x2 && this.y2 === line.y2 );
-    },
     
-    intersects : function intersects(x,y){
-        var o = x;
-        if (o instanceof math.Line)
-            return this.slope !== o.slope || this.equals(o);
-        
-        if (o instanceof math.Vec) {
-            x = o.x;
-            y = o.y;
-        }
-        return this.calcY(x) === y;
-    },
-    
-    isWithin : function isWithin(pt, w,h){
-        if ( !Y.isNumber(w) ){
-            h = w.height; w = w.width;
-        }
-        var dw = Math.abs(this.calcX(pt.y) - pt.x)
-        ,   dh = Math.abs(this.calcY(pt.x) - pt.y) ;
-        return dw <= w || dh <= h ;
-    },
     
     setTScale : function setTScale(tdist){
         if (tdist) {
@@ -81,13 +59,10 @@ math.Line = new Y.Class('Line', math.Vec, {
                              this.y1 + t*this.pb );
     },
     
-    pointAtX : function pointAtX(x){
-        return new math.Vec(x, this.calcY(x));
-    },
-    
-    pointAtY : function pointAtY(y){
-        return new math.Vec(this.calcX(y), y);
-    },
+    pointAtX : function pointAtX(x){ return new math.Vec(x, this.calcY(x)); },
+    pointAtY : function pointAtY(y){ return new math.Vec(this.calcX(y), y); },
+    calcY : function calcY(x){ return (x === this.xint ? 0 : x*this.slope + this.yint); },
+    calcX : function calcX(y){ return (y === this.yint ? 0 : y/this.slope + this.xint); },
     
     near : function near(x,y){
         if ( !isFinite(this.slope) )
@@ -96,12 +71,39 @@ math.Line = new Y.Class('Line', math.Vec, {
             return this.pointAtX(x);
     },
     
-    calcY : function calcY(x){
-        return (x === this.xint ? 0 : x*this.slope + this.yint);
+    
+    
+    equals : function equals(line){
+        return ( this.slope === line.slope
+            && this.x1 === line.x1 && this.y1 === line.y1
+            && this.x2 === line.x2 && this.y2 === line.y2 );
     },
     
-    calcX : function calcX(y){
-        return (y === this.yint ? 0 : y/this.slope + this.xint);
+    intersects : function intersects(x,y){
+        var o = x;
+        if (o instanceof math.Line)
+            return this.slope !== o.slope || this.equals(o);
+        
+        if (o instanceof math.Vec) {
+            x = o.x;
+            y = o.y;
+        }
+        return this.calcY(x) === y;
+    },
+    
+    isWithin : function isWithin(pt, w,h){
+        if ( !Y.isNumber(w) ){
+            h = w.height; w = w.width;
+        }
+        var dw = Math.abs(this.calcX(pt.y) - pt.x)
+        ,   dh = Math.abs(this.calcY(pt.x) - pt.y) ;
+        return dw <= w || dh <= h ;
+    },
+    
+    
+    
+    vec : function vec(){
+        return new math.Vec(this.x, this.y); // reset to vector from origin
     },
     
     base : function base(){
index bb8a8a1..882cdbb 100644 (file)
@@ -10,7 +10,7 @@ math = {
     reflect : function reflect(v, line){
         var dot   = math.Vec.dot
         ,   basev = math.Vec.difference(v, line.p1);
-        return new math.Vec(line.x, line.y)
+        return line.vec()
             .scale(2 * dot(basev,line) / dot(line,line))
             .subtract(basev)
             .add(line.p1);
diff --git a/src/portal/math/oldline.js b/src/portal/math/oldline.js
new file mode 100644 (file)
index 0000000..b13b4bf
--- /dev/null
@@ -0,0 +1,134 @@
+(function(){
+
+var 
+HALF_PI = Math.PI/2,
+SIN_HALF_PI = Math.sin(HALF_PI),
+COS_HALF_PI = Math.cos(HALF_PI);
+
+
+/**
+ * A line in the cartesian plane.
+ */
+math.Line = new Y.Class('Line', math.Vec, {
+    
+    init : function initLine(x1,y1, x2,y2, tdist){
+        this.x1 = x1; this.y1 = y1;
+        this.x2 = x2; this.y2 = y2;
+        
+        var xdelta = x2-x1, ydelta = y2-y1
+        ,    m = this.slope  =  ydelta/xdelta
+        ,   yi = this.yint   = -x1*m + y1
+        ,   xi = this.xint   = -y1/m + x1
+        ;
+        math.Vec.init.call(this, xdelta, ydelta);
+        
+        this.p1 = new math.Vec(x1,y1);
+        this.p2 = new math.Vec(x2,y2);
+        
+        this.theta = Math.atan2(ydelta, xdelta);
+        this._cos  = Math.cos(this.theta);
+        this._sin  = Math.sin(this.theta);
+        
+        this.setTScale(tdist);
+    },
+    
+    clone : function clone(){
+        return new math.Line(this.x1,this.y1, this.x2,this.y2, this.tdist);
+    },
+    
+    equals : function equals(line){
+        return ( this.slope === line.slope
+            && this.x1 === line.x1 && this.y1 === line.y1
+            && this.x2 === line.x2 && this.y2 === line.y2 );
+    },
+    
+    intersects : function intersects(x,y){
+        var o = x;
+        if (o instanceof math.Line)
+            return this.slope !== o.slope || this.equals(o);
+        
+        if (o instanceof math.Vec) {
+            x = o.x;
+            y = o.y;
+        }
+        return this.calcY(x) === y;
+    },
+    
+    isWithin : function isWithin(pt, w,h){
+        if ( !Y.isNumber(w) ){
+            h = w.height; w = w.width;
+        }
+        var dw = Math.abs(this.calcX(pt.y) - pt.x)
+        ,   dh = Math.abs(this.calcY(pt.x) - pt.y) ;
+        return dw <= w || dh <= h ;
+    },
+    
+    setTScale : function setTScale(tdist){
+        if (tdist) {
+            this.tdist = tdist;
+            this.pa = tdist * this._cos;
+            this.pb = tdist * this._sin;
+        } else {
+            this.tdist = this.y / this._sin;
+            this.pa = this.x;
+            this.pb = this.y;
+        }
+        return this;
+    },
+    
+    parametric : function parametric(t){
+        return new math.Vec( this.x1 + t*this.pa ,
+                             this.y1 + t*this.pb );
+    },
+    
+    pointAtX : function pointAtX(x){
+        return new math.Vec(x, this.calcY(x));
+    },
+    
+    pointAtY : function pointAtY(y){
+        return new math.Vec(this.calcX(y), y);
+    },
+    
+    near : function near(x,y){
+        if ( !isFinite(this.slope) )
+            return this.pointAtY(y);
+        else
+            return this.pointAtX(x);
+    },
+    
+    calcY : function calcY(x){
+        return (x === this.xint ? 0 : x*this.slope + this.yint);
+    },
+    
+    calcX : function calcX(y){
+        return (y === this.yint ? 0 : y/this.slope + this.xint);
+    },
+    
+    base : function base(){
+        if (!this._base)
+            this._base = new math.Line(0,0, this.x,this.y);
+        return this._base;
+    },
+    
+    tangent : function tangent(at){
+        var slope = this.slope;
+        
+        if ( slope === 0 )
+            return new math.Line(at.x,at.y, at.x,at.y+1, this.tdist);
+        
+        if ( !isFinite(slope) )
+            return new math.Line(at.x,at.y, at.x+1,at.y, this.tdist);
+        
+        var x1 = at.x, y1 = at.y
+        ,   x2 = at.x - at.y + (at.y !== this.y1 ? this.y1 : this.y2)
+        ,   y2 = at.y + at.x - (at.x !== this.x1 ? this.x1 : this.x2) ;
+        return new math.Line(x1,y1, x2,y2, this.tdist);
+    },
+    
+    toString : function toString(){
+        return '['+this.p1+', '+this.p2+', slope='+this.slope.toFixed(3)+']';
+    }
+    
+});
+
+})();
\ No newline at end of file
index 47b9fa7..d1ac1c8 100644 (file)
@@ -10,6 +10,16 @@ function Rect(x1,y1, x2,y2){
     this.width  = lg_x-sm_x;
     this.height = lg_y-sm_y;
 }
+function rectToString(o){
+    var p = 2
+    ,   x1 = o.x1, y1 = o.y1
+    ,   x2 = o.x2, y2 = o.y2 ;
+    x1 = ((x1 % 1 !== 0) ? x1.toFixed(p) : x1);
+    y1 = ((y1 % 1 !== 0) ? y1.toFixed(p) : y1);
+    x2 = ((x2 % 1 !== 0) ? x2.toFixed(p) : x2);
+    y2 = ((y2 % 1 !== 0) ? y2.toFixed(p) : y2);
+    return '['+x1+','+y1+', '+x2+','+y2+']';
+}
 
 var
 CAPACITY  = 8,
@@ -29,7 +39,7 @@ Region = new Y.Class('Region', {
     },
     
     toString : function toString(){
-        return this.className+'(id='+this.id+', value='+this.value+')';
+        return this.className+'(id='+this.id+', rect='+rectToString(this)+', value='+this.value+')';
     }
 }),
 
@@ -71,6 +81,28 @@ QuadTree = new Y.Class('QuadTree', {
         return acc;
     },
     
+    // _get : function _get(_x1,_y1, _x2,_y2, values){
+    //     var self = this
+    //     ,   cxt = context || self
+    //     ,   x1 = Math.min(_x1,_x2), x2 = Math.max(_x1,_x2)
+    //     ,   y1 = Math.min(_y1,_y2), y2 = Math.max(_y1,_y2) ;
+    //     
+    //     if ( !self.overlaps(x1,y1, x2,y2) )
+    //         return acc;
+    //     
+    //     // Implies this is a leaf: check its values
+    //     if ( self.regions ) acc = fn.call(cxt, acc, self.regions, self, self);
+    //     
+    //     // Recurse into any children -- Note we do not place this in an else-block,
+    //     // as mutation during the above call might cause the tree to split.
+    //     if (self.nw) acc = self.nw.leaves(x1,y1, x2,y2, fn, acc, context);
+    //     if (self.ne) acc = self.ne.leaves(x1,y1, x2,y2, fn, acc, context);
+    //     if (self.sw) acc = self.sw.leaves(x1,y1, x2,y2, fn, acc, context);
+    //     if (self.se) acc = self.se.leaves(x1,y1, x2,y2, fn, acc, context);
+    //     
+    //     return acc;
+    // },
+    
     set : function set(x1,y1, x2,y2, value){
         return this._set(new Region(x1,y1, x2,y2, value));
     },
index b1b958f..7092331 100644 (file)
@@ -1,6 +1,10 @@
+//  -*- mode: JavaScript; tab-width: 4; indent-tabs-mode: nil; -*-
 tanks.config = {
     pathing : { 
         overlayPathmap    : false,
-        traceTrajectories : false
+        traceTrajectories : true
+    },
+    debug : {
+        projectiles : 1
     }
 };
\ No newline at end of file
diff --git a/src/tanks/main-ui.js b/src/tanks/main-ui.js
deleted file mode 100644 (file)
index c0f014e..0000000
+++ /dev/null
@@ -1,149 +0,0 @@
-
-// Set up UI listeners
-function setupUI(){
-    spark = LBT.loop.spark = new FpsSparkline(LBT.loop, '.fps-sparkline', 0,0);
-    
-    initConfig();
-    $('#config input').bind('change', updateConfig);
-    
-    btank = new Tank(0);
-    btank.act = function(){ return this; };
-    LBT.addUnit(btank, 0,0);
-    LBT.pathmap.removeBlocker(btank);
-    btank.shape.hide();
-    
-    LBT.root.draw();
-    
-    // Start button (click or return key)
-    $(document).bind('keydown', 'return', toggleGame);
-    $(document).bind('keydown', 'ctrl+o', toggleOverlay);
-    
-    $('#bullets').bind('blur', function(evt){
-        var n = parseInt($('#bullets').val() || 0);
-        updateBullets(n);
-    });
-    
-    $('#bullets').blur();
-    
-    LBT.root.draw();
-    setInterval(updateInfo, 1000);
-    
-    // Start the simulation!
-    // toggleGame();
-    updateInfo();
-    
-    // Fix grid-size on resize
-    // $(window).bind('resize', resizeGame);
-}
-
-function initConfig(){
-    var p = tanks.config.pathing;
-    $('#config [name=pathmap]').attr('checked', p.overlayPathmap);
-    $('#config [name=trajectories]').attr('checked', p.traceTrajectories);
-}
-
-function updateConfig(evt){
-    var p = tanks.config.pathing;
-    p.overlayPathmap = $('#config [name=pathmap]').attr('checked');
-    p.traceTrajectories = $('#config [name=trajectories]').attr('checked');
-}
-
-var BULLETS = new Y.YArray();
-
-function spawnBullet(x,y, atX,atY){
-    if (x === undefined && y === undefined) {
-        var loc = randOpenLoc();
-        x = loc.x; y = loc.y;
-    }
-    if (atX === undefined && atY === undefined) do {
-        atX = rand(0,COLUMNS*REF_SIZE);
-        atY = rand(0,ROWS*REF_SIZE);
-    } while ( atX === x && atY === y);
-    
-    btank.setLocation(x,y);
-    return btank.fireProjectile(atX,atY);
-}
-
-function updateBullets(n){
-    if ( !Y.isNumber(n) || isNaN(n) || n === BULLETS.size() ) return;
-    
-    while (n < BULLETS.size()) {
-        var i = Math.round(rand(0, BULLETS.size()-1));
-        BULLETS.remove( BULLETS.attr(i).remove() );
-    }
-    
-    while (n > BULLETS.size())
-        BULLETS.push(spawnBullet());
-}
-
-function rand(a,b){ return a + Math.random()*(b-a); }
-function randOpenLoc(){
-    do {
-        var x = rand(0,COLUMNS*REF_SIZE)
-        ,   y = rand(0,ROWS*REF_SIZE);
-    } while ( LBT.pathmap.get(x,y, x+6,y+6).size() );
-    return new math.Vec(x,y);
-}
-
-
-
-// Update performance info periodically
-function updateInfo(){
-    var loop = LBT.loop
-    ,   fps = loop.fps()
-    ,   n_units = LBT.units.size()
-    ,   n_projs = LBT.bullets.size()
-    ;
-    
-    $('#info [name=fps]').val( fps.toFixed(2) + " / " + loop.framerate );
-    $('#info [name=frame]').val( loop.frametime().toFixed(3)+" ms" );
-    $('#info #state').text( loop.running ? 'Running!' : ('Paused (tick '+TICKS+')') );
-    
-    $('#info [name=objects]').val( n_units+n_projs );
-    $('#info [name=units]').val( n_units );
-    $('#info [name=bullets]').val( n_projs );
-    
-    spark.drawTimes();
-    
-    return false;
-}
-
-function toggleGame(evt){
-    if (LBT.loop.running)
-        LBT.stop();
-    else
-        LBT.start();
-    
-    updateInfo();
-}
-
-function toggleOverlay(evt){
-    LBT.showOverlay = !(LBT.showOverlay);
-}
-
-function resizeGame(evt){
-    LBT.resize(evt);
-    
-    if (!LBT.loop.running) {
-        LBT.start();
-        LBT.stop();
-    }
-}
-
-// function initUki(){
-//     uki({ view:'Box', rect:'0 0 250 500', anchor:'top width', className:'box', childViews:[
-//         { view:'Box', rect:'8 8 250 0', anchor:'top width height', childViews:[
-//             { view:'HFlow', rect:'250 25', anchor:'width', childViews:[
-//                 { view:'Label', rect:'200 25', anchor:'top left', text:'Bullets' },
-//                 { view:'TextField', rect:'50 25', anchor:'top right', name:'bullets', value:'10', background:'' }
-//             ]}
-//         ]}
-//     ]})
-//     .attachTo(
-//         $('<div/>').css({
-//             'position':'relative',
-//             'width':'100%',
-//             'top':0, 'left':0
-//         }).appendTo('#controls')[0], '0 0');
-//     // .attachTo(window, '10 10');
-// }
index 5ed561d..3d3035b 100644 (file)
@@ -1,12 +1,21 @@
+var btank   = null
+,   bullets = new Y.YArray()
+;
+
+
+(function(){
+
 jQuery(main);
 
+
 function main(){
-    v = $('#viewport');
+    var v = $('#viewport')
+    ,   sq = REF_SIZE
+    ;
+    
     LBT = new tanks.Game();
     ctx = LBT.level.ctx;
     
-    
-    var sq = REF_SIZE;
     LBT.level.append(
         new Wall(6*sq,1*sq, 1*sq,4*sq),
         new Wall(6*sq,7*sq, 1*sq,2*sq),
@@ -15,8 +24,174 @@ function main(){
     );
     
     T = LBT.addUnit(new Tank(0), 1,2);
-    P = new Player(LBT, T);
+    new Player(LBT, T);
     
     setupUI();
+    B = bullets.attr(0);
+    T = B.trajectory;
+}
+
+
+// Set up UI listeners
+function setupUI(){
+    LBT.loop.spark = new FpsSparkline(LBT.loop, '.fps-sparkline', 0,0);
+    
+    btank = new Tank(0);
+    btank.act = function(){ return this; };
+    LBT.addUnit(btank, 0,0);
+    LBT.pathmap.removeBlocker(btank);
+    btank.shape.hide();
+    
+    initConfig();
+    $('#config input').bind('change', updateConfig);
+    
+    LBT.root.draw();
+    
+    // Start button (click or return key)
+    $(document).bind('keydown', 'return', toggleGame);
+    $(document).bind('keydown', 'ctrl+o', toggleOverlay);
+    
+    $('#bullets').bind('blur', function(evt){
+        var n = parseInt($('#bullets').val() || 0);
+        updateBullets(n);
+    });
+    
+    LBT.root.draw();
+    setInterval(updateInfo, 1000);
+    
+    // Start the simulation!
+    // toggleGame();
+    updateInfo();
+    
+    // Fix grid-size on resize
+    // $(window).bind('resize', resizeGame);
+}
+
+
+
+function toggleGame(evt){
+    if (LBT.loop.running)
+        LBT.stop();
+    else
+        LBT.start();
+    
+    updateInfo();
+}
+
+function toggleOverlay(evt){
+    LBT.showOverlay = !(LBT.showOverlay);
 }
 
+function resizeGame(evt){
+    LBT.resize(evt);
+    
+    if (!LBT.loop.running) {
+        LBT.start();
+        LBT.stop();
+    }
+}
+
+
+function initConfig(){
+    var c = tanks.config, p = c.pathing;
+    
+    $('#config [name=pathmap]').attr('checked', p.overlayPathmap);
+    $('#config [name=trajectories]').attr('checked', p.traceTrajectories);
+    
+    $('#config [name=bullets]').val(c.debug.projectiles);
+    updateBullets( c.debug.projectiles );
+}
+
+function updateConfig(evt){
+    var p = tanks.config.pathing;
+    p.overlayPathmap = $('#config [name=pathmap]').attr('checked');
+    p.traceTrajectories = $('#config [name=trajectories]').attr('checked');
+}
+
+function spawnBullet(x,y, atX,atY){
+    if (x === undefined && y === undefined) {
+        var loc = randOpenLoc();
+        x = loc.x; y = loc.y;
+    }
+    if (atX === undefined && atY === undefined) do {
+        atX = rand(0,COLUMNS*REF_SIZE);
+        atY = rand(0,ROWS*REF_SIZE);
+    } while ( atX === x && atY === y);
+    
+    btank.setLocation(x,y);
+    return btank.fireProjectile(atX,atY);
+}
+
+function updateBullets(n){
+    if ( !Y.isNumber(n) || isNaN(n) || n === bullets.size() ) return;
+    
+    while (n < bullets.size()) {
+        var i = Math.round(rand(0, bullets.size()-1));
+        bullets.remove( bullets.attr(i).remove() );
+    }
+    
+    while (n > bullets.size())
+        bullets.push(spawnBullet());
+}
+
+function rand(a,b){ return a + Math.random()*(b-a); }
+function randOpenLoc(){
+    do {
+        var x = rand(0,COLUMNS*REF_SIZE)
+        ,   y = rand(0,ROWS*REF_SIZE);
+    } while ( LBT.pathmap.get(x,y, x+6,y+6).size() );
+    return new math.Vec(x,y);
+}
+
+
+
+// Update performance info periodically
+function updateInfo(){
+    var loop = LBT.loop
+    ,   fps = loop.fps()
+    ,   n_units = LBT.units.size()
+    ,   n_projs = LBT.bullets.size()
+    ;
+    
+    $('#info [name=fps]').val( fps.toFixed(2) + " / " + loop.framerate );
+    $('#info [name=frame]').val( loop.frametime().toFixed(3)+" ms" );
+    $('#info #state').text( loop.running ? 'Running!' : ('Paused (tick '+TICKS+')') );
+    
+    $('#info [name=objects]').val( n_units+n_projs );
+    $('#info [name=units]').val( n_units );
+    $('#info [name=bullets]').val( n_projs );
+    
+    loop.spark.drawTimes();
+    
+    return false;
+}
+
+
+// function initUki(){
+//     uki({ view:'Box', rect:'0 0 250 500', anchor:'top width', className:'box', childViews:[
+//         { view:'Box', rect:'8 8 250 0', anchor:'top width height', childViews:[
+//             { view:'HFlow', rect:'250 25', anchor:'width', childViews:[
+//                 { view:'Label', rect:'200 25', anchor:'top left', text:'Bullets' },
+//                 { view:'TextField', rect:'50 25', anchor:'top right', name:'bullets', value:'10', background:'' }
+//             ]}
+//         ]}
+//     ]})
+//     .attachTo(
+//         $('<div/>').css({
+//             'position':'relative',
+//             'width':'100%',
+//             'top':0, 'left':0
+//         }).appendTo('#controls')[0], '0 0');
+//     // .attachTo(window, '10 10');
+// }
+
+})();
+
+function dumpPathmap(){
+    var pm = LBT.pathmap;
+    console.warn(new Date(), pm);
+    pm.collect(pm.x1,pm.y1, pm.x2,pm.y2, function(acc, v, r){
+        console.log(r+'');
+    });
+    console.log(' ');
+}
diff --git a/src/tanks/map/collision.js b/src/tanks/map/collision.js
new file mode 100644 (file)
index 0000000..b1694f2
--- /dev/null
@@ -0,0 +1,5 @@
+Collision = new Y.Class('Collision', {
+    
+    
+    
+});
\ No newline at end of file
index ae77649..edc840a 100644 (file)
@@ -1,5 +1,5 @@
 // [x,y]
-Loc = new Y.Class('Loc', math.Vec, {
+Loc = new Y.Class('Loc', new math.Vec(0,0), {
     
     // init : function init(x,y){
     //     math.Vec.init.call(this, x,y);
@@ -93,10 +93,10 @@ Y(Loc).extend({
     
 });
 
-
 // [x1,y1, x2,y2]
 Loc.Rect = new Y.Class('Rect', [], {
-    init : function init(x1,y1, x2,y2){
+    
+    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;
@@ -113,6 +113,31 @@ Loc.Rect = new Y.Class('Rect', [], {
         
         this.p1 = new Loc(x1,y1);
         this.p2 = new Loc(x2,y2);
+    },
+    
+    contains : function contains(x,y){
+        return ( x >= this.x1 && x <= this.x2  &&
+                 y >= this.y1 && y <= this.y2  );
+    },
+    
+    midpoint : function midpoint(){
+        return new Loc( this.x1 + this.width /2
+                      , this.y1 + this.height/2 );
+    },
+    
+    clone : function clone(){
+        return new Loc.Rect( this.p1.clone()
+                           , this.p2.clone() );
+    },
+    
+    toString : function toString(){
+        return '['+this.p1+' '+this.p2+']';
+    }
+});
+
+Loc.BoundingBox = new Y.Class('BoundingBox', Loc.Rect, {
+    init : function initBoundingBox(x1,y1, x2,y2){
+        Loc.Rect.init.call(this, x1,y1, x2,y2);
         
         this.sides = {
             top    : new math.Line(x1,y1, x2,y1),
@@ -162,36 +187,21 @@ Loc.Rect = new Y.Class