Pathing refactor complete.
authordsc <david.schoonover@gmail.com>
Tue, 11 Jan 2011 07:41:19 +0000 (23:41 -0800)
committerdsc <david.schoonover@gmail.com>
Tue, 11 Jan 2011 07:41:19 +0000 (23:41 -0800)
data/types/levels.yaml
src/tanks/map/pathing/map-pathing.cjs
src/tanks/map/pathing/map-searching.cjs
src/tanks/map/pathing/map.cjs
src/tanks/map/pathing/trajectory.cjs
src/tanks/thing/tank.cjs

index 35f3bc3..43fc167 100644 (file)
@@ -57,15 +57,15 @@ types:
           - type: player
             align: 1
             loc: [325,475]
-          - type: green
-            align: 2
-            loc: [75,25]
           - type: blue
             align: 1
             loc: [75,475]
-          - type: blue
-            align: 1
-            loc: [175,475]
+          # - type: blue
+          #   align: 1
+          #   loc: [175,475]
+          - type: green
+            align: 2
+            loc: [75,25]
           - type: green
             align: 2
             loc: [25,375]
index 36cdc97..6d189ba 100644 (file)
@@ -5,7 +5,6 @@ var Y = require('Y').Y
 ,   vec        = require('ezl/math/vec')
 ,   Vec        = vec.Vec
 ,   Line       = require('ezl/math/line').Line
-,   QuadTree   = require('ezl/util/tree/quadtree').QuadTree
 ,   BinaryHeap = require('ezl/util/tree/binaryheap').BinaryHeap
 
 ,   config      = require('tanks/config').config
@@ -13,26 +12,11 @@ var Y = require('Y').Y
 ,   BoundsType  = constants.BoundsType
 ,   DensityType = constants.DensityType
 ,   Map         = require('tanks/map/pathing/map').Map
-,   Trajectory  = require('tanks/map/pathing/trajectory').Trajectory
-,   Traversal   = require('tanks/map/pathing/traversal').Traversal
-,   Thing       = require('tanks/thing/thing').Thing
-,   Bullet      = require('tanks/thing/bullet').Bullet
 
 ,   _X = 0, _Y = 1
-,   BULLET_MOVE_PER_FRAME = MS_PER_FRAME * Bullet.fn.stats.move*REF_SIZE/1000
 ,   SQRT_TWO = Math.sqrt(2)
-
-,   kTrue = op.K(true)
-,   isBullet = Y.is(Bullet)
 ;
 
