From: dsc Date: Fri, 24 Dec 2010 17:40:58 +0000 (-0800) Subject: Fixes pathing around corners in all cases. X-Git-Url: http://git.less.ly:3516/?a=commitdiff_plain;h=c5ac91ab41f841dcf1f118fe1c3fb9cd4785e5c4;p=tanks.git Fixes pathing around corners in all cases. --- diff --git a/src/Y/types/chain.cjs b/src/Y/types/chain.cjs index 98fc812..b13b46d 100644 --- a/src/Y/types/chain.cjs +++ b/src/Y/types/chain.cjs @@ -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 diff --git a/src/ezl/loc/boundingbox.cjs b/src/ezl/loc/boundingbox.cjs index 82b39a1..2317789 100644 --- a/src/ezl/loc/boundingbox.cjs +++ b/src/ezl/loc/boundingbox.cjs @@ -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. diff --git a/src/ezl/math/vec.cjs b/src/ezl/math/vec.cjs index 44cdb2a..00c88ff 100644 --- a/src/ezl/math/vec.cjs +++ b/src/ezl/math/vec.cjs @@ -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) { diff --git a/src/tanks/map/pathmap.cjs b/src/tanks/map/pathmap.cjs index 1d515ee..623cc21 100644 --- a/src/tanks/map/pathmap.cjs +++ b/src/tanks/map/pathmap.cjs @@ -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); } }) diff --git a/src/tanks/map/traversal.cjs b/src/tanks/map/traversal.cjs index 40001c8..4316d32 100644 --- a/src/tanks/map/traversal.cjs +++ b/src/tanks/map/traversal.cjs @@ -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 ); diff --git a/src/tanks/thing/tank.cjs b/src/tanks/thing/tank.cjs index 2c60493..939536d 100644 --- a/src/tanks/thing/tank.cjs +++ b/src/tanks/thing/tank.cjs @@ -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 index 0000000..781a991 --- /dev/null +++ b/src/tanks/thing/wall.cjs @@ -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 index 0000000..e69de29