4
\$\begingroup\$

I've come up with two ways to do sprite movement with CreateJS, and I'm wondering if one is better than the other as far as performance and maintainability.

The player data is saved in a json file and looks like this:

{
  "spritesheets": ["head_short.json", "clothes.json"],
  "animation": "stance_w",
  "position": [300, 100],
  "speed": 0.1
}

Both share the following code used for loading and instantiating the player object:

(Don't get too hung up on the loading stuff. It's fairly complex and might take a while to step through. I just included it in case someone wanted to see.)

var stage = new createjs.Stage('stage');

function load(filename, callback) {
    var loader = new createjs.LoadQueue(true, 'json/');
    loader.loadFile(filename);
    loader.on('fileload', function (obj) {
        if (typeof callback == 'function') {
            callback(obj.result);
        }
    });
}

function loadPlayer(filename, callback) {
    load(filename, function (result) {
        var player = new Player();

        for (var s = 0; s < result.spritesheets.length; s++) {
            loadSpriteSheet(result.spritesheets[s], function (spriteSheet) {
                var sprite = new createjs.Sprite(spriteSheet);

                player.addSprite(sprite);

                if (result.animation) {
                    player.animate(result.animation);
                }

                if (result.position) {
                    player.setPosition(result.position[0], result.position[1]);
                }

                if (result.speed) {
                    player.setSpeed(result.speed);
                }

                if (player.sprites.length == result.spritesheets.length
                    && typeof callback == 'function') {
                    callback(player);
                }
            });
        }
    });
}

function loadSpriteSheet(filename, callback) {
    load(filename, function (result) {
        var spriteSheet = new createjs.SpriteSheet({
                images: result.images,
                frames: result.frames,
                animations: result.animations
            });

        if (typeof callback == 'function') {
            callback(spriteSheet);
        }
    });
}

createjs.Ticker.timingMode = createjs.Ticker.RAF;
createjs.Ticker.on('tick', function (event) {
    stage.update(event);
});

Then, the first implementation has the following. When the mouse is clicked anywhere on the stage, player.move is called once:

loadPlayer('player.json', function (player) {
    player.draw(stage);
    stage.on('stagemousedown', function (event) {
        player.move(event.stageX, event.stageY, createjs.Ticker);
    });
});

player.move sets up an event listener for the tick event, then unsets it once it reaches the coordinates. The ticker is passed as a parameter:

Player.prototype.move = function (x, y, ticker) {
    var angle = Math.atan2(y - this._position.y, x - this._position.x),
        self = this;

    if (this._listener) {
        ticker.off('tick', this._listener);
    }

    this._listener = ticker.on('tick', function (event) {
        var magnitude = event.delta*self._speed,
            velocity = {x: magnitude*Math.cos(angle), y: magnitude*Math.sin(angle)};

        self.setPosition(self._position.x + velocity.x, self._position.y + velocity.y);

        if (self.hasPosition(x, y)) {
            ticker.off('tick', self._listener);
        }
    });
};

The second implementation has this instead. player.update is called on every tick regardless. When the mouse is clicked anywhere on the stage, player.setWaypoint is called once:

loadPlayer('player.json', function (player) {
    player.draw(stage);

    createjs.Ticker.on('tick', function (event) {
        player.update(event);
    });

    stage.on('stagemousedown', function (event) {
        player.setWaypoint(event.stageX, event.stageY);
    });
});

player.update calls player._updatePosition, which moves the player as long as it has a waypoint:

Player.prototype.update = function (event) {
    this._updatePosition(event);
};

Player.prototype._updatePosition = function (event) {
    var angle, magnitude, velocity;

    if (!this._speed || !this._waypoint) {
        return;
    }

    angle = Math.atan2(this._waypoint.y - this._position.y, this._waypoint.x - this._position.x);
    magnitude = event.delta*this._speed;
    velocity = {x: magnitude*Math.cos(angle), y: magnitude*Math.sin(angle)};

    this.setPosition(this._position.x + velocity.x, this._position.y + velocity.y);

    if (this.hasPosition(this._waypoint.x, this._waypoint.y)) {
        this._waypoint = null;
    }
};

Thoughts?

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.