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;
collide : function collide(blocker){
var thing = this.thing;
-
thing.fire('collide', blocker, { 'traversal':this, 'unit':blocker });
blocker.fire('collide', thing, { 'traversal':this, 'unit':thing });
},
-var Y = require('Y').Y
-, op = require('Y/op')
+var Y = require('Y').Y
+, op = require('Y/op')
-, Rect = require('ezl/shape').Rect
+, Rect = require('ezl/shape').Rect
-, Thing = require('tanks/thing/thing').Thing
-, PathingType = require('tanks/constants').PathingType
+, Thing = require('tanks/thing/thing').Thing
+, constants = require('tanks/constants')
+, BoundsType = constants.BoundsType
+, DensityType = constants.DensityType
,
originX : 0,
originY : 0,
- blocking : PathingType.BLOCKING,
+ width : 0,
+ height : 0,
+
+
+ blocking : BoundsType.BLOCKING,
+ density : DensityType.DENSE,
+ isWall : true,
isReflective : true,
+
+ // rendering
+
isRenderable : true,
+ fillStyle : 'rgba(255,255,255, 0.25)',
+ strokeStyle : 'transparent',
+ lineWidth : 0,
+
+ renderWidth : 0,
+ renderHeight : 0,
+ renderOffsetX : 0,
+ renderOffsetY : 0,
+
// inactive
active : false,
this.width = w;
this.height = h;
this.isBoundary = !!isBoundary;
+ if (isBoundary)
+ this.density = DensityType.BOUNDARY;
Thing.init.call(this);
this.position(x,y);
},
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)')
+ new Rect( this.renderWidth || this.width, this.renderHeight || this.height )
+ .position(this.loc.x + this.renderOffsetX, this.loc.y + this.renderOffsetY)
+ .fill(this.fillStyle)
+ .stroke(this.strokeStyle, this.lineWidth)
.appendTo( parent );
return this;
onBuffAcquired : function onBuffAcquired(evt){
var buff = evt.data.buff;
this.buffs.push(buff);
- console.log('Buff '+buff+' acquired by '+this);
+ // console.log('Buff '+buff+' acquired by '+this);
// TODO: update UI
},
onBuffLost : function onBuffLost(evt){
var buff = evt.data.buff;
this.buffs.remove(buff);
- console.log('Buff '+buff+' lost by '+this);
+ // console.log('Buff '+buff+' lost by '+this);
// TODO: update UI
},
, Circle = shape.Circle
, config = require('tanks/config').config
-, PathingType = require('tanks/constants').PathingType
+, BoundsType = require('tanks/constants').BoundsType
, stat = require('tanks/effects/stat')
-
-, Thing = require('tanks/thing/thing').Thing
-, Wall = require('tanks/thing/wall').Wall
-, Trajectory = require('tanks/map/trajectory').Trajectory
-, Traversal = require('tanks/map/traversal').Traversal
, Explosion = require('tanks/fx/explosion').Explosion
+, Thing = require('tanks/thing/thing').Thing
+, Trajectory = require('tanks/map/pathing/trajectory').Trajectory
+, Traversal = require('tanks/map/pathing/traversal').Traversal
,
},
// Instance
- blocking : PathingType.BLOCKING,
+ blocking : BoundsType.BLOCKING,
isRenderable : true,
+ isProjectile : true,
bounces : 0,
bounceLimit : 1,
;
// Ignore collisions with zones
- if (unit.blocking === PathingType.ZONE)
+ if (unit.blocking === BoundsType.ZONE)
return;
// Reflection!
+++ /dev/null
-var Y = require('Y').Y
-, op = require('Y/op')
-, Rect = require('ezl/shape').Rect
-, Wall = require('tanks/thing/wall').Wall
-,
-
-
-Fence =
-exports['Fence'] =
-Wall.subclass('Fence', {
- align : 0, // 0 reserved for neutral units
-
- originX : 0,
- originY : 0,
-
- isReflective : true,
- isRenderable : true,
-
- // inactive
- active : false,
- createCooldowns : op.nop,
-
- // indestructable
- dealDamage : op.nop,
-
- stats : {
- hp : Infinity,
- move : 0,
- power : 0,
- speed : 0,
- shots : 0
- },
-
- // Instance
-
- isBoundary : false,
-
-
-
- init : function initFence(x,y, w,h){
- this.width = w;
- this.height = h;
- this.isBoundary = !!isBoundary;
- Wall.init.call(this, x,y, w,h);
- this.position(x,y);
- },
-
-
-
- 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(0,0,0, 0.25)')
- .stroke('transparent', 0)
- .appendTo( parent );
-
- return this;
- },
-
- toString : function(){
- var bb = this.bbox
- , 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+')';
- }
-});
-
-Wall.register('fence', Fence);