Fixes rect-line intersection.
authordsc <david.schoonover@gmail.com>
Wed, 24 Nov 2010 00:03:53 +0000 (16:03 -0800)
committerdsc <david.schoonover@gmail.com>
Wed, 24 Nov 2010 00:03:53 +0000 (16:03 -0800)
src/Y/y-array.js
src/portal/math/line.js
src/portal/shape/rect.js
src/tanks/map/loc.js
src/tanks/map/pathmap.js
src/tanks/map/trajectory.js
src/tanks/thing/tank.js
src/tanks/ui/grid.js
test/math/index.php
test/math/math.test.js

index 46fa261..7871abe 100644 (file)
@@ -85,7 +85,7 @@ YCollection.subclass('YArray', function(YArray){
     
     
     chainDelegates(YArray, 'push', 'unshift', 'sort', 'splice', 'reverse');
-    mixinNames(YArray, Array, ['reduce', 'map', 'forEach', 'filter', 'slice'],    true, true);
+    mixinNames(YArray, Array, ['reduce', 'map', 'forEach', 'filter', 'slice', 'some', 'every'],    true, true);
     mixinNames(YArray, Array, ['indexOf', 'lastIndexOf', 'shift', 'pop', 'join'], true, false);
     
     return this;
index 11734b8..237aaac 100644 (file)
@@ -10,7 +10,7 @@ COS_HALF_PI = Math.cos(HALF_PI);
 /**
  * A line in the cartesian plane.
  */
-math.Line = new Y.Class('Line', math.Vec, {
+math.Line = math.Vec.subclass('Line', {
     
     init : function initLine(x1,y1, x2,y2, tdist){
         this.x1 = x1; this.y1 = y1;
index 0d84e51..ea8ca8c 100644 (file)
@@ -1,5 +1,5 @@
 
-Rect = new Y.Class('Rect', Shape, {
+Rect = Shape.subclass('Rect', {
     _cssClasses : 'portal layer shape rect',
     
     init : function initRect(w,h){
@@ -23,3 +23,6 @@ Rect = new Y.Class('Rect', Shape, {
     }
     
 });
+Rect.fromPoints = function(x1,y1, x2,y2){
+    return new Rect(x2-x1, y2-y1).position(x1,y1);
+};
\ No newline at end of file
index 43453a9..6024481 100644 (file)
@@ -108,6 +108,13 @@ Loc.Rect = new Y.Class('Rect', [], {
             y2 = y1.y; x2 = y1.x;
             y1 = x1.y; x1 = x1.x;
         }
+    // 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;
+    //     }
+    //     var x1 = Math.min(_x1,_x2), x2 = Math.max(_x1,_x2)
+    //     ,   y1 = Math.min(_y1,_y2), y2 = Math.max(_y1,_y2);
         
         this.length = 4;
         this.x1 = this[0] = this.x = x1;
@@ -127,6 +134,16 @@ Loc.Rect = new Y.Class('Rect', [], {
                  y >= this.y1 && y <= this.y2  );
     },
     
+    intersects : function intersects(line){
+        var x1 = Math.min(this.x1,this.x2), x2 = Math.max(this.x1,this.x2)
+        ,   y1 = Math.min(this.y1,this.y2), y2 = Math.max(this.y1,this.y2)
+        ,   cx1,cy1, cx2,cy2 ;
+        return (  ( (cx1 = line.calcX(y1)) >= x1 && cx1 <= x2 )
+               || ( (cy1 = line.calcY(x1)) >= y1 && cy1 <= y2 )
+               || ( (cx2 = line.calcX(y2)) >= x1 && cx2 <= x2 )
+               || ( (cy2 = line.calcY(x2)) >= y1 && cy2 <= y2 ) );
+    },
+    
     midpoint : function midpoint(){
         return new Loc( this.x1 + this.width /2
                       , this.y1 + this.height/2 );
index 51be52e..665f2df 100644 (file)
@@ -18,7 +18,8 @@ PathMap = QuadTree.subclass('PathMap', {
     },
     
     setup : function setup(x1,y1, x2,y2){
-        var w = this.width, h = this.height, level = this.level
+        var w = this.width, h = this.height
+        ,   level = this.level
         
         ,   BWs = {
             top    : [x1,y1,   w,1, true],
@@ -30,6 +31,15 @@ PathMap = QuadTree.subclass('PathMap', {
         this.boundaryWalls = Y.map(BWs, 'this.level.addWall.apply(this.level, _)', this);
     },
     
+    wallObstructs : function wallObstructs(line, w,h){
+        return this.walls.some(function(wall){
+            var bb = wall.boundingBox
+            ,   ss = bb.sides ;
+            return ( line.calcY(bb.x1) >= bb.y1 && line.calcY(bb.x2) <= bb.y2 )
+                || ( line.calcX(bb.y1) >= bb.x1 && line.calcX(bb.y2) <= bb.x2 ) ;
+        }, this);
+    },
+    
     addBlocker : function addBlocker(obj){
         this.removeBlocker(obj);
         var bb = obj.boundingBox;
index 6b35eea..0521f90 100644 (file)
@@ -118,6 +118,24 @@ 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)+']';
index 1948e5f..1429cd2 100644 (file)
@@ -89,13 +89,12 @@ Tank = Thing.subclass('Tank', {
             }
             
             // Try to blow up nearby tanks
-            var t = this.findNearEnemies(66).shift();
+            var t = this.findNearEnemies(66, true).shift();
             if (t) {
                 // console.log('I gotcha!', t);
                 this.shoot(t.loc.x, t.loc.y);
                 return this;
             }
-            
         }
         
         // Nothing to shoot at? Move toward something
@@ -109,12 +108,12 @@ Tank = Thing.subclass('Tank', {
     },
     
     closestOf : function closestOf(agents){
-        if (!agents || !agents.size())
+        if ( !(agents && agents.size()) )
             return null;
         
         var manhattan = math.Vec.manhattan
-        ,   bb = this.boundingBox, mid = this.midpoint
-        ;
+        ,   bb = this.boundingBox, mid = this.midpoint ;
+        
         agents.sort(function(a,b){
             return Y.op.cmp(
                 manhattan(a.loc,mid),
@@ -208,8 +207,17 @@ Tank = Thing.subclass('Tank', {
         return this.game.pathmap.get(x1,y1, x2,y2).filter(fn, this);
     },
     
-    findNearEnemies : function findNearEnemies(ticks){
-        return this.findNearLike(ticks, 'Y.is(Tank, _) && _.align !== this.align');
+    findNearEnemies : function findNearEnemies(ticks, wallObs){
+        var bb  = this.boundingBox
+        ,   mid = this.midpoint
+        ,   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));
+        });
     },
     
     shoot : function shoot(x,y){
index ca98808..a055b95 100644 (file)
@@ -3,6 +3,8 @@ Grid = new Y.Class('Grid', Rect, {
     
     lineWidth : 0.5,
     strokeStyle : '#6E6E6E',
+    createTableGrid : true,
+    createCanvasGrid : true,
     
     
     init : function init(cols,rows, size){
@@ -13,46 +15,52 @@ Grid = new Y.Class('Grid', Rect, {
     },
     
     drawShape : function drawShape(ctx){
-        var tbody = $('<tbody/>')
-        ,   cols = this.cols, rows = this.rows
+        if (this.table)  this.table.remove();
+        // if (this.canvas) this.canvas.remove();
+        
+        var cols = this.cols, rows = this.rows
         ,   size = this.size
         ,   w    =  this.canvasWidth
         ,   h    =  this.canvasHeight
         ;
         
-        Y(0, rows).forEach(function(y){
-            var row = $('<tr class="row row'+y+'" />').appendTo(tbody);
-            Y(0, cols).forEach(function(x){
-                $('<td class="cell cell'+x+'_'+y+' col'+x+'">'+x+','+y+'</td>')
-                    .width(size).height(size)
-                    .appendTo(row);
+        if ( this.createTableGrid ) {
+            var tbody = $('<tbody/>');
+            Y(0, rows).forEach(function(y){
+                var row = $('<tr class="row row'+y+'" />').appendTo(tbody);
+                Y(0, cols).forEach(function(x){
+                    $('<td class="cell cell'+x+'_'+y+' col'+x+'">'+x+','+y+'</td>')
+                        .width(size).height(size)
+                        .appendTo(row);
+                }, this);
             }, this);
-        }, this);
-        
-        
-        this.table =
-            $('<table class="grid" cellspacing="0" cellpadding="0" />')
-                .width(this.layerWidth)
-                .height(this.layerHeight)
-                .append(tbody)
-                .prependTo( this.layer );
-        
-        // this.canvas.remove();
+            
+            this.table =
+                $('<table class="grid" cellspacing="0" cellpadding="0" />')
+                    .width(this.layerWidth)
+                    .height(this.layerHeight)
+                    .append(tbody)
+                    .prependTo( this.layer );
+            
+        } else
+            this.table = null;
         
-        ctx.lineWidth   = this.lineWidth;
-        ctx.strokeStyle = this.strokeStyle;
-        
-        for (var row=0, y=0; row<=rows; y = (++row) * size){
-            ctx.moveTo(0, y);
-            ctx.lineTo(w, y);
-        }
-        
-        for (var col=0, x=0; col<=cols; x = (++col) * size){
-            ctx.moveTo(x, 0);
-            ctx.lineTo(x, h);
+        if ( this.createCanvasGrid ) {
+            ctx.lineWidth   = this.lineWidth;
+            ctx.strokeStyle = this.strokeStyle;
+            
+            for (var row=0, y=0; row<=rows; y = (++row) * size){
+                ctx.moveTo(0, y);
+                ctx.lineTo(w, y);
+            }
+            
+            for (var col=0, x=0; col<=cols; x = (++col) * size){
+                ctx.moveTo(x, 0);
+                ctx.lineTo(x, h);
+            }
+            
+            ctx.stroke();
         }
-        
-        ctx.stroke();
     }
     
 });
\ No newline at end of file
index c4ea7f5..a96d3a3 100644 (file)
@@ -26,6 +26,7 @@ h1 { position:fixed; top:0; right:0; margin:0; padding:0; font-size:3em; color:#
 #info legend { color:#ccc; font-weight:bold; padding:0 0.5em; }
 #info input { width:3em; font-size:0.8em; padding:0.1em; text-align:center; background-color:rgba(0,0,0, 0.2); color:#ccc; border:0; }
 #info label { margin-right:1em; }
+#info pre { padding:0.5em; height:5em; font:12px monospace; background-color:rgba(0,0,0, 0.2); color:#ccc; border:0; }
 
 
 #howto { position:relative; width:600px; margin:1em auto; background-color:#D8D8D8; }
@@ -49,6 +50,7 @@ h1 { position:fixed; top:0; right:0; margin:0; padding:0; font-size:3em; color:#
             ( <input name="x2" value="" type="text">, <input name="y2" value="" type="text"> )
         <!--</fieldset>-->
         </form>
+        <pre id="inter"></pre>
     </div>
     
     <div id="howto" class="rounded">
index ce7c5a1..237ac71 100644 (file)
@@ -11,6 +11,7 @@ COLS = w/PPU; COLS2 = COLS/2;
 ROWS = h/PPU; ROWS2 = ROWS/2;
 
 grid = new Grid( COLS, ROWS, PPU ).appendTo(plot);
+grid.createTableGrid = false;
 grid.lineWidth = 1.0;
 grid.strokeStyle = '#E0E0E0'; //'#EEEEEE'; //
 grid.draw();
@@ -28,6 +29,13 @@ ctx = P.ctx;
 ctx.translate(w2, h2);
 ctx.scale(PPU, PPU);
 
+
+r = new Loc.Rect(2,6, 4,2);
+R = Rect.fromPoints(r.x1*PPU,-r.y1*PPU, r.x2*PPU,-r.y2*PPU)
+    .fill('rgba(131,187,50, 0.5)')
+    .appendTo(P);
+R.position(R.loc.x+w2, R.loc.y+h2);
+
 points = Y([]);
 line = mkLine(0,0, 2.3125,1);
 addPoint(-5,2);
@@ -42,6 +50,7 @@ P.layer.bind('click', function(evt){
     return false;
 });
 
+
 $('form#line, #line input').bind('submit blur', function(evt){
     var x1 = parseFloat($('#info [name=x1]').val())
     ,   y1 = parseFloat($('#info [name=y1]').val())
@@ -58,6 +67,7 @@ $('form#line, #line input').bind('submit blur', function(evt){
     return false;
 });
 
+
 });
 
 function updateInfo(){
@@ -65,6 +75,7 @@ function updateInfo(){
     $('#info [name=y1]').val(line.y1);
     $('#info [name=x2]').val(line.x2);
     $('#info [name=y2]').val(line.y2);
+    $('#info #inter').text([ 'rect:'+r, 'rect.intersects(line)? '+r.intersects(line) ].join('\n'));
 }
 
 function redraw(color){