From: dsc Date: Fri, 25 Mar 2011 10:53:39 +0000 (-0700) Subject: Adds barrel object and config. X-Git-Url: http://git.less.ly:3516/?a=commitdiff_plain;h=9ddc63e74d74176b25e8bdfbe34bd94ed836b37c;p=tanks.git Adds barrel object and config. --- diff --git a/data/types/units.yaml b/data/types/units.yaml index c0bb747..d1913d0 100644 --- a/data/types/units.yaml +++ b/data/types/units.yaml @@ -20,6 +20,13 @@ defaults: dodge : 1.00 # dodge an incoming bullet shootIncoming : 0.25 # shoot down incoming bullet shootEnemy : 0.75 # shoot at enemy tank if in range + barrel: + width : unit.width * 0.75 + height : unit.height / 6 + originX : 2 + originY : 50% + x : 50% + y : 50% art: map_icon: '' inv_icon: '' diff --git a/src/Y/modules/y.polyevent.cjs b/src/Y/modules/y.polyevent.cjs index 56638e8..312167a 100644 --- a/src/Y/modules/y.polyevent.cjs +++ b/src/Y/modules/y.polyevent.cjs @@ -274,4 +274,6 @@ function setupRepeater(fromEmitter, toEmitter, evt){ } Y.extend( exports, { 'repeat':repeat, 'setupRepeater':setupRepeater }); -Y.extend( Y['event'], exports ); +Y['polyevent'] = exports; + +Y.extend( Y['event'], { 'PolyEmitter':PolyEmitter, 'PolyEvent':PolyEvent, 'repeat':repeat, 'setupRepeater':setupRepeater }); diff --git a/src/Y/op.cjs b/src/Y/op.cjs index 5b7aeed..447e857 100644 --- a/src/Y/op.cjs +++ b/src/Y/op.cjs @@ -43,6 +43,7 @@ var core = require('Y/core') K : function(k){ return function(){ return k; }; }, kObject : function(){ return {}; }, kArray : function(){ return []; }, + kThis : function(){ return this; }, val : function(def,o){ return o !== undefined ? o : def; }, ok : function(o){ return o !== undefined && o !== null; }, first : function(a){ return a; }, diff --git a/src/Y/types/array.cjs b/src/Y/types/array.cjs index 011cb36..ab3a1fd 100644 --- a/src/Y/types/array.cjs +++ b/src/Y/types/array.cjs @@ -159,12 +159,12 @@ YCollection.subclass('YArray', function(YArray){ this['unique'] = function unique(){ - return this.reduce( + return new YArray( this._o.reduce( function(acc, v, i){ if (acc.indexOf(v) === -1) acc.push(v); return acc; - }, new YArray(), this); + }, [], this) ); }; YArray.flatten = flatten; diff --git a/src/Y/types/collection.cjs b/src/Y/types/collection.cjs index d30fbcf..8055012 100644 --- a/src/Y/types/collection.cjs +++ b/src/Y/types/collection.cjs @@ -98,7 +98,7 @@ YBase.subclass('YCollection', { }, new this.__class__() ); }, - amap : function amap( fn ){ + 'amap' : function amap( fn ){ var cxt = arguments[1] || this; return this.reduce(function(acc, v, k, o){ return acc.push(fn.call(cxt, v, k, o)); @@ -121,6 +121,15 @@ YBase.subclass('YCollection', { return -1; }, + 'lastIndexOf' : function lastIndexOf( value ){ + var o = this._o + , idx = -1; + for ( var name in o ) + if ( o[name] === value ) + idx = name; + return idx; + }, + 'has' : function has( value ){ return ( this.indexOf(value) !== -1 ); }, @@ -132,7 +141,7 @@ YBase.subclass('YCollection', { }, true); }, - 'any' : function any( fn ){ + 'some' : function some( fn ){ var self = this, fn = fn || op.bool; return this.reduce(function(acc, v, k, o){ return acc || fn.call(self, v, k, o); @@ -180,7 +189,31 @@ YBase.subclass('YCollection', { 'intersect' : function intersect(a){ var A = Y(a); return this.filter(A.has, A); - } + }, + + // /** + // * Set Union (A v B) + // * @param {Array|Object|YCollection} a Comparison collection. + // * @return {YArray} A new YArray of all elements in both collections, but without duplicates. + // */ + // 'union' : function union(a){ + // return this.clone().extend(a).unique(); + // }, + // + // /** + // * Set Difference (A - B) + // * @param {Array|Object|YCollection} a Comparison collection. + // * @return {YArray} A new YArray of only elements in this not in supplied collection. + // */ + // 'difference' : function difference(a){ + // var A = Y(a); + // return this.filter(Y(A.has).compose(op.not), A); + // }, + // + // // Symmetric Difference + // 'xor' : function xor(a){ + // return this.difference(a).extend( Y(a).difference(this) ); + // } }); diff --git a/src/Y/utils.cjs b/src/Y/utils.cjs index d3b94a1..52d1de7 100644 --- a/src/Y/utils.cjs +++ b/src/Y/utils.cjs @@ -92,17 +92,17 @@ function proxy(options){ // TODO: Throw errors on invalid values - if (isFunction(target)) target = target.prototype; - if (isFunction(donor)) donor = donor.prototype; - if (!isArray(names)) names = [names]; + if (typeof target == 'function') target = target.prototype; + if (typeof donor == 'function') donor = donor.prototype; + if (!isArray(names)) names = [names]; // Need a closure to capture the name names.forEach(function(name){ var fn = donor[name]; - if ( !(isFunction(fn) && (o.override || !(name in target))) ) + if ( !(typeof fn == 'function' && (o.override || !(name in target))) ) return; - target[name] = function(){ + var wrapper = target[name] = function(){ var A = arguments, r, context; if (o.fnFirst) @@ -118,6 +118,7 @@ function proxy(options){ r = fn.apply(context, A); return (o.chain ? this : (o.wrap ? o.wrap(r) : r)); }; + wrapper.name = name; // works in webkit }); return o; diff --git a/src/ezl/layer/layerable.cjs b/src/ezl/layer/layerable.cjs index 3d19d0e..83cea06 100644 --- a/src/ezl/layer/layerable.cjs +++ b/src/ezl/layer/layerable.cjs @@ -13,6 +13,7 @@ var Y = require('Y').Y CONTEXT_ATTRS = Y('globalAlpha globalCompositeOperation strokeStyle fillStyle lineWidth lineCap lineJoin miterLimit shadowOffsetX shadowOffsetY shadowBlur shadowColor'.split(' ')), FAUX_ACCESSORS = Y('width height position stroke fill origin rotate scale translate title'.split(' ')) , _X = 0, _Y = 1 +, CALC_LOC = new Loc(0,0) , @@ -365,7 +366,18 @@ Mixin.subclass('Layerable', { if (x === null || x === undefined) x = bb.x1; if (y === null || y === undefined) y = bb.y1; - var bb = this.bbox; + var p = this.parent + , bb = this.bbox + , sx = (typeof x == 'string') // TODO: store and recalc on w/h change + , sy = (typeof y == 'string') + ; + if (sx || sy) { + if (!p) return this; + var xy = CALC_LOC.setXY(x,y).absolute(p.realWidth, p.realHeight); + x = xy.x; + y = xy.y; + } + if (x === bb.x1 && y === bb.y1) return this; diff --git a/src/ezl/struct/set.cjs b/src/ezl/struct/set.cjs new file mode 100644 index 0000000..0488796 --- /dev/null +++ b/src/ezl/struct/set.cjs @@ -0,0 +1,226 @@ +var Y = require('Y').Y +, op = require('Y/op') +, proxy = require('Y/utils').proxy +, YCollection = require('Y/types/collection').YCollection +, slice = Array.prototype.slice +, + + +Set = +exports['Set'] = +YCollection.subclass('Set', null, function setupSet(Set){ + Y.extend(this, { + _byId : {}, + }); + + this['init'] = + function initSet(){ + this._o = new Y.YArray(); + this._byId = {}; + if ( arguments.length ) + this.update( arguments ); + }; + + var size = + this['size'] = + function size(){ + return this._o.length; + }; + + this['attr'] = op.attr.methodize(); + Object.defineProperty(this, 'length', { 'get':size }); + + this['clone'] = + function clone(){ + return new Set(this._o); + }; + + this['clear'] = + function clear(){ + this._o = new Y.YArray(); + this._byId = {}; + return this; + }; + + this['indexOf'] = + this['lastIndexOf'] = + function unsupported(){ + throw new Error(arguments.callee.name+' is unsupported for type '+this.className+'!'); + }; + + function _getIdSafe(v){ + switch (typeof v) { + case 'undefined': + return undefined; + break; + + case 'boolean': + case 'string': + case 'number': + return v; + break; + + case 'object': + case 'function': + default: + if ( !('__id__' in v) ) + return undefined; + else + return v.__id__; + break; + } + } + + this['_getId'] = + function _getId(v){ + var id = _getIdSafe(v); + if (id === undefined) + throw new Error('All Set elements must be hashable! v='+v); + else + return id; + }; + + this['has'] = + function has(v){ + return (_getIdSafe(v) in this._byId); + }; + + function addIt(v){ + var id = this._getId(v); + + if (!(id in this._byId)) { + this._byId[id] = v; + this._o.push(v); + } + + return this; + } + + this['add'] = + this['push'] = + this['unshift'] = + function add(v){ + var L = arguments.length; + + if (L === 1) + addIt.call(this, v); + else if (L > 1) + slice.call(arguments,0).forEach(addIt, this); + + return this; + }; + + this['update'] = + this['extend'] = + function update(vs){ + Y(vs).forEach(addIt, this); + return this; + }; + + this['join'] = + function join(vs){ + return this.clone().update(vs); + }; + + function removeIt(v){ + var id = this._getId(v); + + if ( id in this._byId ) { + delete this._byId[id]; + this._o.splice(this._o.indexOf(v), 1); + } + + return this; + } + + this['remove'] = + this['discard'] = + function remove(v){ + var L = arguments.length; + + if (L === 1) + removeIt.call(this, v); + else if (L > 1) + slice.call(arguments,0).forEach(removeIt, this); + + return this; + }; + + this['shift'] = + this['pop'] = + function shift(){ + if (!this._o.length) return; + + var v = this._o.shift() + , id = this._getId(v); + delete this._byId[id]; + return v; + }; + + this['unique'] = op.kThis; + + /** + * Tests if `a` is a Collection and has all elements in common with the set. + * Sets are equal if and only if their intersection has the same size as both sets. + * @param {Collection} a + * @return {Boolean} + */ + this['equals'] = + function equals(a){ + if (!a) return false; + var L = this._o.length; + return (L === a.length) && (L === this.intersect(a).length); + }; + + /** + * Tests if the set has no elements in common with `a`. + * Sets are disjoint if and only if their intersection is the empty set. + * @param {Collection} a + * @return {Boolean} + */ + this['isDisjoint'] = + function isDisjoint(a){ + if (!a) return true; + return !Y(a).some(this.has, this); + }; + + /** + * Test whether every element in the set is in `a`. + * @param {Collection} a + * @return {Boolean} + */ + this['isSubset'] = + function isSubset(a){ + if (!a) return false; + var A = Y(a); + return this.every(A.has, A); + }; + + /** + * Test whether every element in `a` is in the set. + * @param {Collection} a + * @return {Boolean} + */ + this['isSuperset'] = + function isSuperset(a){ + if (!a) return false; + return Y(a).every(this.has, this); + }; + + this['toString'] = function(){ + return "Set(["+this._o+"])"; + }; + +}); + +var YArray = Y.YArray +, newSet = Set.instantiate; + +proxy({ target:Set, donor:YArray, context:'_o', + names:['sort', 'zip'] }); +proxy({ target:Set, donor:YArray, context:'_o', wrap:newSet, + names:['concat'] }); +proxy({ target:Set, donor:YArray, context:'_o', fnFirst:true, wrap:newSet, + names:'map forEach filter intersect union difference xor'.split(' ') }); +proxy({ target:Set, donor:YArray, context:'_o', fnFirst:true, + names:'reduce some every'.split(' ') }); diff --git a/src/ezl/util/tree/pointquadtree.cjs b/src/ezl/util/tree/pointquadtree.cjs index 38b7222..19745fd 100644 --- a/src/ezl/util/tree/pointquadtree.cjs +++ b/src/ezl/util/tree/pointquadtree.cjs @@ -212,9 +212,9 @@ PointQuadTree = Y.subclass('PointQuadTree', { _inSubrange : function _inSubrange(x1,y1, x2,y2){ if (arguments.length === 4) - return this._ranges.invoke('containsRange', x1,y1, x2,y2).any(); + return this._ranges.invoke('containsRange', x1,y1, x2,y2).some(); else - return this._ranges.invoke('contains', x1,y1).any(); + return this._ranges.invoke('contains', x1,y1).some(); }, // XXX: Hm. Should this be contains ALL or contains ANY for the range query? diff --git a/src/tanks/inventory/inventory.cjs b/src/tanks/inventory/inventory.cjs index d8cd401..c772d34 100644 --- a/src/tanks/inventory/inventory.cjs +++ b/src/tanks/inventory/inventory.cjs @@ -94,7 +94,7 @@ evt.subclass('Inventory', { */ canAddItem : function canAddItem(item, bag){ if (bag === undefined) - return this._bags.invoke('canAddItem', item).any(); + return this._bags.invoke('canAddItem', item).some(); bag = this.getBag(bag); return bag && bag.canAddItem(item); }, diff --git a/src/tanks/thing/player.cjs b/src/tanks/thing/player.cjs index 0805a3d..aefeea3 100644 --- a/src/tanks/thing/player.cjs +++ b/src/tanks/thing/player.cjs @@ -140,7 +140,7 @@ Tank.subclass('Player', { attack : function attack(x,y){ if ( x === undefined || y === undefined ) { - var theta = this.barrel.transform.rotate + var theta = this.barrelShape.transform.rotate , sin = Math.sin(theta), cos = Math.cos(theta) , t = this.getTurretLoc(); x = t.x + REF_SIZE*cos; diff --git a/src/tanks/thing/tank.cjs b/src/tanks/thing/tank.cjs index 7eae81e..ffe8c34 100644 --- a/src/tanks/thing/tank.cjs +++ b/src/tanks/thing/tank.cjs @@ -12,11 +12,12 @@ var Y = require('Y').Y , constants = require('tanks/constants') , BoundsType = constants.BoundsType , DensityType = constants.DensityType -, LinearTrajectory = require('tanks/map/pathing/linear-trajectory').LinearTrajectory +, LinearTrajectory = require('tanks/map/pathing/linear-trajectory').LinearTrajectory , Traversal = require('tanks/map/pathing/traversal').Traversal , Thing = require('tanks/thing/thing').Thing , Bullet = require('tanks/thing/bullet').Bullet , Lootable = require('tanks/mixins/lootable').Lootable +, Barrel = require('tanks/fx/barrel').Barrel , _X = 0, _Y = 1 , @@ -36,6 +37,15 @@ Thing.subclass('Tank', function(Tank){ barrel : '#D43B24' }, + barrel: { + width : 'unit.width * 0.75', + height : 'unit.height / 6', + originX : 2, + originY : '50%', + x : '50%', + y : '50%' + }, + // Bounding box width : REF_SIZE*0.55, height : REF_SIZE*0.55, @@ -173,7 +183,7 @@ Thing.subclass('Tank', function(Tank){ return null; // console.log('squelch!', blockers); if (!xydef) { - var theta = this.barrel.transform.rotate + var theta = this.barrelShape.transform.rotate , sin = Math.sin(theta), cos = Math.cos(theta); x = tx + REF_SIZE*cos; y = ty + REF_SIZE*sin; @@ -284,7 +294,7 @@ Thing.subclass('Tank', function(Tank){ function getTurretLoc(){ var WIGGLE = 2 , loc = this.loc - , barrel = this.barrel + , barrel = this.barrelShape , theta = barrel.transform.rotate , sin = Math.sin(theta), cos = Math.cos(theta) @@ -316,10 +326,7 @@ Thing.subclass('Tank', function(Tank){ var colors = this.colors , w = this.width, w2 = w/2 , h = this.height, h2 = h/2 - , r = w / 4 - , bw = w * 0.75 - , bh = h / 6 ; this.shape = @@ -338,12 +345,15 @@ Thing.subclass('Tank', function(Tank){ .fill(colors.turret) .appendTo( this.shape ) ; - this.barrel = - new Rect(bw,bh) - .position(w2-2, h2-bh/2) - .origin(2, bh/2) - .fill(colors.barrel) - .appendTo( this.shape ) ; + var b = Y.map(this.barrel, calcValue, this); + + this.barrelShape = + new Barrel(b.width,b.height, b.originX,b.originY) + .appendTo( this.shape ) // have to append early to avoid problems with relative positioning + .position(b.x, b.y) + // .position(w2-2, h2-bh/2) + // .origin(2, bh/2) + .fill( colors.barrel ) ; return this; }; @@ -362,7 +372,7 @@ Thing.subclass('Tank', function(Tank){ this['rotateBarrel'] = function rotateBarrel(x,y){ - this.barrel.rotate(this.angleTo(x,y)); + this.barrelShape.rotate(this.angleTo(x,y)); return this; }; @@ -375,9 +385,15 @@ Thing.subclass('Tank', function(Tank){ , y = off.top + h/2 - pageY , theta = Math.atan2(-y,-x) ; - this.barrel.rotate(theta); + this.barrelShape.rotate(theta); return this; }; }); +var NUM_OR_PERCENT = /^\s*[\d\.]+\s*%?\s*$/; +function calcValue(v){ + var unit = this; + return ( NUM_OR_PERCENT.test(v) ? v : eval(v) ); +} +