createGridTable : false
showGridCoords : false
showFpsGraph : false
+ allowViewportScroll : false
map:
refSize : &ref_size 50
rockSizeMin : 12.5
lootTable : ''
stats:
hp : 1 # health
- move : 1.0 # move speed (squares/sec)
+ move : 1.0 # move speed (squares/sec or orbits/sec)
+ rotate : 1.0 # rotation speed (full-turns/sec)
power : 1 # attack power
speed : 0.5 # attack cool (sec)
accuracy : 1.0 # chance of shooting where aiming
turret : '#C13B00'
barrel : '#244792'
-
+ shield:
+ name: Shield Sphere
+ desc: A protective sphere of energy.
+ tags: [ 'shield' ]
+ symbol: tanks/thing/shield.Shield
+ stats:
+ hp : 1
+ move : 0.5
+ power : 1
+ orbit : 9
+ width : 9
+ height : 9
+ color: '#0A9CFF'
+
+
with path('build/versioned-build.html').open('w') as f:
f.write('<script>BUILD="build/{}";</script>\n'.format(git_version))
with path('build/versioned-app.html').open('w') as f:
- f.write('<script src="build/{}/{}";</script>\n'.format(git_version, APP_FILE))
+ f.write('<script src="build/{}/{}"></script>\n'.format(git_version, APP_FILE))
@task
"Builds the Tanks project"
pass
+
+
@task
@needs('build')
def compress(outfile='build/'+APP_FILE, yuic_jar='~/bin/yuic.jar'):
sh('cat %s | java -jar %s --type js -o %s' % (mods.replace('\n', ' '), yuic_jar, outfile))
@task
+@needs('build')
+def compress_each(yuic_jar='~/bin/yuic.jar'):
+ yuic_jar = path(yuic_jar).expand()
+ info('Compressing Each Source File (YUI Compressor=%s)' % yuic_jar)
+ for dirpath, dirs, files in os.walk(BUILD_DIR):
+ dirpath = path(dirpath)
+ for f in files:
+ if not f.endswith('.js') or f.endswith('.min.js'):
+ continue
+ in_ = dirpath / f
+ out = dirpath / f[:-3] + '.min.js'
+ sh('java -jar %s --type js -o %s %s' % (yuic_jar, out, in_))
+
+@task
+def combine_all(outfile='build/'+APP_FILE, minified=True, add_newlines=True):
+ info('Concatenating Source Files')
+ mods = commonjs(file_list=True, capture=True)
+ if minified:
+ mods = mods.replace('.js\n', '.min.js\n')
+ if add_newlines:
+ sh('echo "" > .NL')
+ modlist = mods.replace('\n', ' .NL ')
+ else:
+ modlist = mods.replace('\n', ' ')
+
+ sh('cat %s > %s' % (modlist, outfile))
+
+ if add_newlines:
+ sh('rm .NL')
+
+@task
def clean():
"Cleans dep cache and build files"
commonjs(clean=True)
parentMembers = Parent[P] || {};
}
- // Creates a new function with the appropriate name
- // based on the className.
- var NewClass, constructor =
- 'var '+className+' = NewClass = '+
- (''+_Class).replace(_Class.name, className) + ';';
- eval(constructor);
+ // Creates a new function with the appropriate name based on the className.
+ var constructor = ('('+_Class+')').replace(_Class.name, className)
+ , NewClass = eval(constructor);
// Copy Class statics
for (var i=0, L=classStatics.length; i<L; ++i) {
prototype.toString = classToString;
// Fix Constructors, prototypes
- NewClass[P] = NewClass.fn = prototype;
- prototype.constructor = prototype.__class__ = NewClass;
- NewClass.__super__ = SuperClass; // don't override NewClass.constructor -- it should be Function
- NewClass.className = prototype.className = className;
+ NewClass[P] = NewClass['fn'] = prototype;
+ prototype['constructor'] = prototype['__class__'] = NewClass;
+ NewClass['__super__'] = SuperClass; // don't override NewClass.constructor -- it should be Function
+ NewClass['className'] = prototype['className'] = className;
// Either invoke body constructor...
if ( isFunction(members) ) {
setDesc(prototype, k, getDesc(members,k));
}
- if (prototype.init) NewClass.init = YFunction(prototype.init);
+ if (prototype.init) NewClass['init'] = YFunction(prototype.init);
KNOWN_CLASSES[className] = NewClass;
}
// Add metaprogramming data to Class object
-Class.__super__ = Object;
-Class.fn = Class[P];
-Class.fn.__class__ = Class;
-Class.className = Class.fn.className = "Class";
+Class['__super__'] = Object;
+Class['fn'] = Class[P];
+Class.fn['__class__'] = Class;
+Class['className'] = Class.fn['className'] = "Class";
/* Class Methods */
return new Class(className, this, members);
}
-Class.subclass =
-Class.fn.subclass = YFunction(subclass);
+Class['subclass'] =
+Class.fn['subclass'] = YFunction(subclass);
[ fabricate, instantiate
* Root-class for all Y-objects.
*/
YBase = new Class("YBase", {
- __y__ : true
+ '__y__' : true
});
exports['Class'] =
-exports['subclass'] = Class;
-exports['YBase'] = YBase;
+exports['subclass'] = Class;
+exports['YBase'] = YBase;
// exports['instantiate'] = instantiate;
// exports['fabricate'] = fabricate;
// Creates a new function with the appropriate name
// based on the className.
- var NewClass,
- constructor = [
- 'var '+className,
- (''+ConstructorTemplate).replace(ConstructorTemplate.name, className),
- 'NewClass = '+className, ''
- ].join(';\n');
-
- eval(constructor);
+ var constructor = ('('+ConstructorTemplate+')').replace(ConstructorTemplate.name, className);
+ // var NewClass, constructor =
+ // 'var NewClass, '+className+' = NewClass = '+
+ // (''+_Class).replace(_Class.name, className) + ';';
+ var NewClass = eval(constructor);
// Copy parent methods, then add new instance methods
for (var k in parentMembers) {
--- /dev/null
+var Y = require('Y').Y
+, Vec = require('ezl/math/vec').Vec
+, _X = 0, _Y = 1
+,
+
+Circle =
+exports['Circle'] =
+Y.subclass('Circle', {
+ isCircle : true,
+
+ init : function initCircle(x,y, radius){
+ if (x instanceof Array) { radius=y; y=x[_Y]; x=x[_X]; }
+ this.x = x; // center of circle
+ this.y = y;
+ this.radius = radius;
+ },
+
+ get loc(){ return new Vec(this.x,this.y); },
+ set loc(v){ this.x = v.x; this.y = v.y; },
+
+ parametric : function parametric(t){
+ var r = this.radius
+ , x = this.x + r*Math.cos(t)
+ , y = this.y + r*Math.sin(t)
+ ;
+ return new Vec(x,y);
+ },
+
+ iparametric : function iparametric(x,y){
+ if (x instanceof Array) { y=x[_Y]; x=x[_X]; }
+ var r = this.radius
+ , tx = Math.acos((x - this.x) / r)
+ , ty = Math.asin((y - this.y) / r)
+ ;
+ // tx and ty should be the same number provided (x,y) is on the trajectory
+ return (tx+ty) * 0.5;
+ },
+
+ timeToMove : function timeToMove(dx,dy){
+ if (dx instanceof Array) { dy=dx[1]; dx=dx[0]; }
+ return Math.abs( Math.acos(dx/this.radius) + Math.asin(dy/this.radius) ) * 0.5; // see note at iparametric
+ },
+
+ pointAtX : function pointAtX(x){ return this.parametric(Math.acos((x - this.x)/this.radius)); },
+ pointAtY : function pointAtY(y){ return this.parametric(Math.asin((y - this.y)/this.radius)); }
+
+
+})
+;
-//#exports BoundsType.{PASSABLE,ZONE,BLOCKING,IRREGULAR,COMPLEX}
+//#exports BoundsType.{PASSABLE,ZONE,BLOCKING,IRREGULAR}
//#exports DensityType.{PASSABLE,BOUNDARY,DENSE,SPARSE,IRREGULAR}
//#exports StatInvariant.{NONE,RATIO,FULL}
/** Obstructs other blockers with its BoundingBox. */
BLOCKING : 2,
- /** Potentially obstructs other objects, but requires a special test once a BoundingBox collision has been detected. */
- IRREGULAR : 3,
-
- /** Potentially obstructs other objects, but requires a special test, and may instruct a different object become the target of the collision. */
- COMPLEX : 4
+ /**
+ * Potentially obstructs other objects, but requires a special test once a
+ * BoundingBox collision has been detected, and may instruct a different
+ * object become the target of the collision.
+ */
+ IRREGULAR : 3
},
// Config
gameoverDelay : null,
+ allowViewportScroll : false,
// Instance
levelId : 'test',
this.animations = this.animations.filter(this.tickAnimations, this);
this.draw();
- this.viewport.centerOn( this.player.loc );
+ if ( !this.allowViewportScroll )
+ this.viewport.centerOn( this.player.loc );
if ( this.gameover )
return;
});
-config.updateOnChange('game.gameoverDelay', Game.fn);
+config.updateOnChange(['game.gameoverDelay', 'debug.allowViewportScroll'], Game.fn);
, SECONDTH = ELAPSED / 1000 // Amount of second completed in this tick
, SQUARETH = REF_SIZE * SECONDTH // Amount of square/second covered in this tick
-, PI = Math.PI
-, QUARTER_PI = PI/4
-, HALF_PI = PI/2
-, PI_AND_HALF = PI + HALF_PI
-, TWO_PI = PI*2
-
;
--- /dev/null
+var Y = require('Y').Y
+, op = require('Y/op')
+, Circle = require('ezl/math/circle').Circle
+, BOUND_SIZE_RATIO = 0.75
+,
+
+CircularTrajectory =
+exports['CircularTrajectory'] =
+Circle.subclass('CircularTrajectory', {
+
+ init : function initCircularTrajectory(owner, x,y, radius, radsPerTick, tCurrent){
+ Y.bindAll(this, 'compare'); //, 'closer', 'intersects');
+ this.owner = owner;
+ Circle.init.call(this, x,y, radius);
+ this.radsPerTick = radsPerTick;
+ this.tCurrent = tCurrent || 0;
+ this.tBound = BOUND_SIZE_RATIO * Math.min(owner.width, owner.height);
+ },
+
+ /**
+ * Linear approximation of distance so we don't have to figure out the intersection point.
+ */
+ compare : function compare(a, b){
+ var oa = a, ob = b;
+ if ( a.loc ) a = a.loc;
+ if ( b.loc ) b = b.loc;
+
+ var abs = Math.abs
+ , loc = this.owner.loc
+ , ax = a.x-this.x, ay = a.y-this.y
+ , bx = b.x-this.x, by = b.y-this.y
+ , ta = ax*ax + ay*ay
+ , tb = bx*bx + by*by
+ ;
+
+ return op.cmp(ta, tb);
+ },
+
+ _compare : function compare(a, b){
+ var oa = a, ob = b;
+ if ( a.loc ) a = a.loc;
+ if ( b.loc ) b = b.loc;
+
+ var abs = Math.abs
+ , t = this.tCurrent
+
+ , ta = this.iparametric(a) - t
+ , tb = this.iparametric(b) - t
+ ;
+
+ if (ta < 0 && tb >= 0)
+ return 1;
+ if (tb < 0 && ta >= 0)
+ return -1;
+ return op.cmp(abs(ta), abs(tb));
+ },
+
+})
+;
require('Y').Y
.extend(exports, {
- 'Map' : require('tanks/map/pathing/map').Map,
- 'Traversal' : require('tanks/map/pathing/traversal').Traversal,
- 'Trajectory' : require('tanks/map/pathing/trajectory').Trajectory
+ 'Map' : require('tanks/map/pathing/map').Map,
+ 'Traversal' : require('tanks/map/pathing/traversal').Traversal,
+ 'LinearTrajectory' : require('tanks/map/pathing/linear-trajectory').LinearTrajectory,
+ 'CircularTrajectory' : require('tanks/map/pathing/circular-trajectory').CircularTrajectory
});
,
-Trajectory =
-exports['Trajectory'] =
-Line.subclass('Trajectory', {
+LinearTrajectory =
+exports['LinearTrajectory'] =
+Line.subclass('LinearTrajectory', {
tCurrent : 0,
- init : function initTrajectory(owner, x1,y1, x2,y2, tdist, tCurrent){
+ init : function initLinearTrajectory(owner, x1,y1, x2,y2, tdist, tCurrent){
Y.bindAll(this, 'compare', 'closer', 'intersects');
this.owner = owner;
},
clone : function clone(){
- return new Trajectory(this.owner, this.x1,this.y1, this.x2,this.y2, this.tdist, this.tCurrent);
+ return new LinearTrajectory(this.owner, this.x1,this.y1, this.x2,this.y2, this.tdist, this.tCurrent);
},
_filterBlockers : function _filterBlockers(v){
return (v.blocking === BoundsType.BLOCKING
- || v.blocking === BoundsType.IRREGULAR
- || v.blocking === BoundsType.COMPLEX );
+ || v.blocking === BoundsType.IRREGULAR );
},
wallObstructs : function wallObstructs(line){
_filterBlocked : function filterBlocked(v, r){
// FIXME: calc bbox for new loc to testCollide()
var bbox = null;
- return ( v.blocking === BoundsType.BLOCKING && !(v.isBoundary || v.isProjectile) )
- || ((v.blocking === BoundsType.IRREGULAR || v.blocking === BoundsType.COMPLEX) && v.testCollide(this.agent,this,bbox));
+ return (v.blocking === BoundsType.BLOCKING && !(v.isBoundary || v.isProjectile) )
+ || (v.blocking === BoundsType.IRREGULAR && v.testCollide(this.agent,this,bbox));
},
getNeighbors : function getNeighbors(){
, manhattan = vec.manhattan
, Map = require('tanks/map/pathing/map').Map
-, Trajectory = require('tanks/map/pathing/trajectory').Trajectory
+, LinearTrajectory = require('tanks/map/pathing/linear-trajectory').LinearTrajectory
, Bullet = require('tanks/thing/bullet').Bullet
, _X = 0, _Y = 1
function nearEnemyInSightFilter(agent){
var me = this; // Runs in the context of the 'me' unit; @see this.findNearLike()
return ( agent.isCombatant && agent.align !== me.align &&
- new Trajectory(me, me.loc, agent.loc).canSee(agent) );
+ new LinearTrajectory(me, me.loc, agent.loc).canSee(agent) );
}
Traversal =
exports['Traversal'] =
Y.subclass('Traversal', {
- ignore : null, // objects to ignore when determining blockers
+ thing : null, // agent and its various state-objects
+ game : null,
+ map : null,
+ trajectory : null, // movement path of the agent
+ ignore : null, // objects to ignore when determining blockers
isBlocked : false,
to : null, // furthest point reached
+ bbox : null, // current agent position (cloned)
remaining : 0, // time left unconsumed due to blocker
blocker : null, // blocking object
side : null, // collision side of blocker (Line)
init : function initTraversal(thing, trajectory, ignore){
this.ignore = Y(ignore || []);
- this.thing = thing;
- this.game = thing.game;
- this.map = thing.game.map;
- this.bbox = thing.bbox.clone();
+ this.thing = thing;
+ this.game = thing.game;
+ this.map = thing.game.map;
+ this.bbox = thing.bbox.clone();
this.trajectory = trajectory || thing.trajectory;
},
traverse : function traverse(t, tx,ty){
- var tr = this.trajectory;
this.remaining = t;
do {
* Filters found obstructions to keep only those not ignored and blocking.
*/
checkBlocker : function checkBlocker(blocker){
- var blocking = blocker.blocking
+ var oBlocking = this.thing.blocking
+ , blocking = blocker.blocking
, density = blocker.density;
// All blockers after the first are ignored
// Skip passable objects
|| (blocking === BoundsType.PASSABLE)
- // Ask irregular objects if we hit
- || (blocking === BoundsType.IRREGULAR && !blocker.testCollide(this.thing,this.to,this.bbox,this))
-
- // Ask complex objects if we hit, and recall they might go busta on us
- || blocking === BoundsType.COMPLEX && !blocker.testCollide(this.thing,this.to,this.bbox,this)
+ // Ask irregular objects if we hit (and recall it might change this.ignore or this.blocker)
+ || (oBlocking === BoundsType.IRREGULAR && !this.thing.testCollide(blocker,this.to,null,this))
+ || (blocking === BoundsType.IRREGULAR && !blocker.testCollide(this.thing,this.to,this.bbox,this))
// Filter out Sparse objects if bullet
|| (density === DensityType.SPARSE && this.thing.isProjectile) )
}
this.isBlocked = true;
- if (!this.blocker) this.blocker = blocker; // BoundsType.COMPLEX might switch blockers on us
+ if (!this.blocker) this.blocker = blocker; // BoundsType.IRREGULAR might switch blockers on us
return true;
},