Fixes pathing around corners in all cases.
authordsc <david.schoonover@gmail.com>
Fri, 24 Dec 2010 17:40:58 +0000 (09:40 -0800)
committerdsc <david.schoonover@gmail.com>
Fri, 24 Dec 2010 17:40:58 +0000 (09:40 -0800)
src/Y/types/chain.cjs
src/ezl/loc/boundingbox.cjs
src/ezl/math/vec.cjs
src/tanks/map/pathmap.cjs
src/tanks/map/traversal.cjs
src/tanks/thing/tank.cjs
src/tanks/thing/wall.cjs [new file with mode: 0644]
src/tanks/thing/zone.cjs [new file with mode: 0644]

index 98fc812..b13b46d 100644 (file)
@@ -6,3 +6,36 @@ var YCollection = require('Y/types/collection').YCollection
 ,   type        = require('Y/type')
 ;
 
+/*
+
+end
+clone
+
+set
+attr
+
+extend
+merge
+concat
+
+reduce
+map
+forEach
+filter
+
+indexOf
+has
+remove
+
+every
+any
+
+pluck
+invoke
+
+zip
+
+apply
+
+toString
+*/
\ No newline at end of file
index 82b39a1..2317789 100644 (file)
@@ -72,28 +72,46 @@ Rect.subclass('BoundingBox', {
     },
     
     /**
-     * Determines the point and line of intersection for the specified bounding boxes
-     * along the given trajectory.
+     * Determines the side of intersection for this bounding box given start-
+     * and end-points along the trajectory.
+     * @return {Line} Side of intersection or null if no collision is detected.
      */
-    // collision : function collision(trj, fromBB, toBB){
-    //     
-    //     if (bb.x2 <= B.x1 && x2 >= B.x1) {
-    //         side = B.leftSide;
-    //         to   = trj.pointAtX(B.x1-offX-1);
-    //         
-    //     } else if (bb.x1 >= B.x2 && x1 <= B.x2) {
-    //         side = B.rightSide;
-    //         to   = trj.pointAtX(B.x2+ro.x+1);
-    //         
-    //     } else if (bb.y2 <= B.y1 && y2 >= B.y1) {
-    //         side = B.topSide;
-    //         to   = trj.pointAtY(B.y1-offY-1);
-    //         
-    //     } else if (bb.y1 >= B.y2 && y1 <= B.y2) {
-    //         side = B.bottomSide;
-    //         to   = trj.pointAtY(B.y2+ro.y+1);
-    //     }
-    // },
+    collision : function collision(trj, from, to){
+        if (from.x2 <= this.x1 && to.x2 >= this.x1)
+            return this.leftSide;
+            
+        if (from.x1 >= this.x2 && to.x1 <= this.x2)
+            return this.rightSide;
+        
+        if (from.y2 <= this.y1 && to.y2 >= this.y1)
+            return this.topSide;
+        
+        if (from.y1 >= this.y2 && to.y1 <= this.y2)
+            return this.bottomSide;
+        
+        return null;
+    },
+    
+    /**
+     * Determines the furthest point before intersection between this bounding box
+     * and the box on given start- and end-points along the trajectory.
+     * @return {Vec} Furthest point or null if no collision is detected.
+     */
+    furthest : function furthest(trj, from, to){
+        if (from.x2 <= this.x1 && to.x2 >= this.x1)
+            return tr.pointAtX(this.x1 - 1 - from.originRight);
+            
+        if (from.x1 >= this.x2 && to.x1 <= this.x2)
+            return tr.pointAtX(this.x2 + 1 + from.originLeft);
+            
+        if (from.y2 <= this.y1 && to.y2 >= this.y1)
+            return tr.pointAtY(this.y1 - 1 - from.originTop);
+            
+        if (from.y1 >= this.y2 && to.y1 <= this.y2)
+            return tr.pointAtY(this.y2 + 1 + from.originBottom );
+        
+        return null;
+    },
     
     /**
      * Moves absolute location of the origin and retains its relative position of the bounds.
index 44cdb2a..00c88ff 100644 (file)
@@ -120,9 +120,9 @@ Y.extend(exports, {
         return a[_X]*b[_X] + a[_Y]*b[_Y];
     },
     
-    lerp : function lerp(x, a, b) {
-        return new Vec( lerp(a[_X], b[_X], x),
-                        lerp(a[_Y], b[_Y], x)  );
+    lerp : function vecLerp(x, a, b) {
+        return new Vec( lerp(x, a[_X], b[_X]),
+                        lerp(x, a[_Y], b[_Y])  );
     },
     
     manhattan: function manhattan(x1,y1, x2,y2) {
index 1d515ee..623cc21 100644 (file)
@@ -70,6 +70,20 @@ Map.subclass('PathMap', {
         this.boundaryWalls = Y.map(BWs, 'this.level.addWall.apply(this.level, _)', this);
     },
     
+    getBlockers : function getBlockers(x1,y1, x2,y2, ignore){
+        if (x1 && x1.x1 !== undefined) {
+            ignore = y1;
+            y2 = x1.y2;  x2 = x1.x2;
+            y1 = x1.y1;  x1 = x1.x1;
+        }
+        var bs = this.get(x1,y1, x2,y2)
+            .filter('_.blocking === 2'); // map.BLOCKING
+        if (ignore && bs.length)
+            return bs.remove.apply(bs, ignore || []);
+        else
+            return bs;
+    },
+    
     wallObstructs : function wallObstructs(line){
         return this.walls.some(function(wall){
             return wall.boundingBox.intersects(line);
@@ -131,14 +145,28 @@ Map.subclass('PathMap', {
             
             // End case -- result has been found, return the traced path
             if (current === end) {
-                var path = []
+                var path = Y([])
                 ,   mid  = this.gridSquareMid
                 ,   node = current;
                 while( node.prev ) {
                     path.push( vec.sum(node,mid) );
                     node = node.prev;
                 }
-                return Y(path.reverse());
+                
+                if (!path.length)
+                    return path;
+                
+                path = Y(path.reverse());
+                
+                // Ensure we don't get stuck on a corner on our first step
+                var first = path.first()
+                ,   bb = agent.boundingBox.relocated( vec.lerp(0.5, agent.loc,first) )
+                ,   blockers = this.getBlockers(bb, [agent]);
+                
+                if (blockers.length)
+                    path.unshift( vec.sum(start,mid) );
+                
+                return path;
             }
             
             // Normal case -- move current from open to closed, process each of its neighbors
@@ -183,19 +211,19 @@ Map.subclass('PathMap', {
         }
         
         // No result was found -- empty array signifies failure to find path
-        return [];
+        return Y([]);
     },
     
     vec2Square : function vec2Square(x,y){
         if (x instanceof Array){ y = x.y; x = x.x; }
-        var floor = Math.floor, size = this.gridSquare;
-        return new Vec(floor(x/size), floor(y/size));
+        var floor = Math.floor, SIZE = this.gridSquare;
+        return new Vec(floor(x/SIZE), floor(y/SIZE));
     },
     
     square2Vec : function square2Vec(x,y){
         if (x instanceof Array){ y = x.y; x = x.x; }
-        var floor = Math.floor, size = this.gridSquare;
-        return new Vec(floor(x)*size, floor(y)*size);
+        var floor = Math.floor, SIZE = this.gridSquare;
+        return new Vec(floor(x)*SIZE, floor(y)*SIZE);
     }
     
 })
index 40001c8..4316d32 100644 (file)
@@ -41,6 +41,7 @@ Y.subclass('Traversal', {
      * Checks for blockers and moves traversal bounds forward as much as possible.
      */
     step : function step(tx,ty){
+        this.start = this.bbox.clone();
         var tr = this.trajectory
         ,   or = this.thing.loc
         ,   dt = Math.min(tr.tBound, this.remaining)
@@ -117,25 +118,26 @@ Y.subclass('Traversal', {
     },
     
     rewind : function rewind(blocker){
-        var tr = this.trajectory, bb = this.bbox
+        var tr = this.trajectory
+        ,   bb = this.bbox, st = this.start
         ,   B = blocker.boundingBox
         ,   to = this.to ;
         
         // Figure out which boundary of the blocker we crossed and calculate
         // the furthest non-overlapping point.
-        if (bb.x2 <= B.x1 && bb.x2 >= B.x1) {
+        if (st.x2 <= B.x1 && bb.x2 >= B.x1) {
             this.side = B.leftSide;
             to = tr.pointAtX(B.x1 - 1 - bb.originRight);
             
-        } else if (bb.x1 >= B.x2 && bb.x1 <= B.x2) {
+        } else if (st.x1 >= B.x2 && bb.x1 <= B.x2) {
             this.side = B.rightSide;
             to = tr.pointAtX(B.x2 + 1 + bb.originLeft);
             
-        } else if (bb.y2 <= B.y1 && bb.y2 >= B.y1) {
+        } else if (st.y2 <= B.y1 && bb.y2 >= B.y1) {
             this.side = B.topSide;
             to = tr.pointAtY(B.y1 - 1 - bb.originTop);
             
-        } else if (bb.y1 >= B.y2 && bb.y1 <= B.y2) {
+        } else if (st.y1 >= B.y2 && bb.y1 <= B.y2) {
             this.side = B.bottomSide;
             to = tr.pointAtY(B.y2 + 1 + bb.originBottom );
             
index 2c60493..939536d 100644 (file)
@@ -84,8 +84,8 @@ Thing.subclass('Tank', function(Tank){
         this.elapsed = elapsed;
         this.now = now;
         
-        this.continueMove();
-        return;
+        // this.continueMove();
+        // return;
         
         // Check to see if we should obey our last decision, and not recalc
         if (this.forceCurrentMove && this.forceCurrentMove() && this.currentMoveLimit > now) {
@@ -193,7 +193,7 @@ Thing.subclass('Tank', function(Tank){
         ,   path  = this.currentPath = pm.path(this, end)
         ,   to    = this.currentMove = path.shift()
         ;
-        console.log('calculatePath()', start, 'toward:', end, 'next:', this.currentMove, 'path: ['+path.invoke('toString')+']');
+        // console.log('calculatePath()', start, 'toward:', end, 'next:', this.currentMove, 'path: '+path.invoke('toString'));
     };
     
     
diff --git a/src/tanks/thing/wall.cjs b/src/tanks/thing/wall.cjs
new file mode 100644 (file)
index 0000000..781a991
--- /dev/null
@@ -0,0 +1,73 @@
+var Y     = require('Y').Y
+,   op    = require('Y/op')
+,   Rect  = require('ezl/shape').Rect
+,   Thing = require('tanks/thing/thing').Thing
+,   map   = require('tanks/map/map')
+,
+
+
+Wall =
+exports['Wall'] =
+Thing.subclass('Wall', {
+    blocking : map.BLOCKING,
+    active   : false,
+    
+    originX : 0,
+    originY : 0,
+    
+    stats : {
+        hp    : Infinity,
+        move  : 0,
+        power : 0,
+        speed : 0,
+        shots : 0
+    },
+    
+    isBoundary : false,
+    
+    
+    
+    init : function initWall(x,y, w,h, isBoundary){
+        this.width = w;
+        this.height = h;
+        this.isBoundary = !!isBoundary;
+        Thing.init.call(this);
+        this.position(x,y);
+    },
+    
+    // inactive
+    createCooldowns : op.nop,
+    
+    // indestructable
+    dealDamage : op.nop,
+    
+    
+    render : function render(parent){
+        if (this.isBoundary)
+            return this;
+        
+        if (this.shape)
+            this.shape.remove();
+        
+        this.shape =
+            new Rect(this.width, this.height)
+                .position(this.loc.x, this.loc.y)
+                .fill('rgba(255,255,255, 0.25)')
+                .appendTo( parent );
+        
+        return this;
+    },
+    
+    toString : function(){
+        var bb = this.boundingBox
+        ,   x1,y1, x2,y2;
+        if (bb){
+            x1 = bb.x1; y1 = bb.y1;
+            x2 = bb.x2; y2 = bb.y2;
+        } else {
+            x1=y1=x2=y2=NaN;
+        }
+        return this.className+'['+x1+','+y1+', '+x2+','+y2+'](w='+this.width+', h='+this.height+')';
+    }
+});
+
diff --git a/src/tanks/thing/zone.cjs b/src/tanks/thing/zone.cjs
new file mode 100644 (file)
index 0000000..e69de29