The tank moves!
authordsc <david.schoonover@gmail.com>
Sun, 31 Oct 2010 10:23:23 +0000 (03:23 -0700)
committerdsc <david.schoonover@gmail.com>
Sun, 31 Oct 2010 10:23:23 +0000 (03:23 -0700)
32 files changed:
css/lttl.css
index.php
src/Y/core.js
src/Y/modules/simpleclass.js [moved from src/portal/simpleclass.js with 100% similarity]
src/Y/y-function.js
src/Y/y.js.php
src/js/_intro.js [deleted file]
src/js/_outro.js [deleted file]
src/js/array.js [deleted file]
src/js/core.js [deleted file]
src/js/function.js [deleted file]
src/js/js.js.php [deleted file]
src/js/number.js [deleted file]
src/js/object.js [deleted file]
src/js/regexp.js [deleted file]
src/js/string.js [deleted file]
src/js/type.js [deleted file]
src/portal/layer.js
src/portal/shape.js
src/portal/util/loc.js
src/portal/util/quadtree.js
src/tanks/game.js [deleted file]
src/tanks/game/game.js [new file with mode: 0644]
src/tanks/game/map.js [new file with mode: 0644]
src/tanks/game/player.js [new file with mode: 0644]
src/tanks/lttl.js
src/tanks/map.js [deleted file]
src/tanks/tank.js [deleted file]
src/tanks/ui.js
src/tanks/unit/tank.js [new file with mode: 0644]
src/tanks/util/grid.js [new file with mode: 0644]
src/tanks/util/pathmap.js [moved from src/simoon/grid/grid.js with 96% similarity]

index 2a24362..1d2321e 100644 (file)
@@ -7,13 +7,12 @@ ul, ol, li { list-style: none ! important; margin:0; padding:0; }
 .rounded { border-radius:1em; -moz-border-radius:1em; -webkit-border-radius:1em; }
 
 #viewport { position:relative; top:1em; width:500px; height:500px; margin:0 auto;
-    outline:1px solid #ccc; }
+    /* outline:1px solid #ccc; */ }
 
 #howto { position:fixed; top:3em; right:1em; color:#BFBFBF; }
 
 #info { position:fixed; bottom:10px; right:10px; padding:0.5em; background-color:rgba(0,0,0, 0.1); color:#787878; }
     #info label { display:block; float:left; width:3em; margin-right:0.5em; color:#787878; }
     #info input { border:0; background-color:transparent; min-width:5em; width:5em; color:#5c5c5c; }
-
-#log { position:fixed; top:auto; bottom:0; left:0; width:100%; height:30%; border-top:1px solid #bbb; }
+    #info .sep { opacity:0.1; background-color:#999; margin:5px 0; height:1px; }
 
index 8806461..04f9df7 100644 (file)
--- a/index.php
+++ b/index.php
     <li id="state"></li>
     <li><label for="fps">fps</label> <input id="fps" name="fps" value="" type="text"></li>
     <li><label for="frame">frame</label> <input id="frame" name="frame" value="" type="text"></li>
-    <li><label for="agents">agents</label> <input id="agents" name="agents" value="" type="text"></li>
+    <li><div class="sep"></div></li>
+    <li><label for="objects">objects</label> <input id="objects" name="objects" value="" type="text"></li>
     <li><label for="units">units</label> <input id="units" name="units" value="" type="text"></li>
     <li><label for="bullets">bullets</label> <input id="bullets" name="bullets" value="" type="text"></li>
 </ul>
 
-<div id="log" style="display:none"></div>
-
 <div id="scripts">
     <!--[if IE]><script type="text/javascript" src="lib/excanvas.min.js"></script><![endif]-->
 <?php
