From: dsc Date: Sat, 12 Mar 2011 20:00:23 +0000 (-0800) Subject: Adds Barrel class to pull it apart from a unit's sprite. X-Git-Url: http://git.less.ly:3516/?a=commitdiff_plain;h=7e29a81fc3742753e492fb4960494ed60702b563;p=tanks.git Adds Barrel class to pull it apart from a unit's sprite. --- diff --git a/data/types/units.yaml b/data/types/units.yaml index 4fbbada..c0bb747 100644 --- a/data/types/units.yaml +++ b/data/types/units.yaml @@ -122,10 +122,11 @@ types: hp : 1 move : 0.5 power : 1 - orbit : 9 - width : 9 - height : 9 - color: '#0A9CFF' - + orbit : 8 + width : 8 + height : 8 + colors: + body : '#0A9CFF' + shine : '#195FBC' diff --git a/src/ezl/layer/layerable.cjs b/src/ezl/layer/layerable.cjs index 40af4a6..3d19d0e 100644 --- a/src/ezl/layer/layerable.cjs +++ b/src/ezl/layer/layerable.cjs @@ -249,7 +249,6 @@ Mixin.subclass('Layerable', { return new Vec(this.layerWidth,this.layerHeight); var bb = this.bbox - , ox1 = bb.x1, oy1 = bb.y1 , ow = this.realWidth, lw, olw = lw = this.layerWidth, cw , oh = this.realHeight, lh, olh = lh = this.layerHeight, ch , changes = {}, cchanges = {} @@ -263,7 +262,7 @@ Mixin.subclass('Layerable', { this.realWidth = w; lw = Math.round(w); // HTMLElement.{width,height} is a long if (lw !== olw) { - this.layerWidth = changes.width = lw; + this.layerWidth = changes.width = lw; this.canvasWidth = cchanges.width = cw = Math.ceil(w); dirtied = true; } @@ -273,7 +272,7 @@ Mixin.subclass('Layerable', { this.realHeight = h; lh = Math.round(h); // HTMLElement.{width,height} is a long if (lh !== olh) { - this.layerHeight = changes.height = lh; + this.layerHeight = changes.height = lh; this.canvasHeight = cchanges.height = ch = Math.ceil(h); dirtied = true; } @@ -284,10 +283,10 @@ Mixin.subclass('Layerable', { var x1 = bb.x1 | 0 , y1 = bb.y1 | 0; - if (ox1 !== x1) - changes.left = x1; - if (oy1 !== y1) - changes.top = y1; + if (x1 !== this.layerX) + changes.left = this.layerX = x1; + if (y1 !== this.layerY) + changes.top = this.layerY = y1; this.layer.css(changes); @@ -420,6 +419,20 @@ Mixin.subclass('Layerable', { scrollWidth : function scrollWidth(v){ return this.layer.attr('scrollWidth', v); }, scrollHeight : function scrollHeight(v){ return this.layer.attr('scrollHeight', v); }, + /** + * Calculates angle in radians from the Layer's origin to (x,y). + * @param {Number} x + * @param {Number} y + * @return {Number} Angle in radians. + */ + angleTo : function angleTo(x,y){ + var loc = this.loc + , x0 = x - loc.x + , y0 = y - loc.y + ; + return Math.atan2(y0,x0); + }, + /// Transformations /// @@ -441,14 +454,25 @@ Mixin.subclass('Layerable', { }, /** + * @return {Number} The layer's current angle of rotation in radians. + */ + /** * Rotates this layer by r radians. + * @param {Number} r Radians to rotate. + * @return {this} + */ + /** + * Rotates this layer by the angle between the layer's origin and (x,y). + * @param {Number} x + * @param {Number} y + * @return {this} */ - rotate : function rotate(r){ + rotate : function rotate(x,y){ var t = this.transform; - if (r === undefined) + if (x === undefined && y === undefined) return t.rotate; - t.rotate = r; + t.rotate = (y === undefined ? x : this.angleTo(x,y)); return this._applyTransforms(); }, @@ -630,24 +654,58 @@ Mixin.subclass('Layerable', { return this; }, - erase : function erase(x,y, w,h, alsoChildren){ - this._erased.push({ 'x':x,'y':y, 'w':w,'h':h, 'alsoChildren':alsoChildren }); + eraseRect : function eraseRect(x,y, w,h, alsoChildren){ + return this._addErasedPath('rect', x,y, { 'w':w,'h':h }, alsoChildren); + }, + + eraseCircle : function eraseCircle(x,y, r, alsoChildren){ + return this._addErasedPath('circle', x,y, { 'r':r }, alsoChildren); + }, + + _addErasedPath : function _addErasedPath(type, x,y, args, alsoChildren){ + this._erased.push( Y.extend({ 'type':type, 'x':x,'y':y, 'alsoChildren':alsoChildren }, args||{}) ); this.dirty = true; if (alsoChildren) - this.children.invoke('erase', x,y, w,h, alsoChildren); + this.children.invoke('_addErasedPath', x,y, args, alsoChildren); return this; }, _erase : function _erase(args){ - var x = args.x, y = args.y - , w = args.w, h = args.h; + var ctx = this.ctx + , gco = ctx.globalCompositeOperation + + , pw = this.canvas.width() + , ph = this.canvas.height() + + , type = args.type + , x = args.x, y = args.y + ; - if (w < 0) w = this.canvas.width() + w; - if (h < 0) h = this.canvas.height() + h; + ctx.beginPath(); + ctx.fillStyle = '#000000'; + ctx.lineWidth = 0; + + switch (args.type) { + case 'rect': + var w = args.w, h = args.h; + if (w < 0) w = pw + w; + if (h < 0) h = ph + h; + ctx.clearRect(x,y, w,h); + break; + + case 'circle': + var r = args.r; + if (r <= 0) r = Math.min(pw-x,ph-y)/2 + (r || 0); + ctx.globalCompositeOperation = 'destination-out'; + ctx.arc(x,y, r, 0, Math.PI*2, false); + ctx.fill(); + break; + + default: break; + } - this.ctx.beginPath(); - this.ctx.clearRect(x,y, w,h); - this.ctx.closePath(); + ctx.closePath(); + ctx.globalCompositeOperation = gco; }, /** @@ -757,7 +815,7 @@ Mixin.subclass('Layerable', { ; // Check we're in the DOM, otherwise jQuery vomits if ( el && el.attr('parentNode') ) - pos = this.position(); + pos = el.position(); return this.className+'['+pos.left+','+pos.top+']( children='+kids+' )'; } }); diff --git a/src/ezl/shape/rect.cjs b/src/ezl/shape/rect.cjs index 2918a2b..3cce462 100644 --- a/src/ezl/shape/rect.cjs +++ b/src/ezl/shape/rect.cjs @@ -20,10 +20,10 @@ Shape.subclass('Rect', { }, toString : function(){ - var loc = this.loc - , x1 = loc.x, y1 = loc.y - , x2 = x1+this.layerWidth, y2 = y1 + this.layerHeight; - return this.className+'['+x1+','+y1+', '+x2+','+y2+'](w='+this.layerWidth+', h='+this.layerHeight+')'; + // var loc = this.loc + // , x1 = loc.x, y1 = loc.y + // , x2 = x1+this.layerWidth, y2 = y1 + this.layerHeight; + return this.className+this.bbox+'(w='+this.layerWidth+', h='+this.layerHeight+')'; } }); diff --git a/src/tanks/fx/barrel.cjs b/src/tanks/fx/barrel.cjs new file mode 100644 index 0000000..339969f --- /dev/null +++ b/src/tanks/fx/barrel.cjs @@ -0,0 +1,77 @@ +var Y = require('Y').Y +, Vec = require('ezl/math/vec').Vec +, Rect = require('ezl/shape').Rect + +// , ORIGIN = new Vec(0,0) +// , FACING_RIGHT = exports['FACING_RIGHT'] = 'right' +// , FACING_LEFT = exports['FACING_LEFT'] = 'left' +, + +Barrel = +exports['Barrel'] = +Rect.subclass('Barrel', { + originX : 0, + originY : '50%', + // facing : FACING_RIGHT, + + + /** + * @constructor + * @param {Number} width + * @param {Number} height + * @param {Number|String} [pivotX=0] x coordinate of pivot point (in pixels or as a percentage of width). + * @param {Number} [pivotY='50%'] y coordinate of pivot point (in pixels or as a percentage of height). + * @return {this} + */ + init : function initBarrel(w,h, pivotX,pivotY){ + this.originX = pivotX || 0; + this.originY = pivotY || '50%'; + // this.facing = facing || FACING_RIGHT; + Rect.init.call(this, w,h); + }, + + + /** + * Converts (pageX,pageY) from global to local coordinates (x,y), and then + * rotates this layer by the angle between the layer's origin and (x,y). + * @param {Number} pageX + * @param {Number} pageY + * @return {this} + */ + rotateRelPage : function rotateRelPage(pageX,pageY){ + var off = this.offset() + , w = this.realWidth, h = this.realHeight + , x = off.left + w/2 - pageX + , y = off.top + h/2 - pageY + , theta = Math.atan2(-y,-x) + ; + return this.rotate(theta); + }, + + /** + * Calculates the coordinates of the barrel tip based on barrel facing and rotation. + * @param {Number} [wiggle=0] Optional offset distance in front of the barrel tip. + * @param {Boolean} [relParent=false] If true, coordinates will be relative to parent's origin. + * @return {Vec} Coordinates of barrel tip (with offset). + */ + barrelTipLoc : function barrelTipLoc(wiggle, relParent){ + var theta = this.transform.rotate + , sin = Math.sin(theta), cos = Math.cos(theta) + + // (sqrt(2)/2 * wiggle) is max diagonal to ensure projectile doesn't overlap with firing unit + , len = this.bbox.originRight + (wiggle || 0)*0.707 + + // , len = this.bbox.originDist(this.facing) + (wiggle || 0)*0.707 + // , olen = (this.facing === FACING_LEFT ? this.bbox.originLeft : this.bbox.originRight) + // , len = olen + (wiggle || 0)*0.707 + + , o = ((relParent && this.parent) ? this.parent.loc : ORIGIN) + , x = o.x + this.loc.x + len*cos + , y = o.y + this.loc.y + len*sin + ; + return new Vec(x,y); + } + + +}) +; diff --git a/src/tanks/fx/index.cjs b/src/tanks/fx/index.cjs index aa388b6..698054c 100644 --- a/src/tanks/fx/index.cjs +++ b/src/tanks/fx/index.cjs @@ -1,5 +1,8 @@ -var Y = require('Y').Y; - -Y.extend(exports, { - 'Explosion' : require('tanks/fx/explosion').Explosion -}); \ No newline at end of file +var Y = require('Y').Y +, barrel = require('tanks/fx/barrel') +, explosion = require('tanks/fx/explosion') +; +Y.core.extend(exports, { + 'Barrel' : barrel.Barrel, + 'Explosion' : explosion.Explosion +}); diff --git a/src/tanks/map/pit.cjs b/src/tanks/map/pit.cjs index c562065..271f686 100644 --- a/src/tanks/map/pit.cjs +++ b/src/tanks/map/pit.cjs @@ -56,7 +56,7 @@ Wall.subclass('Pit', { .position(0,0) .fill(this.shadowFillStyle) .stroke(this.strokeStyle, this.lineWidth) - .erase(ss,ss, -ss,-ss) + .eraseRect(ss,ss, -ss,-ss) .appendTo( this.shape ); return this; diff --git a/src/tanks/thing/shield.cjs b/src/tanks/thing/shield.cjs index 43a2820..3a74f7d 100644 --- a/src/tanks/thing/shield.cjs +++ b/src/tanks/thing/shield.cjs @@ -28,11 +28,14 @@ Component.subclass('Shield', { isReflective : false, // Projectiles bounce off agent rather than explode? hasInventory : false, // Agent can acquire items? - orbit : 9, - width : 9, - height : 9, + orbit : 8, + width : 8, + height : 8, - color : '#0A9CFF', + colors: { + body : '#0A9CFF', + shine : '#195FBC' + }, stats : {}, // radial speed in revolutions/sec @@ -52,6 +55,7 @@ Component.subclass('Shield', { this.radsPerTick = TWO_PI * this.stats.move.val / 1000 * MS_PER_FRAME; this.trajectory = new CircularTrajectory(this, oloc.x,oloc.y, this.radius, this.radsPerTick, this.radialPosition); + this.colors = Y.extend({}, this.colors); this.act(0); }, @@ -70,26 +74,26 @@ Component.subclass('Shield', { , to = tvsl.traverse(this.radsPerTick); this.game.moveThingTo(this, to.x,to.y); - - // var oloc = this.owner.loc - // , t = (this.radialPosition += this.radsPerTick) - // , r = this.radius - // , x = oloc.x + r*Math.cos(t) - // , y = oloc.y + r*Math.sin(t) - // ; - // this.game.moveThingTo(this, x,y); return this; }, render : function render(parent){ this.remove(); - var loc = this.loc; - this.shape = new Circle(this.width/2) + var loc = this.loc + , d = this.width, r = d/2; + + this.shape = new Circle(r) .position(loc.x, loc.y) - .fill(this.color) + .fill(this.colors.body) .appendTo( parent ); + this.shine = new Circle(r) + .position(r,r) + .fill(this.colors.shine) + // .eraseCircle(-r,-r, d*SQRT_TWO) + .eraseCircle(r*0.2,-r*1.5, 1.1*d*SQRT_TWO) + .appendTo( this.shape ); return this; } })