Fixes turret location calculation. Thanks Chester!
authordsc <david.schoonover@gmail.com>
Wed, 24 Nov 2010 06:54:09 +0000 (22:54 -0800)
committerdsc <david.schoonover@gmail.com>
Wed, 24 Nov 2010 06:54:09 +0000 (22:54 -0800)
index.php
src/Y/modules/y.cookies.js [new file with mode: 0644]
src/Y/modules/y.kv.js
src/Y/y-object.js
src/Y/y-string.js
src/tanks/config.js
src/tanks/thing/player.js
src/tanks/thing/tank.js
src/tanks/ui/config.js [new file with mode: 0644]
tanks.php

index 7376a28..afcb361 100644 (file)
--- a/index.php
+++ b/index.php
 
 <div id="overlay"></div>
 
-<div id="ai" style="display:none" class="bigblue">
-    <div class="box">
-        <h2>Add Tank AI</h2>
-        <textarea id="custom-tank"></textarea>
-        <div class="ready pinkbutton rounded">Ready</div>
-    </div>
-</div>
-
 <div id="welcome" class="bigblue">
     <div class="box">
         <h1>The Littlest Battletank</h1>
             <li>Move your tank with <code>wasd</code> or the arrow keys.</li>
             <li>Use the mouse to aim; click to shoot (or press <code>spacebar</code>).</li>
             <li>Press <code>enter</code> to pause.</li>
-            <li>For now, refresh the page to play again. :)</li>
         </ul>
         
         <h2 class="start">Click anywhere to start!</h2>
     </div>
 </div>
 
+<div id="ai" style="display:none" class="bigblue">
+    <div class="box">
+        <h2>Add Tank AI</h2>
+        <textarea id="custom-tank"></textarea>
+        <div class="ready pinkbutton rounded">Ready</div>
+    </div>
+</div>
+
 <div id="viewport"></div>
 
 <div id="debug" style="display:none"><div class="inner box">
diff --git a/src/Y/modules/y.cookies.js b/src/Y/modules/y.cookies.js
new file mode 100644 (file)
index 0000000..2342220
--- /dev/null
@@ -0,0 +1,28 @@
+(function(Y, undefined){ if (!Y) return;
+
+var _document = document
+,   enc = encodeURIComponent
+,   dec = decodeURIComponent
+,   ns  = Y.cookies = {}
+;
+
+ns.get =
+    function getCookie(k){
+        var cookies = Y(_document.cookie+'').fromKV('; ');
+        if (k !== undefined)
+            return cookies[k];
+        else
+            return cookies;
+    };
+
+ns.set = 
+    function setCookie(k, v, expires, path){
+        expires = 'expires='+(expires || "Sun, 24-Mar-2024 11:11:11 GMT");
+        path = 'path='+(path || "/");
+        _document.cookie = [ enc(k)+'='+enc(v), expires, path ].join('; ');
+        return Y.cookies.get();
+    };
+
+// TODO: YCollection methods on ns over kv pairs.
+
+})(this.Y);
index 76873b3..f6c2c82 100644 (file)
@@ -1,27 +1,28 @@
 (function(Y, undefined){ if (!Y) return;
 
-var enc = encodeURIComponent, 
-    dec = decodeURIComponent;
+var enc = encodeURIComponent
+,   dec = decodeURIComponent
+;
 
-Y.YObject.prototype.toKV =
-function toKV(del){
-    return this.reduce(function(acc, v, k){
-        return acc.push( enc(k) + '=' + enc(v) );
-    }, Y([]))
-    .join(del !== undefined ? del : "&");
-};
+Y.YCollection.prototype.toKV =
+    function toKV(del){
+        return this.reduce(function(acc, v, k){
+            return acc.push( enc(k) + '=' + enc(v) );
+        }, Y([]))
+        .join(del !== undefined ? del : "&");
+    };
 
 Y.YString.prototype.toObject =
 Y.YString.prototype.fromKV =
-function fromKV(del){
-    return Y(this.split(del || '&'))
-        .reduce(function(acc, pair){
-            var idx = pair.indexOf('=')
-            ,   k = dec(pair.slice(0,idx))
-            ,   v = dec(pair.slice(idx+1)) ;
-            if (k) acc[k] = v;
-            return acc;
-        }, {});
-};
+    function fromKV(del){
+        return Y(this.split(del || '&'))
+            .reduce(function(acc, pair){
+                var idx = pair.indexOf('=')
+                ,   k = dec(pair.slice(0,idx))
+                ,   v = dec(pair.slice(idx+1)) ;
+                if (k) acc[k] = v;
+                return acc;
+            }, {});
+    };
 
 })(this.Y);
