Вопрос

I'm creating an animation piece using EaselJS and am running into a problem with it's Inheritance when trying to declare reusable objects.

For example, in my animation piece I want to draw multiple coins at different points on the canvas, and then animate said coin.

This is how my code looks like at the moment:

(function() {

var Coin = function(container) {
    this.initialize(container);
}

var c = Coin.prototype = new createjs.Container(); 

c.Container_initialize = c.initialize;

c.initialize = function() {
    this.Container_initialize();

    var coinInstance = this, 
    coin = new createjs.Bitmap(loader.getResult('coin'));   

    createjs.Ticker.addEventListener('tick', function() {
        var characterBitmap = character.children[0].children[0];
        var coinBitmap = coinInstance.children[0],
        collided = ndgmr.checkPixelCollision(characterBitmap, coinBitmap);

        if(collided && coinInstance.alpha == 1) {
            createjs.Tween.get(coinInstance).to({y: coinInstance.y-100, alpha: 0}, 300);
        }

    });

    this.addChild(coin);
}

window.Coin = Coin;

}());

function drawCoin(container, positionX, positionY) {
    var coin = new Coin();
    coin.x = positionX;
    coin.y = positionY;

    container.addChild(coin);
}

Now to clarify - this piece of code does work - however I feel it could be better executed. Ideally I would like to be able to declare the function the event listener fires once (e.g. how I have c.initialize, have c.animate). My problem is when I make this change, the animation looses the instance of 'this' and I can no longer locate the specific instance of the coin to animate based on its properties.

Any ideas fellow developers?

Это было полезно?

Решение

Let's assume you are making a Super Mario clone. The way I would handle this would be to have a World class, that housed the Mario and the Coin instances.

Rather than having the "tick" listener in the Coin class, create it on the World class. Then, using a delegate utility, scope the tick event handler to the World instance. You can then loop through the coins checking for collision with Mario and animate them off as necessary. Consider the following example and bonus Delegate utility I've written.

The benefit here is that you aren't having to keep track all the coin tick listeners which could lead to memory leaks and performance issues. Secondly, by delegating the event listeners, you no longer have to hack your way into finding the DisplayObject you want. i.e. character.children[0].children[0].

Disclaimer, I haven't run this code so I can't promise it is error free

World.js

(function() {

var World = function(container) {
    this.initialize(container);
}

var p = World.prototype = new createjs.Container(); 

p.Container_initialize = c.initialize;

p.character;
p.coins = [];

p.initialize = function() {
    this.Container_initialize();

    //Create Mario
    this.character = new Mario();
    this.addChild(this.character);

    //Create 100 coins in a horizontal row
    var xPos = 0;
    for(var i = 0; i < 100; i++){
        var coin = new Coin();
        coin.x = xPos;
        this.coins.push(coin);
        this.addChild(coin);
        xPos += 100;
    }

    //Scope the tick listener to 'this', being the instance of the World class.
    createjs.Ticker.addEventListener('tick', ns.Delegate.create(this, this.ticker_Tick));
}

p.ticker_Tick = function(){
    //Since we have scoped this function to 'this' we can reference the World properties using 'this';
    for(var i = 0; i < this.coins.length; i++){
        var coin = this.coins[i];
        var collided = ndgmr.checkPixelCollision(this.character, coin);
        if(collided){
            //You may want to add an on complete handler here to remove the coin once animated off
            createjs.Tween.get(coin).to({y: coin.y-100, alpha: 0}, 300);
        }
    }
};

window.World = World;

}());

Delegate.js

this.ns = this.ns || {};

(function(){
    var Delegate = function(){
        throw new Error("Cannot directly instantiate Delegate. Use Delegate.create()");
    }

    Delegate.create = function(contextObject, delegateMethod){
        return function () {
            return delegateMethod.apply(contextObject, arguments);
        }
    }

    var p = Delegate.prototype;

    ns.Delegate = Delegate;
}());
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top