From: dsc Date: Sun, 9 Jan 2011 10:26:50 +0000 (-0800) Subject: Adds Fences; minor refactor to map-like stuff. X-Git-Url: http://git.less.ly:3516/?a=commitdiff_plain;h=ea386b8d34acd114f17f9146e8c681fea5a74399;p=tanks.git Adds Fences; minor refactor to map-like stuff. --- diff --git a/data/types/levels.yaml b/data/types/levels.yaml index df2c2f5..86b4a1f 100644 --- a/data/types/levels.yaml +++ b/data/types/levels.yaml @@ -30,10 +30,18 @@ types: 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] diff --git a/src/tanks/constants.cjs b/src/tanks/constants.cjs index b44aa33..2404b79 100644 --- a/src/tanks/constants.cjs +++ b/src/tanks/constants.cjs @@ -1,11 +1,11 @@ -//#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, @@ -21,6 +21,30 @@ require('Y').Y.extend(exports, { }, + /** + * 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. diff --git a/src/tanks/map/fence.cjs b/src/tanks/map/fence.cjs new file mode 100644 index 0000000..cb1e79b --- /dev/null +++ b/src/tanks/map/fence.cjs @@ -0,0 +1,31 @@ +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); diff --git a/src/tanks/map/index.cjs b/src/tanks/map/index.cjs index d143552..0b2364f 100644 --- a/src/tanks/map/index.cjs +++ b/src/tanks/map/index.cjs @@ -1,9 +1,9 @@ -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 }); diff --git a/src/tanks/map/level.cjs b/src/tanks/map/level.cjs index 328de4a..c31d975 100644 --- a/src/tanks/map/level.cjs +++ b/src/tanks/map/level.cjs @@ -5,12 +5,12 @@ var Y = require('Y').Y , 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) diff --git a/src/tanks/map/map.cjs b/src/tanks/map/map.cjs index feec7a3..92461b4 100644 --- a/src/tanks/map/map.cjs +++ b/src/tanks/map/map.cjs @@ -1,32 +1,45 @@ // -*- 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; }, @@ -35,6 +48,13 @@ QuadTree.subclass('Map', { this.remove(obj.region); delete obj.region; } + + if (obj.isWall) { + this.allWalls.remove(obj); + this.innerWalls.remove(obj); + this.denseWalls.remove(obj); + } + return obj; }, @@ -44,13 +64,21 @@ QuadTree.subclass('Map', { 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); + } }); diff --git a/src/tanks/map/pathing/index.cjs b/src/tanks/map/pathing/index.cjs new file mode 100644 index 0000000..633d120 --- /dev/null +++ b/src/tanks/map/pathing/index.cjs @@ -0,0 +1,6 @@ +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 +}); diff --git a/src/tanks/map/pathmap.cjs b/src/tanks/map/pathing/pathmap.cjs similarity index 89% rename from src/tanks/map/pathmap.cjs rename to src/tanks/map/pathing/pathmap.cjs index 3a09ae2..6dc6504 100644 --- a/src/tanks/map/pathmap.cjs +++ b/src/tanks/map/pathing/pathmap.cjs @@ -9,9 +9,10 @@ var Y = require('Y').Y , 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) @@ -37,44 +38,12 @@ Map.subclass('PathMap', { - 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); }, /** @@ -246,7 +215,8 @@ Y.subclass('Square', new Vec(0,0), { if (this.pathId === pathId) return this; - this.pathId = pathId; + this.pathId = pathId; + this.agent = this.pathmap._agent; this.blocked = this._blocked(); this.dist = 0; @@ -264,8 +234,7 @@ Y.subclass('Square', new Vec(0,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 @@ -280,7 +249,7 @@ Y.subclass('Square', new Vec(0,0), { , y1 = y, y2 = y + SIZE , blockers = pm.get(x1,y1, x2,y2) - .remove(agent) + .remove(this.agent) .filter(this._filterBlocked, this) ; @@ -291,7 +260,8 @@ Y.subclass('Square', new Vec(0,0), { * @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(){ diff --git a/src/tanks/map/trajectory.cjs b/src/tanks/map/pathing/trajectory.cjs similarity index 94% rename from src/tanks/map/trajectory.cjs rename to src/tanks/map/pathing/trajectory.cjs index 9653053..837c758 100644 --- a/src/tanks/map/trajectory.cjs +++ b/src/tanks/map/pathing/trajectory.cjs @@ -5,7 +5,8 @@ var Y = require('Y').Y , 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 , @@ -153,8 +154,13 @@ Line.subclass('Trajectory', { }, 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 ) diff --git a/src/tanks/map/traversal.cjs b/src/tanks/map/pathing/traversal.cjs similarity index 87% rename from src/tanks/map/traversal.cjs rename to src/tanks/map/pathing/traversal.cjs index 9d9237b..6f6beda 100644 --- a/src/tanks/map/traversal.cjs +++ b/src/tanks/map/pathing/traversal.cjs @@ -1,5 +1,7 @@ var Y = require('Y').Y -, PathingType = require('tanks/constants').PathingType +, constants = require('tanks/constants') +, BoundsType = constants.BoundsType +, DensityType = constants.DensityType , Traversal = @@ -90,15 +92,26 @@ Y.subclass('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; @@ -111,7 +124,6 @@ Y.subclass('Traversal', { collide : function collide(blocker){ var thing = this.thing; - thing.fire('collide', blocker, { 'traversal':this, 'unit':blocker }); blocker.fire('collide', thing, { 'traversal':this, 'unit':thing }); }, diff --git a/src/tanks/thing/wall.cjs b/src/tanks/map/wall.cjs similarity index 58% rename from src/tanks/thing/wall.cjs rename to src/tanks/map/wall.cjs index f59831f..a814c75 100644 --- a/src/tanks/thing/wall.cjs +++ b/src/tanks/map/wall.cjs @@ -1,10 +1,12 @@ -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 , @@ -16,9 +18,27 @@ Thing.subclass('Wall', { 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, @@ -45,6 +65,8 @@ Thing.subclass('Wall', { this.width = w; this.height = h; this.isBoundary = !!isBoundary; + if (isBoundary) + this.density = DensityType.BOUNDARY; Thing.init.call(this); this.position(x,y); }, @@ -59,9 +81,10 @@ Thing.subclass('Wall', { 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; diff --git a/src/tanks/mixins/quantified.cjs b/src/tanks/mixins/quantified.cjs index 05f2e4a..0889a07 100644 --- a/src/tanks/mixins/quantified.cjs +++ b/src/tanks/mixins/quantified.cjs @@ -53,14 +53,14 @@ Mixin.subclass('Quantified', { 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 }, diff --git a/src/tanks/thing/bullet.cjs b/src/tanks/thing/bullet.cjs index 41be7dc..1a48969 100644 --- a/src/tanks/thing/bullet.cjs +++ b/src/tanks/thing/bullet.cjs @@ -8,14 +8,12 @@ var Y = require('Y').Y , 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 , @@ -33,8 +31,9 @@ Thing.subclass('Bullet', { }, // Instance - blocking : PathingType.BLOCKING, + blocking : BoundsType.BLOCKING, isRenderable : true, + isProjectile : true, bounces : 0, bounceLimit : 1, @@ -121,7 +120,7 @@ Thing.subclass('Bullet', { ; // Ignore collisions with zones - if (unit.blocking === PathingType.ZONE) + if (unit.blocking === BoundsType.ZONE) return; // Reflection! diff --git a/src/tanks/thing/fence.cjs b/src/tanks/thing/fence.cjs deleted file mode 100644 index b08b7b0..0000000 --- a/src/tanks/thing/fence.cjs +++ /dev/null @@ -1,80 +0,0 @@ -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); diff --git a/src/tanks/thing/index.cjs b/src/tanks/thing/index.cjs index d36e903..d1a1bbb 100644 --- a/src/tanks/thing/index.cjs +++ b/src/tanks/thing/index.cjs @@ -3,5 +3,3 @@ exports['Bullet'] = require('tanks/thing/bullet').Bullet; exports['Tank'] = require('tanks/thing/tank').Tank; exports['Player'] = require('tanks/thing/player').Player; exports['Item'] = require('tanks/thing/item').Item; -exports['Wall'] = require('tanks/thing/wall').Wall; -exports['Fence'] = require('tanks/thing/fence').Fence; diff --git a/src/tanks/thing/item.cjs b/src/tanks/thing/item.cjs index 76dd7cc..6457a05 100644 --- a/src/tanks/thing/item.cjs +++ b/src/tanks/thing/item.cjs @@ -4,7 +4,7 @@ var Y = require('Y').Y , shape = require('ezl/shape') , Rect = shape.Rect -, PathingType = require('tanks/constants').PathingType +, BoundsType = require('tanks/constants').BoundsType , Buff = require('tanks/effects/buff').Buff , Thing = require('tanks/thing/thing').Thing @@ -20,7 +20,7 @@ Thing.subclass('Item', { align : 0, // 0 reserved for neutral units - blocking : PathingType.ZONE, + blocking : BoundsType.ZONE, width : ITEM_SIZE, height : ITEM_SIZE, @@ -91,7 +91,7 @@ Thing.subclass('Item', { onAcquired : function onAcquired(evt){ this.owner = evt.data.unit; - console.log(this.owner+' acquired '+this+' ('+this.desc+')!'); + // console.log(this.owner+' acquired '+this+' ('+this.desc+')!'); this.currentBuffs = this.itemBuffs.invoke('instantiate', this.owner); this.destroy(); // removes map object }, @@ -101,7 +101,7 @@ Thing.subclass('Item', { if ( this.currentBuffs ) this.currentBuffs.invoke('die', 'item.lost'); var unit = this.owner; - console.log(unit+' lost '+this+'!'); + // console.log(unit+' lost '+this+'!'); this.owner = null; // TODO: game to listen, re-add to level at unit.loc }, diff --git a/src/tanks/thing/tank.cjs b/src/tanks/thing/tank.cjs index 7dabe64..4c318d5 100644 --- a/src/tanks/thing/tank.cjs +++ b/src/tanks/thing/tank.cjs @@ -1,5 +1,5 @@ -var Y = require('Y').Y -, op = require('Y/op') +var Y = require('Y').Y +, op = require('Y/op') , vec = require('ezl/math/vec') , shape = require('ezl/shape') @@ -10,13 +10,16 @@ var Y = require('Y').Y , Rect = shape.Rect , Circle = shape.Circle -, Thing = require('tanks/thing/thing').Thing -, Bullet = require('tanks/thing/bullet').Bullet -, Trajectory = require('tanks/map/trajectory').Trajectory -, Traversal = require('tanks/map/traversal').Traversal +, constants = require('tanks/constants') +, BoundsType = constants.BoundsType +, DensityType = constants.DensityType +, 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 , isBullet = Y.is(Bullet) -, BULLET_MOVE_PER_FRAME = MS_PER_FRAME * Bullet.prototype.stats.move*REF_SIZE/1000 +, BULLET_MOVE_PER_FRAME = MS_PER_FRAME * Bullet.fn.stats.move*REF_SIZE/1000 , _X = 0, _Y = 1 , @@ -24,7 +27,6 @@ var Y = require('Y').Y Tank = exports['Tank'] = Thing.subclass('Tank', function(Tank){ - // TODO: lookup projectile on Bullet Y.core.descriptors(this, { colors : { @@ -146,6 +148,65 @@ Thing.subclass('Tank', function(Tank){ /** + * Fires this agent's cannon. If a target location is omitted, the shot + * will be fired in the direction of the tank's current barrel rotation. + * + * @param {Number} [x] Target X coordinate. + * @param {Number} [y] Target Y coordinate. + */ + this['shoot'] = + function shoot(x,y){ + if ( this.nShots >= this.stats.shots.val || !this.cooldowns.attack.ready ) + return null; + + var xydef = (x !== undefined && y !== undefined); + if (xydef) + this.rotateBarrel(x,y); + + // Additional space on each side which must be clear around the + // shot to ensure we don't shoot ourself in the foot (literally) + var WIGGLE = 1 + , Projectile = this.projectile + , pw2 = Projectile.fn.width/2, ph2 = Projectile.fn.height/2 + + , tloc = this.getTurretLoc() + , tx = tloc.x, ty = tloc.y + + , x1 = tx - pw2 - WIGGLE, y1 = ty - ph2 - WIGGLE + , x2 = tx + pw2 + WIGGLE, y2 = ty + ph2 + WIGGLE + , blockers = this.game.pathmap.get(x1,y1, x2,y2).filter(filterShoot, this) + ; + + if ( blockers.size() ) + return null; // console.log('squelch!', blockers); + + if (!xydef) { + var theta = this.barrel.transform.rotate + , sin = Math.sin(theta), cos = Math.cos(theta); + x = tx + REF_SIZE*cos; + y = ty + REF_SIZE*sin; + } + + this.cooldowns.attack.activate(this.now); + this.nShots++; + + var p = new Projectile(this, tx,ty, x,y); + p.addEventListener('destroy', this.onBulletDeath); + return p; + }; + + function filterShoot(v){ + return (v !== this) + && (v.density === DensityType.BOUNDARY || (v.isWall && v.density === DensityType.DENSE)); + } + + this['ableToShoot'] = + function ableToShoot(){ + return this.nShots < this.stats.shots.val && this.cooldowns.attack.ready; + }; + + + /** * @return {this} */ this['move'] = @@ -285,7 +346,6 @@ Thing.subclass('Tank', function(Tank){ var tank = this, bb = this.bbox , w = bb.width+wiggle, h = bb.height+wiggle ; - // , w = (bb.width+wiggle)/2, h = (bb.height+wiggle)/2 ; return bullets.filter(function(b){ var trj = b.trajectory; @@ -295,61 +355,6 @@ Thing.subclass('Tank', function(Tank){ }); }; - /** - * Fires this agent's cannon. If a target location is omitted, the shot - * will be fired in the direction of the tank's current barrel rotation. - * - * @param {Number} [x] Target X coordinate. - * @param {Number} [y] Target Y coordinate. - */ - this['shoot'] = - function shoot(x,y){ - if ( this.nShots >= this.stats.shots.val || !this.cooldowns.attack.ready ) - return null; - - var xydef = (x !== undefined && y !== undefined); - if (xydef) - this.rotateBarrel(x,y); - - // Additional space on each side which must be clear around the - // shot to ensure we don't shoot ourself in the foot (literally) - var WIGGLE = 1 - , Projectile = this.projectile - , pw2 = Projectile.fn.width/2, ph2 = Projectile.fn.height/2 - - , tloc = this.getTurretLoc() - , tx = tloc.x, ty = tloc.y - - , x1 = tx - pw2 - WIGGLE, y1 = ty - ph2 - WIGGLE - , x2 = tx + pw2 + WIGGLE, y2 = ty + ph2 + WIGGLE - , blockers = this.game.pathmap.get(x1,y1, x2,y2).remove(this) - ; - - if ( blockers.size() ) - return null; // console.log('squelch!', blockers); - - if (!xydef) { - var theta = this.barrel.transform.rotate - , sin = Math.sin(theta), cos = Math.cos(theta); - x = tx + REF_SIZE*cos; - y = ty + REF_SIZE*sin; - } - - this.cooldowns.attack.activate(this.now); - this.nShots++; - - var p = new Projectile(this, tx,ty, x,y); - p.addEventListener('destroy', this.onBulletDeath); - // this.game.addThing(p).render(this.game.level); - return p; - }; - - - this['ableToShoot'] = - function ableToShoot(){ - return this.nShots < this.stats.shots.val && this.cooldowns.attack.ready; - }; - this['getTurretLoc'] = function getTurretLoc(){ var WIGGLE = 2 @@ -367,7 +372,6 @@ Thing.subclass('Tank', function(Tank){ , x = loc.x + len*cos , y = loc.y + len*sin ; - // console.log('getTurretLoc()', 'loc:', loc, '(x,y):', [x,y]); return new Vec(x,y); }; diff --git a/src/tanks/thing/thing.cjs b/src/tanks/thing/thing.cjs index 9a0ea6f..975e3d7 100644 --- a/src/tanks/thing/thing.cjs +++ b/src/tanks/thing/thing.cjs @@ -9,7 +9,9 @@ var Y = require('Y').Y , Cooldown = require('ezl/loop').Cooldown , config = require('tanks/config').config -, PathingType = require('tanks/constants').PathingType +, constants = require('tanks/constants') +, BoundsType = constants.BoundsType +, DensityType = constants.DensityType , stat = require('tanks/effects/stat') , Quantified = require('tanks/mixins/quantified').Quantified , Speciated = require('tanks/mixins/speciated').Speciated @@ -52,7 +54,9 @@ new evt.Class('Thing', { dirty : true, // Properties - blocking : PathingType.BLOCKING, + blocking : BoundsType.BLOCKING, + density : DensityType.DENSE, + isProjectile : false, isRenderable : false, // Agent will present itself for rendering when ready // FIXME: stupid hack active : true, // Agent takes actions? isReflective : false, // Projectiles bounce off agent rather than explode? diff --git a/src/tanks/ui/pathmapui.cjs b/src/tanks/ui/pathmapui.cjs index 9bf2d6d..ff188e2 100644 --- a/src/tanks/ui/pathmapui.cjs +++ b/src/tanks/ui/pathmapui.cjs @@ -5,8 +5,8 @@ var Y = require('Y').Y , vec = require('ezl/math/vec') , config = require('tanks/config').config -, PathingType = require('tanks/constants').PathingType -, PathMap = require('tanks/map/pathmap').PathMap +, BoundsType = require('tanks/constants').BoundsType +, PathMap = require('tanks/map/pathing/pathmap').PathMap , @@ -81,7 +81,7 @@ Rect.subclass('PathMapUI', { return acc; acc[r.id] = r; - if (v.blocking === PathingType.ZONE) { + if (v.blocking === BoundsType.ZONE) { ctx.fillStyle = this.zoneFillStyle; ctx.strokeStyle = this.zoneStrokeStyle; ctx.lineWidth = this.zoneLineWidth;