@@ -40,19 +39,25 @@ $scripts = array(
     
     "src/portal/layer.js",
     "src/portal/shape.js",
+    "src/portal/util/quadtree.js",
+    "src/portal/util/rbtree.js",
+    "src/portal/util/eventloop.js",
+    "src/portal/util/cooldown.js",
+    "src/portal/util/loc.js",
+    
+    "src/tanks/util/pathmap.js",
+    "src/tanks/util/grid.js",
+    
+    "src/tanks/game/game.js",
+    "src/tanks/game/map.js",
+    
+    "src/tanks/unit/tank.js",
     
-    // "src/portal/util/quadtree.js",
-    // "src/portal/util/rbtree.js",
-    // "src/portal/util/eventloop.js",
-    // "src/portal/util/cooldown.js",
-    // "src/portal/util/loc.js",
+    "src/tanks/game/player.js",
     
-    "src/tanks/map.js",
-    "src/tanks/tank.js",
-    "src/tanks/game.js",
-    "src/tanks/ui.js",
+    "src/tanks/lttl.js",
+    "src/tanks/ui.js"
     
-    "src/tanks/lttl.js"
 );
 
 function js($src) {
index d7c0080..0a14fee 100644 (file)
@@ -9,6 +9,7 @@ function reduce(o, fn, acc, cxt){
     if ( !o )
         return acc;
     
+    fn = Function.toFunction(fn);
     if ( notSelfOrWrapped(o.reduce) )
         return o.reduce.apply(o, slice.call(arguments,1));
     
index d73707d..e729d92 100644 (file)
@@ -48,6 +48,7 @@ function curry(fn){
     if (fn.__curried__)
         return fn.apply(this, Y(arguments,1));
     
+    fn = Function.toFunction(fn);
     var args = Y(arguments, 1)
     ,   L = unwrap(fn).length;
     
@@ -87,7 +88,7 @@ Y.compose = compose;
 YFunction.prototype.compose = methodize(compose);
 function _composer(x,fn){ return fn.call(this, x); }
 function compose(f,g){
-    var fns = Y(arguments);
+    var fns = Y(arguments).map(Function.toFunction);
     return function(){
         return fns.reduce(_composer, Y(arguments), this);
     };
@@ -96,7 +97,7 @@ function compose(f,g){
 Y.chain = chain;
 YFunction.prototype.chain = methodize(chain);
 function chain(f,g){
-    var fns = Y(arguments);
+    var fns = Y(arguments).map(Function.toFunction);
     
     if ( g.__sequence__ )
         fns = g.__sequence__.concat( fns.slice(1) );
index e86a8af..73f48e7 100644 (file)
@@ -10,6 +10,7 @@ function dump_file($path, $add_newline=true){
 }
 
 $y_files = array(
+    'to-function',
     'alias',
     'type',
     'core',
diff --git a/src/js/_intro.js b/src/js/_intro.js
deleted file mode 100644 (file)
index 599c5c9..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-(function(){
-
-var undefined,
-globals  = this,
-_toString = _Object.prototype.toString,
-_hasOwn   = _Object.prototype.hasOwnProperty,
-_isArray  = _Array.isArray;
diff --git a/src/js/_outro.js b/src/js/_outro.js
deleted file mode 100644 (file)
index efe95da..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-
-globals.reduce = reduce;
-globals.extend = extend;
-globals.attr   = attr;
-
-})();
diff --git a/src/js/array.js b/src/js/array.js
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/src/js/core.js b/src/js/core.js
deleted file mode 100644 (file)
index 40c493e..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-// Generic Collection Functions
-
-function notSelfOrWrapped(fn){
-    var self = arguments.callee.caller;
-    return fn && fn !== self && fn.__wraps !== self;
-}
-
-function reduce(o, fn, acc, cxt){
-    if ( !o )
-        return acc;
-    
-    if ( notSelfOrWrapped(o.reduce) )
-        return o.reduce.apply(o, slice.call(arguments,1));
-    
-    cxt = cxt || o;
-    for ( var name in o )
-        acc = fn.call(cxt, acc, o[name], name, o);
-    
-    return acc;
-}
-
-function attr(o, key, value, def){
-    if ( o && notSelfOrWrapped(o.attr) )
-        return o.attr.apply(o, slice.call(arguments,1));
-    
-    if ( value !== undefined || def !== undefined ){
-        o[key] = (value !== undefined ? value : def);
-        return o;
-    } else
-        return o[key];
-}
-
-function extend( A, B ){
-    return slice.call(arguments,1).reduce(function(A, donor){
-        return reduce(donor, function(o, v, k){
-            return attr(o, k, v, o[k]);
-        }, A);
-    }, A);
-}
diff --git a/src/js/function.js b/src/js/function.js
deleted file mode 100644 (file)
index c52011f..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-var WR_P = "__wraps__";
-
-
-function unwrap(fn){
-    return ( fn && isFunction(fn) ) ? unwrap(fn[WR_P]) || fn : fn;
-}
-
-Function.prototype.curry = curry;
-function curry(){
-    var fn = this
-    ,   args = Array.slice(arguments,0)
-    ,   L = unwrap(fn).length;
-    
-    function curried(){
-        var _args = args.concat(Array.slice(arguments,0));
-        if ( _args.length >= L )
-            return fn.apply(this, _args);
-        else
-            return curry.apply(fn, _args);
-    }
-    curried[WR_P] = fn;
-    
-    return curried;
-}
-
-Function.prototype.methodize = methodize;
-function methodize() {
-    var fn = this;
-    if ( fn.__methodized__ )
-        return fn.__methodized__;
-    
-    var m = fn.__methodized__ =
-        function(){
-            return fn.apply(this, [this].concat(Array.slice(arguments, 0)));
-        };
-    m[WR_P] = fn;
-    return m;
-}
-
-/** Returns the declared name of a function. */
-Function.prototype.getName = getName;
-function getName(){
-    var fn = this;
-    return fn.className || fn.name || (fn+'').match( /function\s*([^\(]*)\(/ )[1] || '';
-}
-
diff --git a/src/js/js.js.php b/src/js/js.js.php
deleted file mode 100644 (file)
index 8868e17..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-<?php
-function dump_file($path, $add_newline=true){
-    $size = filesize($path);
-    if ($size > 0) {
-        $f = fopen($path, "r");
-        echo fread($f, $size);
-        fclose($f);
-    }
-    if ($add_newline) echo "\n";
-}
-
-$jsjs_files = array(
-    'type',
-    'core',
-    'function',
-    'object',
-    'array',
-    'string',
-    'number'
-);
-
-function jsjs_list($path='') {
-    global $jsjs_files;
-    $path = $path ? $path : dirname($_SERVER["REQUEST_URI"]);
-    // echo $path;
-    foreach ($jsjs_files as $f) {
-        echo "<script src='$path/$f.js' type='text/javascript'></script>\n";
-    }
-}
-
-function jsjs_dump($expose=false) {
-    global $jsjs_files;
-    if (!$expose)
-        dump_file("./_intro.js");
-    foreach ($jsjs_files as $f)
-        dump_file("./$f.js");
-    if (!$expose)
-        dump_file("./_outro.js");
-}
-
-if ( basename($_SERVER["SCRIPT_FILENAME"]) == basename(__FILE__) ) {
-    if ( $_REQUEST["list"] )
-        jsjs_list();
-    else
-        jsjs_dump();
-}
\ No newline at end of file
diff --git a/src/js/number.js b/src/js/number.js
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/src/js/object.js b/src/js/object.js
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/src/js/regexp.js b/src/js/regexp.js
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/src/js/string.js b/src/js/string.js
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/src/js/type.js b/src/js/type.js
deleted file mode 100644 (file)
index 1fd1447..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-// Type Utilities //
-// Much borrowed from jQuery
-
-var class2type = "Boolean Number String Function Array Date RegExp Object"
-    .split(" ")
-    .reduce(function(class2type, name) {
-        class2type[ "[object "+name+"]" ] = name.toLowerCase();
-        return class2type;
-    }, {});
-
-function type_of(obj){
-    return obj == null ?
-        String( obj ) :
-        class2type[ toString.call(obj) ] || "object";
-}
-
-function isFunction(obj) { return type_of(obj) === "function"; }
-function isString(obj)   { return type_of(obj) === "string"; }
-function isNumber(obj)   { return type_of(obj) === "number"; }
-
-// A crude way of determining if an object is a window
-function isWindow( obj ) {
-       return obj && typeof obj === "object" && "setInterval" in obj;
-}
-
-function isPlainObject( obj ){
-    // Must be an Object.
-    // Because of IE, we also have to check the presence of the constructor property.
-    // Make sure that DOM nodes and window objects don't pass through, as well
-    if ( !obj || type_of(obj) !== "object" || obj.nodeType || isWindow(obj) )
-        return false;
-    
-    // Not own constructor property must be Object
-    if ( obj.constructor &&
-        !hasOwn.call(obj, "constructor") &&
-        !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") )
-            return false;
-    
-    
-    // Own properties are enumerated firstly, so to speed up,
-    // if last one is own, then all properties are own.
-    
-    var key;
-    for ( key in obj ) {}
-    
-    return key === undefined || hasOwn.call( obj, key );
-}
-
-
index a59db7a..31ac03d 100644 (file)
@@ -4,7 +4,7 @@
 $(function(){
     $('<style />')
         .text([
-            '.portal.layer { position:absolute; z-index:1; overflow:hidden; }',
+            '.portal.layer { position:absolute; z-index:1; overflow:hidden; top:0; left:0; }',
             '.portal.layer canvas { z-index:0; }'
         ].join('\n'))
         .appendTo('head');
@@ -177,9 +177,9 @@ Layer = new Y.Class('Layer', {
             return this;
         
         var _ctx = ctx || this.ctx;
-        this._openPath(_ctx)
-            .drawShape(_ctx)
-            ._closePath(_ctx);
+        this._openPath(_ctx);
+        this.drawShape(_ctx);
+        this._closePath(_ctx);
         
         this.dirty = false;
         this.children.invoke('draw', ctx);
index 0e225b7..364263a 100644 (file)
@@ -88,12 +88,12 @@ Rect = new Y.Class('Rect', Shape, {
     drawShape : function(ctx){
         ctx.rect(0,0, this._width,this._height);
         ctx.fill();
-        return this;
     }
     
 });
 
 Polygon = new Y.Class('Polygon', Shape, {
+    _cssClasses : 'portal layer shape polygon',
     
     /**
      * Expects two arrays of coordinate-halfs, which could be zipped
@@ -117,19 +117,40 @@ Polygon = new Y.Class('Polygon', Shape, {
             ctx.lineTo.apply(ctx, pair);
         });
         ctx.fill();
-        return this;
     }
 });
 
 Triangle = new Y.Class('Triangle', Polygon, {
+    _cssClasses : 'portal layer shape polygon triangle',
+    
     init : function(x1,y1, x2,y2){
         Polygon.init.call(this, [x1,x2], [y1,y2]);
     }
 });
 
 Quad = new Y.Class('Quad', Polygon, {
+    _cssClasses : 'portal layer shape polygon quad',
+    
     init : function(x1,y1, x2,y2, x3,y3){
         Polygon.init.call(this, [x1,x2,x3], [y1,y2,y3]);
     }
 });
 
+Circle = new Y.Class('Circle', Shape, {
+    _cssClasses : 'portal layer shape circle',
+    
+    init : function(radius){
+        Layer.init.call(this);
+        
+        var d = radius * 2;
+        this.width(d).height(d);
+        this.radius = radius;
+    },
+    
+    drawShape : function(ctx){
+        var r = this.radius;
+        ctx.arc(r,r, r, 0, Math.PI*2, false);
+        ctx.fill();
+    }
+    
+});
\ No newline at end of file
index ef44e23..88f66e2 100644 (file)
@@ -4,12 +4,25 @@ Loc = new Y.Class('Loc', {
         this.y = Math.max(y,0);
     },
     
+    moveBy : function(dir, amount){
+        var mod = 1;
+        switch (dir) {
+            case Loc.LEFT: mod = -1;
+            case Loc.RIGHT:
+                return new Loc(this.x+amount*mod, this.y);
+            
+            case Loc.UP: mod = -1;
+            case Loc.DOWN:
+                return new Loc(this.x, this.y+amount*mod);
+        }
+    },
+    
     clone : function(){
         return new Loc(this.x, this.y);
     },
     
     toSquare : function(){
-        return Square.fromLoc(this.x, this.y);
+        return Loc.Square.fromLoc(this.x, this.y);
     },
     
     toString : function(){
@@ -18,6 +31,8 @@ Loc = new Y.Class('Loc', {
     
 });
 Y(Loc).extend({
+    UP    : 'up',    DOWN : 'down',
+    RIGHT : 'right', LEFT : 'left',
     
     fromSquare : function(col, row){
         return new Loc(
@@ -32,7 +47,7 @@ Y(Loc).extend({
 });
 
 
-Rect = new Y.Class('Rect', {
+Loc.Rect = new Y.Class('Rect', {
     init : function(x1,y1, x2,y2){
         if (x1 instanceof Loc && y1 instanceof Loc) {
             var top    = x1,
@@ -62,7 +77,7 @@ Rect = new Y.Class('Rect', {
     },
     
     clone : function(){
-        return new Rect(
+        return new Loc.Rect(
             this.top.clone(),
             this.bottom.clone() );
     },
@@ -79,7 +94,7 @@ Rect = new Y.Class('Rect', {
     
 });
 
-Square = new Y.Class('Square', Rect, {
+Loc.Square = new Y.Class('Square', Rect, {
     init : function(col, row){
         col = this.col = Math.max(col,0);
         row = this.row = Math.max(row,0);
@@ -89,7 +104,7 @@ Square = new Y.Class('Square', Rect, {
         ,   x2 = x1 + REF_SIZE
         ,   y2 = y1 + REF_SIZE;
         
-        Rect.init.call(this, x1,y1, x2,y2);
+        Loc.Rect.init.call(this, x1,y1, x2,y2);
     },
     
     clone : function(){
@@ -105,8 +120,8 @@ Square = new Y.Class('Square', Rect, {
     }
     
 });
-Square.fromLoc = function(x, y){
-    return new Square(
+Loc.Square.fromLoc = function(x, y){
+    return new Loc.Square(
         Math.floor(x / REF_SIZE),
         Math.floor(y / REF_SIZE) );
 };
index 1637321..5a7cfc5 100644 (file)
@@ -199,7 +199,7 @@ QuadTree = new Y.Class('QuadTree', {
     }
 });
 
-this['QuadTree'] = QuadTree;
 QuadTree['Region'] = Region;
+this['QuadTree'] = QuadTree;
 
 })();
diff --git a/src/tanks/game.js b/src/tanks/game.js
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/src/tanks/game/game.js b/src/tanks/game/game.js
new file mode 100644 (file)
index 0000000..291326d
--- /dev/null
@@ -0,0 +1,68 @@
+var undefined
+,   GRID_ELEMENT  = '#viewport'
+
+,   REF_SIZE      = 50
+,   CELL_SIZE     = REF_SIZE
+,   SCALE         = CELL_SIZE / REF_SIZE
+,   GRID_OFFSET   = 0
+
+,   COLUMNS       = 10
+,   ROWS          = 10
+,   CAPACITY      = 32
+
+,   FRAME_RATE    = 30
+,   MS_PER_FRAME  = 1000 / FRAME_RATE
+
+,   NOW           = new Date().getTime() // Current tick's timestamp (ms)
+,   ELAPSED       = MS_PER_FRAME         // Time (ms) since previous tick
+,   FRAMETH       = ELAPSED / 1000       // Ratio of second completed
+,   TICKS         = 0                    // Ticks since start of game
+
+,   PI            = Math.PI
+,   TWO_PI        = PI*2
+,   HALF_PI       = PI/2
+
+;
+
+
+
+Game = new Y.Class('Game', {
+    
+    init : function(viewport){
+        this.loop = new EventLoop(this, FRAME_RATE);
+        
+        // Seal all methods
+        // Y.bindAll(this);
+        this.resize = this.resize.bind(this);
+        this.tick   = this.tick.bind(this);
+        
+        this.viewport = $(viewport || GRID_ELEMENT);
+        
+        this.initMap();
+        
+        this.addEventListener('tick', this.tick);
+    },
+    showOverlay : false,
+    
+    /**
+     * Main Event Loop.
+     */
+    tick : function(evt){
+        var d = evt.data;
+        
+        NOW     = d.now;
+        ELAPSED = d.elapsed;
+        TICKS   = d.ticks;
+        
+        this.root.draw();
+        
+        this.units.invoke('act');
+        // XXX: Collect the dead
+        
+        // this.grid.removeOverlay(this.el);
+        // if (this.showOverlay) this.grid.overlay(this.el);
+    }
+    
+});
+
+
diff --git a/src/tanks/game/map.js b/src/tanks/game/map.js
new file mode 100644 (file)
index 0000000..96bd951
--- /dev/null
@@ -0,0 +1,161 @@
+
+Y(Game.prototype).extend({
+    
+    initMap : function(){
+        var self = this;
+        
+        this.pathmap = new PathMap(0,0, COLUMNS*REF_SIZE, ROWS*REF_SIZE, CAPACITY);
+        
+        var root = this.root = this.grid = 
+            new Grid(COLUMNS,ROWS, CELL_SIZE)
+                .appendTo(this.viewport);
+        this.level =
+            new Layer()
+                .width( root._width )
+                .height( root._height)
+                .appendTo(this.root);
+        
+        // this.root.ctx.scale(1.0, 1.0);
+        
+        this.byId = {};
+        this.units    = new Y.YArray();
+        this.bullets  = new Y.YArray();
+        this.blockers = new Y.YArray();
+        
+        // Agent.addEventListener('create', function(evt){
+        //     self.addAgent(evt.instance);
+        // });
+        // Agent.addEventListener('destroy', function(evt){
+        //     self.killAgent(evt.instance);
+        // });
+    },
+    
+    
+    // *** Path Map Management *** //
+    
+    addBlocker : function(agent){
+        var bb = agent.boundingBox;
+        if (agent.blocking && bb)
+            agent.region = this.grid.set(bb.x1,bb.y1, bb.x2,bb.y2, agent);
+        return agent;
+    },
+    
+    removeBlocker : function(agent){
+        if (agent.region)
+            this.grid.remove(agent.region);
+        return agent;
+    },
+    
+    updateBlocker : function(agent){
+        this.removeBlocker(agent);
+        this.addBlocker(agent);
+    },
+    
+    
+    // *** Agent Management *** //
+    
+    addUnit : function(unit, col,row){
+        unit.game = this;
+        
+        // Center unit in square
+        var sqX = (col || 0) * REF_SIZE
+        ,   sqY = (row || 0) * REF_SIZE
+        ,   x = sqX + (REF_SIZE-unit.width)/2
+        ,   y = sqY + (REF_SIZE-unit.height)/2 ;
+        
+        unit.setLocation(x,y);
+        unit.render( this.level );
+