-/**
- * A QuadTree which aids in pathing for AI.
- *  - QuadTree methods which took rect coords (x1,y1, x2,y2) will accept
- *    anything Rect-like (having properties x1,y1, x2,y2).
- *  - Pathing methods will account for the unit's size when calculating paths,
- *    intersections, blocking, and similar tasks.
- */
 Y.core.extend(Map.fn, {
     
     /**
index 35d54ac..f96a082 100644 (file)
@@ -4,49 +4,20 @@ var Y = require('Y').Y
 
 ,   vec        = require('ezl/math/vec')
 ,   Vec        = vec.Vec
-,   Line       = require('ezl/math/line').Line
-,   QuadTree   = require('ezl/util/tree/quadtree').QuadTree
-,   BinaryHeap = require('ezl/util/tree/binaryheap').BinaryHeap
+,   manhattan  = vec.manhattan
 
-,   config      = require('tanks/config').config
-,   constants   = require('tanks/constants')
-,   BoundsType  = constants.BoundsType
-,   DensityType = constants.DensityType
 ,   Map         = require('tanks/map/pathing/map').Map
 ,   Trajectory  = require('tanks/map/pathing/trajectory').Trajectory
-,   Traversal   = require('tanks/map/pathing/traversal').Traversal
-,   Thing       = require('tanks/thing/thing').Thing
 ,   Bullet      = require('tanks/thing/bullet').Bullet
 
 ,   _X = 0, _Y = 1
-,   BULLET_MOVE_PER_FRAME = MS_PER_FRAME * Bullet.fn.stats.move*REF_SIZE/1000
+,   BULLET_MOVE_PER_FRAME = MS_PER_FRAME * Bullet.fn.stats.move*REF_SIZE/1000 // FIXME: different projectile types move at different rates!
 ,   SQRT_TWO = Math.sqrt(2)
 ;
 
 
 Y.core.extend(Map.fn, {
     
-    // moveAwayFrom : function moveAwayFrom(agent){
-    //     var mid = this.midpoint
-    //     ,   trj = agent.trajectory.tangent(mid)
-    //     
-    //     ,   wall = this.closestOf(this.game.map.allWalls)
-    //     ,   wmid = wall.midpoint
-    //     
-    //     ,   lvl = this.game.level.bbox, w = lvl.width, h = lvl.height
-    //     ,   x   = ((mid.x - wmid.x) > 0 ? w : 0)
-    //     ,   y   = ((mid.y - wmid.y) > 0 ? h : 0)
-    //     ,   to  = this.currentMove = trj.near(x,y);
-    //     
-    //     this.forceCurrentMove = this.willCollide.bind(this, [agent], 5);
-    //     this.currentMoveLimit = this.now + 1000;
-    //     
-    //     this.move(to.x, to.y);
-    //     
-    //     // console.log('  --> Dodge', agent, 'away from', wall, 'to', to);
-    //     return to;
-    // },
-    
     findNearLike : function findNearLike(me, ticks, fn){
         if (fn) fn = fn.toFunction();
         
@@ -62,10 +33,16 @@ Y.core.extend(Map.fn, {
             return dudes;
     },
     
+    findNearBullets : function findNearBullets(me, ticks){
+        return this.findNearLike(me, ticks, this._nearBulletFilter);
+    },
+    _nearBulletFilter : function nearBulletFilter(agent){
+        return agent.isProjectile;
+    },
+    
     findNearEnemies : function findNearEnemies(me, ticks){
         return this.findNearLike(me, ticks, this._nearEnemyFilter);
     },
-    
     _nearEnemyFilter : function nearEnemyFilter(agent){
         var me = this; // Runs in the context of the 'me' unit; @see this.findNearLike()
         return agent.isCombatant && agent.align !== me.align;
@@ -74,11 +51,10 @@ Y.core.extend(Map.fn, {
     findNearEnemiesInSight : function findNearEnemiesInSight(me, ticks){
         return this.findNearLike(me, ticks, this._nearEnemyInSightFilter);
     },
-    
     _nearEnemyInSightFilter : function nearEnemyInSightFilter(agent){
         var me = this; // Runs in the context of the 'me' unit; @see this.findNearLike()
         return ( agent.align !== me.align && agent.isCombatant && 
-                 new Trajectory(me, me.loc, agent.loc).pathBlocked(agent) );
+                 new Trajectory(me, me.loc, agent.loc).canSee(agent) );
     },
     
     closestOf : function closestOf(me, agents){
@@ -92,6 +68,10 @@ Y.core.extend(Map.fn, {
         })[0];
     },
     
+    closestWall : function closestWall(me){
+        return this.closestOf(me, this.allWalls);
+    },
+    
     willCollide : function willCollide(me, bullets, wiggle){
         bullets = ( Y.isArray(bullets) ? bullets : [bullets] );
         wiggle  = wiggle || 0;
index 3d7ce32..8b6b7d2 100644 (file)
@@ -8,6 +8,13 @@ var Y = require('Y').Y
 ,
 
 
+/**
+ * A QuadTree which aids in pathing for AI.
+ *  - QuadTree methods which took rect coords (x1,y1, x2,y2) will accept
+ *    anything Rect-like (having properties x1,y1, x2,y2).
+ *  - Pathing methods will account for the unit's size when calculating paths,
+ *    intersections, blocking, and similar tasks.
+ */
 Map =
 exports['Map'] =
 QuadTree.subclass('Map', {
index 5cc3892..f3072f4 100644 (file)
@@ -152,14 +152,23 @@ Line.subclass('Trajectory', {
         return ( t <= ft && (dw <= w || dh <= h) );
     },
     
+    canSee : function canSee(obj, ignore){
+        var blockers = 
+            this.map.denseWalls
+                .apply('remove', [this.owner, obj].concat(ignore || []) )
+                .filter( this.intersects )
+                .sort( this.compare );
+        return !!blockers.length;
+    },
+    
     pathBlocked : function pathBlocked(obj, ignore){
-        var walls, blockers;
-        if (this.owner.isProjectile)
-            walls = this.map.denseWalls;
-        else
-            walls = this.map.innerWalls; // FIXME: won't filter out concave intersections with the bounds
+        // var walls, blockers
+        // if (this.owner.isProjectile)
+        //     walls = this.map.denseWalls;
+        // else
+        //     walls = this.map.innerWalls; // FIXME: won't filter out concave intersections with the bounds
         
-        blockers = walls
+        var blockers = this.map.innerWalls
                     .concat( this.game.units )
                     .apply('remove', [this.owner].concat(ignore || []) )
                     .filter( this.intersects )
index 2caad1c..dfbcbed 100644 (file)
@@ -2,11 +2,10 @@ var Y  = require('Y').Y
 ,   op = require('Y/op')
 
 ,   vec           = require('ezl/math/vec')
-,   shape         = require('ezl/shape')
+,   Vec           = vec.Vec
 ,   Cooldown      = require('ezl/loop').Cooldown
 ,   CooldownGauge = require('ezl/widget').CooldownGauge
-,   Vec           = vec.Vec
-,   manhattan     = vec.manhattan
+,   shape         = require('ezl/shape')
 ,   Rect          = shape.Rect
 ,   Circle        = shape.Circle
 
@@ -18,8 +17,6 @@ var Y  = require('Y').Y
 ,   Thing       = require('tanks/thing/thing').Thing
 ,   Bullet      = require('tanks/thing/bullet').Bullet
 
-,   isBullet = Y.is(Bullet)
-,   BULLET_MOVE_PER_FRAME = MS_PER_FRAME * Bullet.fn.stats.move*REF_SIZE/1000
 ,   _X = 0, _Y = 1
 ,
 
@@ -90,7 +87,7 @@ Thing.subclass('Tank', function(Tank){
     
     this['act'] =
     function act(elapsed, now){
-        var ai = this.ai;
+        var ai = this.ai, map = this.game.map;
         this.elapsed = elapsed;
         this.now = now;
         
@@ -105,11 +102,11 @@ Thing.subclass('Tank', function(Tank){
         
         // Try to shoot down nearby bullets
         if (ai.shootIncoming.ready && this.ableToShoot()) {
-            var bs = this.willCollide( this.findNearLike(25, isBullet) );
+            var bs = map.willCollide(this,  map.findNearBullets(this, 25) );
             // console.log('['+TICKS+':'+this.id, this, '] Shoot down bullets?', bs.size() && bs);
             if ( bs.size() ) {
                 ai.shootIncoming.activate(now);
-                var b = this.closestOf(bs);
+                var b = map.closestOf(this, bs);
                 // console.log('  --> Incoming! Shoot it down!', b);
                 this.shoot(b.loc.x, b.loc.y);
                 return this;
@@ -118,11 +115,11 @@ Thing.subclass('Tank', function(Tank){
         
         // Dodge incoming bullet
         if (ai.dodge.ready) {
-            var bs = this.willCollide(this.findNearLike(71, isBullet), 5);
+            var bs = map.willCollide(this, map.findNearBullets(this, 71), 5);
             // console.log('['+TICKS+':'+this.id, this, '] Dodge bullets?', bs.size() && bs);
             if (bs.size()) {
                 ai.dodge.activate(now);
-                var bullet = this.closestOf(bs);
+                var bullet = map.closestOf(this, bs);
                 this.moveAwayFrom(bullet);
                 return this;
             }
@@ -130,7 +127,7 @@ Thing.subclass('Tank', function(Tank){
         
         // Try to blow up nearby tanks
         if (ai.shootEnemy.ready && (this.stats.shots.val - this.nShots > 1)) {
-            var t = this.findNearEnemies(71, true).shift();
+            var t = map.findNearEnemiesInSight(this, 71).shift();
             // console.log('['+TICKS+':'+this.id, this, '] Shoot at enemies?', t);
             if (t) {
                 ai.shootEnemy.activate(now);
@@ -226,7 +223,7 @@ Thing.subclass('Tank', function(Tank){
     this['continueMove'] =
     function continueMove(){
         if ( !this.currentMove || this.ai.path.ready ){
-            var target = this.findNearEnemies(10000).shift();
+            var target = this.game.map.findNearEnemies(this, 10000).shift();
             if (target)
                 this.calculatePath(target.loc);
             else
@@ -263,6 +260,30 @@ Thing.subclass('Tank', function(Tank){
     };
     
     
+    this['moveAwayFrom'] =
+    function moveAwayFrom(agent){
+        var map = this.game.map
+        ,   mid = this.midpoint
+        ,   trj = agent.trajectory.tangent(mid)
+        
+        ,   wall = map.closestWall(this)
+        ,   wmid = wall.midpoint
+        
+        ,   lvl = this.game.level.bbox, w = lvl.width, h = lvl.height
+        ,   x   = ((mid.x - wmid.x) > 0 ? w : 0)
+        ,   y   = ((mid.y - wmid.y) > 0 ? h : 0)
+        ,   to  = this.currentMove = trj.near(x,y);
+        
+        this.forceCurrentMove = map.willCollide.bind(map, this, [agent], 5);
+        this.currentMoveLimit = this.now + 1000;
+        
+        this.move(to.x, to.y);
+        
+        // console.log('  --> Dodge', agent, 'away from', wall, 'to', to);
+        return to;
+    };
+    
+    
     this['getTurretLoc'] =
     function getTurretLoc(){
         var WIGGLE = 2