args: [150,300, 50,50]
- type: wall
args: [100,100, 50,50]
+ - type: fence
+ args: [360,210, 130,30]
+ - type: fence
+ args: [10,210, 30,30]
+ - type: fence
+ args: [110,210, 30,30]
+ - type: fence
+ args: [210,210, 30,30]
units:
- type: player
align: 1
- loc: [275,475]
+ loc: [325,475]
- type: blue
align: 1
loc: [175,475]
-//#exports PathingType.{PASSABLE,ZONE,BLOCKING,IRREGULAR}
+//#exports BoundsType.{PASSABLE,ZONE,BLOCKING,IRREGULAR}
+//#exports DensityType.{PASSABLE,BOUNDARY,DENSE,SPARSE,IRREGULAR}
//#exports StatInvariant.{NONE,RATIO,FULL}
require('Y').Y.extend(exports, {
- /// Pathing Constants ///
- /** How this object interacts with the world. */
- PathingType : {
+ /** How to determine the bounds of this object for pathing. */
+ BoundsType : {
/** Does not obstruct other objects. */
PASSABLE : 0,
},
+ /**
+ * Governs the kinds of objects this object obstructs.
+ */
+ DensityType : {
+
+ /** Not an obstruction. */
+ PASSABLE : 0,
+
+ /** Blocks absolutely everything. No exceptions. */
+ BOUNDARY : 1,
+
+ /** Blocks everything material (eg, units). */
+ DENSE : 2,
+
+ /** Does not block small things (eg, projectiles). */
+ SPARSE : 3,
+
+ /** Blocks based on custom rules. */
+ IRREGULAR : 4
+
+ },
+
+
+
/**
* Invariant to restore for the current value when modifying the base or max of a Stat.
* @see {tanks.effects.stat.Stat} for the default behavior of its methods.
--- /dev/null
+var Y = require('Y').Y
+
+, constants = require('tanks/constants')
+, BoundsType = constants.BoundsType
+, DensityType = constants.DensityType
+, Wall = require('tanks/map/wall').Wall
+,
+
+
+Fence =
+exports['Fence'] =
+Wall.subclass('Fence', {
+
+ isReflective : false,
+ fillStyle : 'rgba(0,0,0, 0.25)',
+ strokeStyle : 'transparent',
+ lineWidth : 0,
+
+ blocking : BoundsType.BLOCKING,
+ density : DensityType.SPARSE,
+ isBoundary : false,
+
+
+
+ init : function initFence(x,y, w,h){
+ Wall.init.call(this, x,y, w,h, this.isBoundary);
+ }
+
+});
+
+Wall.register('fence', Fence);
-var Y = require('Y').Y;
-
-Y.extend(exports, {
+require('Y').Y
+.extend(exports, {
+ 'pathing' : require('tanks/map/pathing'),
+
'Map' : require('tanks/map/map').Map,
- 'PathMap' : require('tanks/map/pathmap').PathMap,
'Level' : require('tanks/map/level').Level,
- 'Traversal' : require('tanks/map/traversal').Traversal,
- 'Trajectory' : require('tanks/map/trajectory').Trajectory
+ 'Wall' : require('tanks/map/wall').Wall,
+ 'Fence' : require('tanks/map/fence').Fence
});
, Rect = require('ezl/shape').Rect
, Buff = require('tanks/effects/buff').Buff
-, PathMap = require('tanks/map/pathmap').PathMap
+, PathMap = require('tanks/map/pathing/pathmap').PathMap
, Thing = require('tanks/thing/thing').Thing
, Tank = require('tanks/thing/tank').Tank
, Item = require('tanks/thing/item').Item
, Player = require('tanks/thing/player').Player
-, Wall = require('tanks/thing/wall').Wall
+, Wall = require('tanks/map/wall').Wall
, Speciated = require('tanks/mixins/speciated').Speciated
, min = Y(Math.min).limit(2)
// -*- mode: JavaScript; tab-width: 4; indent-tabs-mode: nil; -*-
var Y = require('Y').Y
-, QuadTree = require('ezl/util/tree/quadtree').QuadTree
+, QuadTree = require('ezl/util/tree/quadtree').QuadTree
-
-/** Does not obstruct other objects. */
-, PASSABLE = exports['PASSABLE'] = 0
-
-/** Does not obstruct other objects, but still collides with them. */
-, ZONE = exports['ZONE'] = 1
-
-/** Obstructs other blockers with its BoundingBox. */
-, BLOCKING = exports['BLOCKING'] = 2
-
-/** Potentially obstructs other objects, but requires a special test once a BoundingBox collision has been detected. */
-, IRREGULAR = exports['IRREGULAR'] = 3
+, constants = require('tanks/constants')
+, BoundsType = constants.BoundsType
+, DensityType = constants.DensityType
,
Map =
exports['Map'] =
QuadTree.subclass('Map', {
+ allWalls : null, // All walls in this map
+ innerWalls : null, // Non-boundary walls
+ denseWalls : null, // Non-boundary non-Fences
+
+
+ init : function initMap(x1,y1, x2,y2, capacity){
+ this.allWalls = Y([]);
+ this.innerWalls = Y([]);
+ this.denseWalls = Y([]);
+ QuadTree.init.call(this, x1,y1, x2,y2, capacity);
+ },
addBlocker : function addBlocker(obj){
this.removeBlocker(obj);
+
var pt = obj.blocking
, bb = obj.bbox ;
if (pt !== undefined && bb)
obj.region = this.set(bb.x1,bb.y1, bb.x2,bb.y2, obj);
+
+ if (obj.isWall) {
+ if ( !this.allWalls.has(obj) )
+ this.allWalls.push(obj);
+ if ( !(obj.isBoundary || this.innerWalls.has(obj)) )
+ this.innerWalls.push(obj);
+ if ( obj.density === DensityType.DENSE || obj.density === DensityType.BOUNDARY )
+ this.denseWalls.push(obj);
+ }
+
return obj;
},
this.remove(obj.region);
delete obj.region;
}
+
+ if (obj.isWall) {
+ this.allWalls.remove(obj);
+ this.innerWalls.remove(obj);
+ this.denseWalls.remove(obj);
+ }
+
return obj;
},
y2 = x1.y2; x2 = x1.x2;
y1 = x1.y1; x1 = x1.x1;
}
- var bs = this.get(x1,y1, x2,y2)
- .filter('_.blocking === BLOCKING');
+ var bs = this.get(x1,y1, x2,y2).filter(this._filterBlockers, this);
if (ignore && bs.length)
return bs.remove.apply(bs, ignore || []);
else
return bs;
- }
+ },
+ _filterBlockers : function _filterBlockers(v){
+ return (v.blocking === BoundsType.BLOCKING || v.blocking === BoundsType.IRREGULAR);
+ },
+
+ wallObstructs : function wallObstructs(line){
+ return this.innerWalls.some(function(wall){
+ return wall.bbox.intersects(line);
+ }, this);
+ }
});
--- /dev/null
+require('Y').Y
+.extend(exports, {
+ 'PathMap' : require('tanks/map/pathing/pathmap').PathMap,
+ 'Traversal' : require('tanks/map/pathing/traversal').Traversal,
+ 'Trajectory' : require('tanks/map/pathing/trajectory').Trajectory
+});
, Line = math.Line
, config = require('tanks/config').config
-, PathingType = require('tanks/constants').PathingType
+, constants = require('tanks/constants')
+, BoundsType = constants.BoundsType
+, DensityType = constants.DensityType
, Map = require('tanks/map/map').Map
-, Wall = require('tanks/thing/wall').Wall
, SQRT_TWO = Math.sqrt(2)
-
init : function init(x1,y1, x2,y2, capacity, buffer_size) {
this.buffer_size = buffer_size;
x1 -= buffer_size; y1 -= buffer_size;
x2 += buffer_size; y2 += buffer_size;
- QuadTree.init.call(this, x1,y1, x2,y2, capacity);
+ Map.init.call(this, x1,y1, x2,y2, capacity);
this._squares = {};
-
- this.innerWalls = Y([]);
- this.allWalls = Y([]);
-
- // this.game.addEventListener('ready', this.setup.bind(this, x1,y1, x2,y2));
- },
-
- addBlocker : function addBlocker(obj){
- Map.fn.addBlocker.call(this, obj);
- if (obj instanceof Wall) {
- if ( !this.allWalls.has(obj) )
- this.allWalls.push(obj);
- if ( !(obj.isBoundary || this.innerWalls.has(obj)) )
- this.innerWalls.push(obj);
- }
- return obj;
- },
-
- removeBlocker : function removeBlocker(obj){
- Map.fn.removeBlocker.call(this, obj);
- if (obj instanceof Wall) {
- this.innerWalls.remove(obj);
- this.allWalls.remove(obj);
- }
- return obj;
- },
-
- wallObstructs : function wallObstructs(line){
- return this.innerWalls.some(function(wall){
- return wall.bbox.intersects(line);
- }, this);
},
/**
if (this.pathId === pathId)
return this;
- this.pathId = pathId;
+ this.pathId = pathId;
+ this.agent = this.pathmap._agent;
this.blocked = this._blocked();
this.dist = 0;
*/
_blocked : function blocked(){
var pm = this.pathmap
- , agent = pm._agent
- // , bb = agent.bbox
+ // , bb = this.agent.bbox
// , origin = bb.relOrigin
// , left = origin.x, right = bb.width - left
, y1 = y, y2 = y + SIZE
, blockers = pm.get(x1,y1, x2,y2)
- .remove(agent)
+ .remove(this.agent)
.filter(this._filterBlocked, this)
;
* @private
*/
_filterBlocked : function filterBlocked(v, r){
- return v.blocking === PathingType.BLOCKING && !v.isBoundary;
+ return (v.blocking === BoundsType.BLOCKING && !v.isBoundary)
+ || (v.blocking === BoundsType.IRREGULAR && v.testCollide(this.agent,this,null) ); // FIXME: hm. calc bbox?
},
getNeighbors : function getNeighbors(){
, Line = math.Line
, Rect = math.Rect
, BoundingBox = require('ezl/loc').BoundingBox
-, Thing = require('tanks/thing/thing').Thing
+
+, Thing = require('tanks/thing/thing').Thing
, BOUND_SIZE_RATIO = 0.75
,
},
pathBlocked : function pathBlocked(obj, ignore){
- var blockers =
- this.pathmap.innerWalls
+ var walls, blockers;
+ if (this.owner.isProjectile)
+ walls = this.pathmap.denseWalls;
+ else
+ walls = this.pathmap.innerWalls; // FIXME: won't filter out concave intersections with the bounds
+
+ blockers = walls
.concat( this.game.units )
.apply('remove', [this.owner].concat(ignore || []) )
.filter( this.intersects )
var Y = require('Y').Y
-, PathingType = require('tanks/constants').PathingType
+, constants = require('tanks/constants')
+, BoundsType = constants.BoundsType
+, DensityType = constants.DensityType
,
Traversal =
* Filters found obstructions to keep only those not ignored and blocking.
*/
checkBlocker : function checkBlocker(blocker){
- var blocking = blocker.blocking;
+ var blocking = blocker.blocking
+ , density = blocker.density;
// All blockers after the first are ignored
- if ( this.ignore.has(blocker) || blocking === PathingType.PASSABLE || this.isBlocked )
+ if ( this.isBlocked || this.ignore.has(blocker)
+ // Skip passable objects
+ || (blocking === BoundsType.PASSABLE)
+
+ // Ask irregular objects if we hit
+ || (blocking === BoundsType.IRREGULAR && !blocker.testCollide(this.thing,this.to,this.bbox))
+
+ // Filter out Sparse objects if bullet
+ || (density === DensityType.SPARSE && this.thing.isProjectile) )
+ {
return false;
+ }
// Only fire collision with this zone once per traversal
// XXX: Zone will have to manage enterance/exit and provide a method for testing, hm -- this would obviate the main need for this.ignore
- if ( blocking === PathingType.ZONE ) {
+ if ( blocking === BoundsType.ZONE ) {
this.ignore.push(blocker);
this.collide(blocker);
return false;