index 2c82bf1..b286350 100644 (file)
@@ -3,10 +3,66 @@ var
 YObject =
 Y.YObject =
 YCollection.subclass('YObject', {
-    'init': function (o){
-        if (!o) o = {};
-        this._o = o;
-        YCollection.init.call(this, o);
+    
+    'init': function initYObject(o){
+        this._o = o || {};
+    },
+    
+    /** 
+     * Ensures an object has the given property or nested property chain. Each missing link in a chain is filled with a new, empty object.
+     * @param {String} chain Property name or nested property chain starting at `base`. Property chains are specified in dotted lookup syntax.
+     * @return {this}
+     */
+    ensure : function ensure(chain){
+        if (chain) chain
+            .split('.')
+            .reduce(function(o,link) {
+                if( o && link && o[link] === undefined )
+                    o[link] = {};
+                return o[link];
+            }, this._o );
+        return this;
+    },
+    
+    /**
+     * Searches a heirarchical object for a given subkey specified in dotted-property syntax.
+     * @param {Array|String} chain The property-chain to lookup.
+     * @param {Boolean} [meta] If supplied return an object of the form
+      *         `{ key: Qualified key name, obj: Parent object of key, value: Value at obj[key] }` 
+      *     if chain is found (and `undefined` otherwise).
+     * @return {Any} The value at the path, or `undefined`.
+     */
+    getNested : function getNested(chain, meta){
+        if ( !isArray(chain) )
+            chain = chain.toString().split('.');
+        
+        var lastIdx = chain.length-1
+        ,   ret = chain.reduce(function(current, key){
+            if ( current === undefined || current.value[key] === undefined )
+                return undefined;
+            else
+                return {
+                    key   : key,
+                    value : current.value[key],
+                    obj   : current.value
+                };
+        }, { value:this._o });
+        
+        return (ret && !meta ? ret.value : ret);
+    },
+    
+    /**
+     * Searches a heirarchical object for a given subkey specified in dotted-property
+     *  syntax, setting it wiht the provided value if found.
+     * @param {Array|String} chain The property-chain to lookup.
+     * @param {Any} value The value to set.
+     * @return {this}
+     */
+    setNested : function setNested(chain, value){
+        var prop = this.ensure(chain).getNested(chain);
+        prop.obj[prop.key] = value;
+        return this;
     }
+    
 });
 
index 906d701..72d17ab 100644 (file)
@@ -3,6 +3,7 @@ var
 YString =
 Y.YString =
 YCollection.subclass('YString', function(YString){
+    
     mixinNames(YString, String, [
             'slice', 'split',
             'substr', 'substring',
@@ -26,7 +27,49 @@ YCollection.subclass('YString', function(YString){
         init : function init(o){
             if (!o) o = "";
             this._o = o;
-            YCollection.init.call(this, o);
+        },
+        
+        /**
+         * As Array.slice -- replaces `howMany` elements starting at `idx`
+         * with the concatenation of the rest of the arguments.
+         * 
+         * A negative value `idx` is offset from the end.
+         * 
+         * Invalid values for `howMany` will be replaced with 0.
+         */
+        splice : function splice(idx, howMany){
+            var s = this._o;
+            
+            idx = (idx < 0 ? s.length+idx : idx);
+            howMany = Number(howMany > 0 ? howMany : 0);
+            
+            var prefix = s.slice(0, idx)
+            ,   insert = Y(arguments, 2).join('')
+            ,   suffix = s.slice(idx+howMany)
+            ;
+            this._o = prefix + insert + suffix;
+            return this;
+        },
+        
+        /**
+         * Replaces the portion of the string defined by s.slice(start, end)
+         * with the concatenation of the rest of the arguments.
+         * 
+         * Negative values for start and/or end are allowed.
+         */
+        mutate : function mutate(start, end){
+            return this.splice.apply(this, [start, end-start].concat(Y(arguments, 2)) );
+            // var s = this._o, len = s.length ;
+            // 
+            // if (start < 0) start += len;
+            // if (end < 0)   end   += len;
+            // 
+            // var prefix = s.slice(0, start)
+            // ,   insert = Y(arguments, 2).join('')
+            // ,   suffix = s.slice(end)
+            // ;
+            // this._o = prefix + insert + suffix;
+            // return this;
         },
         
         strip: function strip(){ 
@@ -67,5 +110,44 @@ YCollection.subclass('YString', function(YString){
             return this._o;
         }
     });
+    
+    this.set = function set(key, value, def){
+        var s = this._o, _val = (value !== undefined ? value : def);
+        
+        if ( Y.isNumber(key) )
+            return this.splice(key, 1, _val);
+        if ( Y.isArray(key) )
+            return this.splice.apply(this, key.slice(0,2).concat([_val]) );
+        
+        // TODO: Should cache the new properties and re-applied them whenever we mutate _o,
+        // as strings are immutable and they'll be lost otherwise.
+        Y.op.set(s, key, _val);
+        return this;
+    };
+    
+    this.attr = function attr(key, value, def){
+        var s = this._o;
+        // set
+        if ( value !== undefined || def !== undefined )
+            return Y.attr(this, key, value, def);
+            
+        // get
+        else {
+            if ( Y.isNumber(key) )
+                return s.charAt(key);
+            if ( Y.isArray(key) )
+                return s.slice.apply(s, key);
+            
+            return s[key];
+        }
+    };
+    this.attr.__wraps__ = Y.attr;
+    
+    this.reduce = function reduce(fn, acc){
+        fn = Function.toFunction(fn);
+        for ( var s = this._o, cxt = arguments[2]||this, i = 0, L = s.length; i < L; ++i )
+            acc = fn.call(cxt, acc, s.charAt(i), i, s);
+        return acc;
+    };
+    
 });
-
index e8987c9..fc710fd 100644 (file)
@@ -2,11 +2,11 @@
 tanks.config = {
     ui : {
         showGridCoords : false,
-        showCountdown  : false
+        showCountdown  : true
     },
     pathing : { 
         overlayPathmap    : false,
         overlayAIPaths    : false,
         traceTrajectories : false
     }
-};
\ No newline at end of file
+};
index cd7827c..ff4c8b4 100644 (file)
@@ -131,7 +131,10 @@ PlayerTank = Tank.subclass('PlayerTank', {
         if ( !this.game.loop.running ) return;
         
         switch (evt.which) {
-            case 1: evt.leftMouse   = true; this.attack(); break;
+            case 1: evt.leftMouse   = true;
+                this.rotateBarrelRelPage(evt.pageX, evt.pageY);
+                this.attack();
+            break;
             case 2: evt.rightMouse  = true; break;
             case 3: evt.middleMouse = true; break;
         }
index 1e8bcec..42e7570 100644 (file)
@@ -233,6 +233,7 @@ Tank = Thing.subclass('Tank', {
             return null;
         
         var barrel = this.barrel
+        ,   mid = this.midpoint
         ,   bb = this.boundingBox
         ,   w2 = bb.width/2,    h2 = bb.height/2
         ,   x0 = bb.x1+w2,      y0 = bb.y1+h2
@@ -263,16 +264,15 @@ Tank = Thing.subclass('Tank', {
     },
     
     getTurretLoc : function getTurretLoc(){
-        var loc    = this.loc
-        ,   barrel = this.barrel, bbb = barrel.boundingBox
+        var loc    = this.loc, mid = this.midpoint
+        ,   barrel = this.barrel
         
         ,   theta  = barrel.transform.rotate
         ,   sin = Math.sin(theta),  cos = Math.cos(theta)
+        ,   len = barrel.boundingBox.width
         
-        ,   x0 = 3+bbb.x2-bbb.x1,   y0 = (bbb.y2-bbb.y1)/2
-        
-        ,   x = loc.x + bbb.x1 + x0*cos - y0*sin
-        ,   y = loc.y + bbb.y1 + x0*sin + y0*cos
+        ,   x = mid.x + len*cos
+        ,   y = mid.y + len*sin
         ;
         // console.log('getTurretLoc()', 'loc:', loc, 'bbb.(x2,y2):', [bbb.x2,bbb.y2], '(x,y):', [x,y]);
         return new math.Vec(x,y);
@@ -330,28 +330,28 @@ Tank = Thing.subclass('Tank', {
         ,   h = this.height, h2 = h/2
         
         ,   r  = w / 4
-        ,   cw = w * 0.75
-        ,   ch = h / 6
+        ,   bw = w * 0.75
+        ,   bh = h / 6
         ;
         
         this.shape = 
             new Rect(w,h)
                 .position(this.loc.x, this.loc.y)
                 .fill(this.bodyColor)
-                .appendTo( parent );
-        
-        this.turret = new Circle(r, true)
-            .position(w2-r, h2-r)
-            .fill(this.turretColor)
-            .appendTo( this.shape )
-        ;
-        
-        this.barrel = new Rect(cw,ch)
-            .position(w2-2, h2-ch/2)
-            .origin(2, ch/2)
-            .fill(this.barrelColor)
-            .appendTo( this.shape )
-        ;
+                .appendTo( parent ) ;
+        
+        this.turret =
+            new Circle(r, true)
+                .position(w2-r, h2-r)
+                .fill(this.turretColor)
+                .appendTo( this.shape ) ;
+        
+        this.barrel =
+            new Rect(bw,bh)
+                .position(w2-2, h2-bh/2)
+                .origin(2, bh/2)
+                .fill(this.barrelColor)
+                .appendTo( this.shape ) ;
         
         return this;
     },
diff --git a/src/tanks/ui/config.js b/src/tanks/ui/config.js
new file mode 100644 (file)
index 0000000..d74e090
--- /dev/null
@@ -0,0 +1,8 @@
+(function(){
+
+function splitCamel(s){
+    
+    
+}
+
+})();
index 9a3054d..40693fc 100644 (file)
--- a/tanks.php
+++ b/tanks.php
@@ -55,6 +55,7 @@ class Tanks {
         "src/Y/y.js.php",
         "src/Y/modules/y.event.js",
         "src/Y/modules/y.kv.js",
+        "src/Y/modules/y.cookies.js",
         
         "src/evt/evt.class.js",