Search code examples
javascriptcanvaseaseljscreatejshtml4

what is this strange easelJS behaviour?


im quite new to javascript and easelJS/createJS but i think i understand them enough to do simple task. I started to experiment with canvas, and had stuck in one place.

This little project uses canvas and easelJS to render simple shuttle with 2 engines, and simple physics to move it around. (pseudo)Physics works fine: for both engines, separate actions are taken, but rendering fails. whenever I turn on engine (keys 'q' or 'w') boths engine's fires come out.

I tried to find simpliest subset of this code to reproduce that problem but i failed, so i provide whole code of this simple project.

<!DOCTYPE HTML>
<html>
<head>
<title></title>

<style>
    /*#myCanvas{
        width: 1200px;
        height: 600px;
    }*/
</style>

<script src="createjs-2013.12.12.min.js"></script>
<script>


/* Keyboard */
var Key = {
    _pressed: {},

    /*LEFT: 37,
    UP: 38,
    RIGHT: 39,
    DOWN: 40,*/
    Q: 81, W: 87, E: 69, R:82, T:84, Y: 89,


    isDown: function(keyCode) {
        return this._pressed[keyCode];
    },

    onKeydown: function(event) {
        this._pressed[event.keyCode] = true;
    },

    onKeyup: function(event) {
        delete this._pressed[event.keyCode];
    },

    getThrottles: function () {
        var resObj = {};
        for(var code in this._pressed){
            resObj[String.fromCharCode(code)] = 1;
        }
        return resObj;
    }
};

/* Vector2 */
function Vector2 (x, y, dx, dy){
    this.x = x ? x : 0;
    this.y = y ? y : 0;
    this.dx = dx ? dx : 0;
    this.dy = dy ? dy : 0;
}

/* Physics */
var Physics = {
    objects: [],

    update: function(){
        for(ind in this.objects){
            var obj = this.objects[ind];

            for(ind2 in obj.forces){
                var f = obj.forces[ind2];


                // velocities calculations
                if(f.x == obj.x && f.y == obj.y){
                    obj.velocity.dx += f.dx/obj.mass;
                    obj.velocity.dy += f.dy/obj.mass;
                }
                else{
                    var len = Math.sqrt((f.x-obj.x)*(f.x-obj.x) + (f.y-obj.y)*(f.y-obj.y));
                    var fpar = new Vector2(0, 0, (obj.x-f.x)/len, (obj.y-f.y)/len);
                    var fper = new Vector2(0, 0, (obj.y-f.y)/len, -(obj.x-f.x)/len);
                    var factorpar = f.dx*fpar.dx + f.dy*fpar.dy;
                    var factorper = f.dx*fper.dx + f.dy*fper.dy;

                    obj.velocity.dx += f.dx/obj.mass;
                    obj.velocity.dy += f.dy/obj.mass;

                    // TODO: here radius should be considered in equation
                    obj.avelocity += factorper/obj.imoment;

                }


            }

            obj.forces.length = 0;

            // rotations and translations
            obj.x += obj.velocity.dx;
            obj.y += obj.velocity.dy;
            obj.rotation += obj.avelocity;

            // dumping
            var dumping = 0.95;
            var adumping = 0.95;
            var minvel = 0.0001;
            var minavel = 0.0001;

            obj.velocity.dx = dumping * obj.velocity.dx;
            obj.velocity.dy = dumping * obj.velocity.dy;
            obj.avelocity = adumping * obj.avelocity;

        }

    }

};



var myStage;

createjs.DisplayObject.prototype.mass =0.5;
createjs.DisplayObject.prototype.imoment = 0.1;
createjs.DisplayObject.prototype.forces = [];
createjs.DisplayObject.prototype.velocity = new Vector2();
createjs.DisplayObject.prototype.avelocity = 0;

