Bullet reflections now work!
authordsc <david.schoonover@gmail.com>
Mon, 8 Nov 2010 08:53:07 +0000 (00:53 -0800)
committerdsc <david.schoonover@gmail.com>
Mon, 8 Nov 2010 08:53:07 +0000 (00:53 -0800)
18 files changed:
index.php
src/Y/core.js
src/Y/y-core.js
src/Y/y-op.js
src/portal/layer.js
src/portal/math/line.js
src/portal/math/vec.js
src/portal/shape.js
src/portal/util/eventloop.js
src/portal/util/fps.js
src/tanks/game/map.js
src/tanks/game/player.js
src/tanks/lttl.js
src/tanks/thing/bullet.js
src/tanks/thing/tank.js
src/tanks/ui.js
src/tanks/util/grid.js
test/math/math.test.js

index 40593b9..2a76380 100644 (file)
--- a/index.php
+++ b/index.php
@@ -43,6 +43,11 @@ $scripts = array(
     
     "src/portal/layer.js",
     "src/portal/shape.js",
+    
+    "src/portal/math/math.js",
+    "src/portal/math/vec.js",
+    "src/portal/math/line.js",
+    
     "src/portal/util/quadtree.js",
     "src/portal/util/rbtree.js",
     "src/portal/util/eventloop.js",
index 19e33ae..493e4bf 100644 (file)
@@ -1,6 +1,6 @@
 // Generic Collection Functions
 
-function notSelfOrWrapped(fn){
+function notWrapped(fn){
     var self = arguments.callee.caller;
     return fn && fn !== self && fn.__wraps__ !== self;
 }
@@ -10,7 +10,7 @@ function reduce(o, fn, acc, cxt){
         return acc;
     
     // fn = Function.toFunction(fn);
-    if ( notSelfOrWrapped(o.reduce) )
+    if ( notWrapped(o.reduce) )
         return o.reduce.apply(o, [fn, acc, cxt]);
     
     cxt = cxt || o;
@@ -20,31 +20,39 @@ function reduce(o, fn, acc, cxt){
     return acc;
 }
 
-function set(o, key, value, def){
-    if ( o && notSelfOrWrapped(o.set) )
-        return o.set.apply(o, slice.call(arguments,1));
     
+function set(o, key, value, def){
     if ( o && key !== undefined )
         o[key] = (value !== undefined ? value : def);
-    
     return o;
 }
 
-function attr(o, key, value, def){
-    if ( o && notSelfOrWrapped(o.attr) )
-        return o.attr.apply(o, slice.call(arguments,1));
-    
+function dset(o, key, value, def){
+    if ( o && notWrapped(o.set) )
+        return o.set.apply(o, slice.call(arguments,1));
+    else
+        return set(o, key, value, def);
+}
+
+function attr(o,key,value,def){
     if ( !o || key === undefined ) return o;
     
-    if ( isPlainObject(key) )
+    if ( Y.isPlainObject(key) )
         return extend(o, key);
     
     if ( value !== undefined || def !== undefined ){
-        return set(o, key, value, def);
+        return dset(o, key, value, def);
     } else
         return o[key];
 }
 
+function dattr(o, key, value, def){
+    if ( o && notWrapped(o.attr) )
+        return o.attr.apply(o, slice.call(arguments,1));
+    else
+        return attr(o, key, value, def);
+}
+
 function extend( A, B ){
     return slice.call(arguments,1).reduce(extend._extendall, A);
 }
@@ -52,6 +60,6 @@ extend._extendall = function _extendall(A, donor){
     return reduce(donor, extend._set, A);
 };
 extend._set = function _set(o, v, k){
-    return attr(o, k, v, o[k]);
+    return dattr(o, k, v, o[k]);
 };
 
index 995751b..dced427 100644 (file)
@@ -1,7 +1,7 @@
 
 Y.reduce = reduce;
-Y.set    = set;
-Y.attr   = attr;
+Y.set    = dset;
+Y.attr   = dattr;
 Y.extend = extend;
 
 Y.isFunction = isFunction;
index 5017606..ca5064d 100644 (file)
@@ -36,17 +36,24 @@ Y.op = {
     zrshift: function(x,y){ return x >>> y; },
     
     // values
-    nop:    function(){},
+    nop:    function(x){},
     I:      function(x){       return x; },
     K:      function(k){       return function(){ return k; }; },
     val:    function(def,o){   return o !== undefined ? o : def; },
     ok:     function(o){       return o !== undefined && o !== null; },
     
-    // values & accessors
-    has:    function(k,o){     return k in o; },
-    get:    function(k,o){     return o[k] },
-    getdef: function(def,k,o){ return (k in o ? o[k] : def); },
-    set:    function(o,k,v){   if (o && k !== undefined) o[k] = v; return o; },
+    // reduce-ordered values & accessors
+    khas:    function(k,o){     return k in o; },
+    kget:    function(k,o){     return o[k] },
+    defkget: function(def,k,o){ return (k in o ? o[k] : def); },
+    vkset:   function(o,v,k){   if (o && k !== undefined) o[k] = v; return o; },
+    
+    // curry-ordered values & accessors
+    has:     function(o,k){     return k in o; },
+    get:     function(o,k){     return o[k] },
+    getdef:  function(o,k,def){ return (k in o ? o[k] : def); },
+    set:     set,
+    attr:    attr,
     method: function(name){
         var args = Y(arguments,1);
         return function(obj){
index f88500a..db019dd 100644 (file)
@@ -1,5 +1,14 @@
 (function($, undefined){
 
+var CONTEXT_ATTRS = Y([
+    'globalAlpha', 'globalCompositeOperation',
+    'strokeStyle', 'fillStyle',
+    'lineWidth', 'lineCap', 'lineJoin', 'miterLimit',
+    'shadowOffsetX', 'shadowOffsetY', 'shadowBlur', 'shadowColor'
+]);
+
+
+
 Layer = new Y.Class('Layer', {
     _cssClasses : 'portal layer',
     
@@ -118,6 +127,29 @@ Layer = new Y.Class('Layer', {
     
     /// Attributes ///
     
+    
+    attr : function attr(key, value, def){
+        if (!key) return this;
+        
+        if ( Y.isPlainObject(key) ) {
+            for (var k in key)
+                this.attr(k, key[k]);
+            return this;
+            
+        // } else if ( CONTEXT_ATTRS.has(key) ) {
+        //     var r = Y.attr(this.ctx, key, value, def);
+        //     
+        //     if (r === this.ctx) {
+        //         // This implies we set a property
+        //         this.dirty = true;
+        //         return this;
+        //     } else
+        //         return r;
+        //     
+        } else
+            return Y.op.attr(this, key, value, def);
+    },
+    
     /**
      * Changes the layer's width and then updates the canvas.
      */
@@ -291,19 +323,6 @@ Layer = new Y.Class('Layer', {
     
     /// Drawing Functions ///
     
-    // for debugging
-    point : function point(x,y, color){
-        var ctx = this.ctx;
-        this._openPath(ctx);
-        
-        var r = 2;
-        ctx.arc(x+r,y+r, r, 0, Math.PI*2, false);
-        ctx.fillStyle = color || '#FFFFFF';
-        ctx.fill();
-        
-        this._closePath(ctx);
-        return this;
-    },
     /**
      * @param {CanvasDrawingContext2D} [ctx=this.ctx] Forces context to use rather than the layer's own.
      * @param {Boolean} [force=false] Forces redraw.
@@ -322,7 +341,8 @@ Layer = new Y.Class('Layer', {
     },
     
     _openPath : function _openPath(ctx){
-        var w = this.canvasWidth
+        var self = this
+        ,   w = this.canvasWidth
         ,   h = this.canvasHeight
         ,   neg = this.negBleed
         ;
@@ -337,6 +357,14 @@ Layer = new Y.Class('Layer', {
         
         // ctx.scale(this.absScaleX, this.absScaleY);
         
+        // Set context attributes
+        CONTEXT_ATTRS.forEach(function(name){
+            if (self[name] === undefined)
+                delete ctx[name];
+            else
+                ctx[name] = self[name];
+        });
+        
         return this;
     },
     
@@ -365,6 +393,22 @@ Layer = new Y.Class('Layer', {
         return this;
     },
     
+    // for debugging
+    point : function point(x,y, color){
+        var ctx = this.ctx;
+        // this._openPath(ctx);
+        
+        var r = 2;
+        ctx.beginPath();
+        ctx.arc(x,y, r, 0, Math.PI*2, false);
+        ctx.fillStyle = color || '#FFFFFF';
+        ctx.fill();
+        ctx.closePath();
+        
+        // this._closePath(ctx);
+        return this;
+    },
+    
     
     
     
@@ -439,6 +483,7 @@ $(function(){
     $('<style />')
         .text([
             '.portal.layer { position:absolute; z-index:1; top:0; left:0; line-height:0; }',
+            // '.portal.layer { outline:1px solid #000000; }',
             '.portal.layer canvas { z-index:0; }'
         ].join('\n'))
         .appendTo('head');
index 8ffb956..b774a96 100644 (file)
@@ -1,9 +1,17 @@
+(function(){
+
+var 
+HALF_PI = Math.PI/2,
+SIN_HALF_PI = Math.sin(HALF_PI),
+COS_HALF_PI = Math.cos(HALF_PI);
+
+
 /**
  * A line in the cartesian plane.
  */
 math.Line = new Y.Class('Line', math.Vec, {
     
-    init : function init(x1,y1, x2,y2, t){
+    init : function init(x1,y1, x2,y2, tdist){
         this.x1 = x1; this.y1 = y1; this.p1 = new math.Vec(x1,y1);
         this.x2 = x2; this.y2 = y2; this.p2 = new math.Vec(x2,y2);
         
@@ -13,19 +21,41 @@ math.Line = new Y.Class('Line', math.Vec, {
         ,   xi = this.xint   = -y1/m + x1
         ;
         math.Vec.init.call(this, xdelta, ydelta);
-        this.setT(t);
+        
+        this.theta = Math.atan2(ydelta, xdelta);
+        this._cos  = Math.cos(this.theta);
+        this._sin  = Math.sin(this.theta);
+        this.setTScale(tdist);
+    },
+    
+    clone : function clone(){
+        return new math.Line(this.x1,this.y1, this.x2,this.y2, this.tdist);
     },
     
-    setT : function setT(t){
-        this.t  = 1/(t || 1);
-        this.pa = this.t*this.x;
-        this.pb = this.t*this.y;
+    setTScale : function setTScale(tdist){
+        if (tdist) {
+            this.tdist = tdist;
+            this.pa = tdist * this._cos;
+            this.pb = tdist * this._sin;
+        } else {
+            this.tdist = this.y / this._sin;
+            this.pa = this.x;
+            this.pb = this.y;
+        }
         return this;
     },
     
     pcalc : function parametric(t){
-        return new math.Vec( this.x1 + this.pa*t ,
-                             this.y1 + this.pb*t );
+        return new math.Vec( this.x1 + t*this.pa ,
+                             this.y1 + t*this.pb );
+    },
+    
+    pointX : function pointX(x){
+        return new math.Vec(x, this.calcY(x));
+    },
+    
+    pointY : function pointY(y){
+        return new math.Vec(this.calcX(y), y);
     },
     
     calcY : function calcY(x){
@@ -37,11 +67,26 @@ math.Line = new Y.Class('Line', math.Vec, {
     },
     
     base : function base(){
-        return new math.Line(0,0, this.x,this.y);
+        if (!this._base)
+            this._base = new math.Line(0,0, this.x,this.y);
+        return this._base;
+    },
+    
+    tangent : function tangent(at){
+        var _theta = Math.PI/2 + this.theta
+        ,   x  = (at.x !== this.x1 ? this.x1 : this.x2) - at.x
+        ,   y  = (at.y !== this.y1 ? this.y1 : this.y2) - at.y
+        ,   _x = at.x + y
+        ,   _y = at.y - x
+        return new math.Line(at.x,at.y, _x,_y, this.tdist);
     },
     
     toString : function toString(){
-        return 'Line('+this.x1+','+this.y1+', '+this.x2+','+this.y2+', slope='+this.slope+')';
+        return 'Line('+this.x1.toFixed(2)+','+this.y1.toFixed(2)+', '+
+                       this.x2.toFixed(2)+','+this.y2.toFixed(2)+', '+
+                       'slope='+this.slope.toFixed(3)+')';
     }
     
-});
\ No newline at end of file
+});
+
+})();
index ce387ee..995f1c1 100644 (file)
@@ -62,7 +62,7 @@ math.Vec = new Y.Class('Vec', {
     },
     
     toString : function toString(){
-        return 'Vec('+this.x+','+this.y+')';
+        return 'Vec('+this.x.toFixed(3)+','+this.y.toFixed(3)+')';
     }
     
 });
index 1eb20bf..1f1b109 100644 (file)
@@ -1,35 +1,6 @@
-CONTEXT_ATTRS = Y([
-    'globalAlpha', 'globalCompositeOperation', 'strokeStyle', 'fillStyle',
-    'lineWidth', 'lineCap', 'lineJoin', 'miterLimit', 'shadowOffsetX',
-    'shadowOffsetY', 'shadowBlur', 'shadowColor'
-]);
-
-
 Shape = new Y.Class('Shape', Layer, {
     _cssClasses : 'portal layer shape',
     
-    attr : function attr(key, value, def){
-        if (!key) return this;
-        
-        if ( Y.isPlainObject(key) ) {
-            for (var k in key)
-                this.attr(k, key[k]);
-            return this;
-            
-        } else if ( CONTEXT_ATTRS.has(key) ) {
-            var r = Y.attr(this.ctx, key, value, def);
-            
-            if (r === this.ctx) {
-                // This implies we set a property
-                this.dirty = true;
-                return this;
-            } else
-                return r;
-            
-        } else
-            return Y.attr(this, key, value, def);
-    },
-    
     _calcDimension : function _calcDimension(which, values){
         values.unshift(0);
         var self = this
@@ -50,12 +21,12 @@ Shape = new Y.Class('Shape', Layer, {
 Rect = new Y.Class('Rect', Shape, {
     _cssClasses : 'portal layer shape rect',
     
-    init : function init(w, h){
+    init : function initRect(w, h){
         Layer.init.call(this);
         
         this.width(w)
-            .height(h)
-            .origin(w/2, h/2);
+            .height(h);
+            // .origin(w/2, h/2);
     },
     
     drawShape : function drawShape(ctx){
@@ -68,18 +39,18 @@ Rect = new Y.Class('Rect', Shape, {
 Circle = new Y.Class('Circle', Shape, {
     _cssClasses : 'portal layer shape circle',
     
-    init : function init(radius){
+    init : function initCircle(radius){
         Layer.init.call(this);
         
         var d = radius * 2;
-        this.radius = radius;
-        this.width(d).height(d)
-            .origin(radius,radius);
+        this.radius = this.negBleed.x = this.negBleed.y = radius;
+        this.width(d).height(d);
+            // .origin(radius,radius);
     },
     
     drawShape : function drawShape(ctx){
         var r  = this.radius;
-        ctx.arc(r,r, r, 0, Math.PI*2, false);
+        ctx.arc(0,0, r, 0, Math.PI*2, false);
         ctx.fill();
     }
     
@@ -93,7 +64,7 @@ Polygon = new Y.Class('Polygon', Shape, {
      * together to make the numbered coordinates.
      * x0 and y0 will always be 0.
      */
-    init : function init(xs, ys){
+    init : function initPolygon(xs, ys){
         Layer.init.call(this);
         
         var xs = this._calcDimension('x', xs)
@@ -104,8 +75,8 @@ Polygon = new Y.Class('Polygon', Shape, {
         
         this.points = Y(xs).zip(ys).map(Loc.instantiate, Loc);
         this.width(w)
-            .height(h)
-            .origin(w/2, h/2);
+            .height(h);
+            // .origin(w/2, h/2);
     },
     
     drawShape : function drawShape(ctx){
@@ -117,12 +88,90 @@ Polygon = new Y.Class('Polygon', Shape, {
 });
 
 // Er, this won't do. It's only a line-segment.
-Line = new Y.Class('Line', Polygon, {
+Line = new Y.Class('Line', Shape, {
+    _cssClasses : 'portal layer shape line',
+    
+    init : function initLine(x,y){
+        Layer.init.call(this);
+        
+        this.sublayer = jQuery('<div style="overflow:hidden" />')
+            .append(this.canvas)
+            .appendTo(this.layer);