function Engine(width, height){
    var that = this;
    this.width = width;
    this.height = height;
    this.innerThrottle = 0;

    this.throttle = function(value){
        if(value!==null)
            that.innerThrottle = value;

        that.flame.graphics.clear();
        that.flame.graphics.beginFill("#ff0000").drawRoundRect(
                        -that.width*that.innerThrottle/2,
                        that.height+that.margin,
                        that.width*that.innerThrottle,
                        that.width*that.innerThrottle,
                that.margin);

        return that.innerThrottle;
    };



    //drawing
    this.margin = 0.1 * this.width;
    this.body = new createjs.Shape();
    this.body.graphics.beginFill("#999999").drawRect(-this.width/2, 0, this.width, this.height);
    this.addChild(this.body);

    this.flame = new createjs.Shape();
    this.flame.graphics.beginFill("#ff0000").drawRoundRect(
                    -this.width*this.throttle()/2,
                    this.height+this.margin,
                    this.width*this.throttle(),
                    this.width*this.throttle(),
            this.margin);
    this.addChild(this.flame);
}
Engine.prototype = new createjs.Container();

function Shuttle(radius){
    var that = this;
    this.engineNames = ['Q','W','E','R','T','Y'];
    this.engines = {};
    this.addEngine = function (x,y,rotation){
        var tmpEn = new Engine(radius/2, radius/1);
        tmpEn.x = x;
        tmpEn.y = y;
        tmpEn.rotation = rotation;
        that.addChild(tmpEn);

        that.engines[that.engineNames[Object.keys(that.engines).length]] = tmpEn;
    };

    this.steering = null;

    this.shuttleTick = function(){
        var throttles = that.steering.getThrottles();
        var engines = that.engines;

        for(var key in engines)
            engines[key].throttle(0);

        for(var key2 in throttles){
            if(engines[key2]){
                engines[key2].throttle(throttles[key2]);

                var end = engines[key2].localToGlobal(0,-0.1);
                var start = engines[key2].localToGlobal(0,0);

                that.forces.push(new Vector2(start.x, start.y, (end.x-start.x)*throttles[key2], (end.y-start.y)*throttles[key2]));
            }
        }


    };



    // drawing
    var core = new createjs.Shape();
    core.graphics.beginFill("#000000").drawCircle(0,0,radius);
    this.addChild(core);
}
Shuttle.prototype = new createjs.Container();

var shuttle;
function init(){

    // Key object initialization
    window.addEventListener('keyup', function(event) { Key.onKeyup(event); }, false);
    window.addEventListener('keydown', function(event) { Key.onKeydown(event); }, false);


    myStage = new createjs.Stage("myCanvas");

    //var engine = new Engine(200,300);
    var r = 10;
    shuttle = new Shuttle(r);
    shuttle.steering = Key;
    shuttle.addEngine(-r,0,0);
    shuttle.addEngine(r,0,0);
    shuttle.x = 500;
    shuttle.y = 200;
    //shuttle.velocity.dx = 1;
    //shuttle.avelocity = 1;

    myStage.addChild(shuttle);

    Physics.objects = [shuttle];

    createjs.Ticker.setFPS(60);
    createjs.Ticker.addEventListener('tick', tick);

}

function tick(){
    shuttle.shuttleTick();
    Physics.update();
    myStage.update();
}
</script>


</head>
<body onload="init()">
<canvas id="myCanvas" width="1200" height="600">

</canvas>
</body>
</html>

Solution

  • Your specific problem is that you are extending the Container class, but not initializing it when creating your Engine instances. If you insert this at the top of the Engine(width, height) function, it should work:

    this.initialize();
    

    More generally though, you should probably look into how Javascript's prototypal inheritance works - your code is quite hard to read and unnecessarily complicated.

    There are many different methods for implementing "classic" OOP inheritance patterns in JS, but since you are working with CreateJS, the most useful approach in your case is probably learning their method first, adjust your classes to follow the same pattern, and work from there - see e.g. this question.