Difference between revisions of "Rot.js tutorial, part 3"

From RogueBasin
Jump to navigation Jump to search
Line 85: Line 85:
     this.player = this._createBeing(Player, freeCells);
     this.player = this._createBeing(Player, freeCells);
     this.pedro = this._createBeing(Pedro, freeCells);
     this.pedro = this._createBeing(Pedro, freeCells);
}
Game.init = function() {
    /* ...previous stuff... */
    this.engine.addActor(this.player);
    this.engine.addActor(this.pedro);
}
}
</syntaxhighlight>
</syntaxhighlight>

Revision as of 14:34, 13 December 2012

This is the third part of a rot.js tutorial.

FIXME THIS IS A WORK IN PROGRESS, NOT FINISHED YET!

Looking inside the box

The game generates several boxes, but so far, none of the contains the prized ananas. Let us store the ananas in the first box generated:

Game.ananas = null;

Game._generateBoxes = function(freeCells) {
    for (var i=0;i<10;i++) {
        /* ...previous stuff... */
        if (!i) { this.ananas = key; } /* first box contains an ananas */
    }
}

Apart from moving, there is one more interaction a player must perform: looking into boxes. We will allow both Enter (keyCode 13) and Spacebar (keyCode 32) for this action:

Player.prototype.handleEvent = function(e) {
    var code = e.keyCode;
    if (code == 13 || code == 32) {
        this._checkBox();
        return;
    }
}

Opening a box to verify its contents is as simple as comparing current player's position with our list of boxes and the stored ananas position:

Player.prototype._checkBox = function() {
    var key = this._x + "," + this._y;
    if (Game.map[key] != "*") {
        alert("There is no box here!");
    } else if (key == Game.ananas) {
        alert("Hooray! You found an ananas and won this game.");
        Game.engine.lock();
        window.removeEventListener("keydown", this);
    } else {
        alert("This box is empty :-(");
    }
}

Pedro, the angry owner

The game is now winnable! Let's add a villain as a second actor. We will place him using the same algorithm we used previously. To do this, let's refactor the original _createPlayer method into a more useful parametrized factory _createBeing by passing a constructor function as an argument:

var Pedro = function(x, y) {
    this._x = x;
    this._y = y;
    this._draw();
}
    
Pedro.prototype.getSpeed = function() { return 100; }
    
Pedro.prototype._draw = function() {
    Game.display.draw(this._x, this._y, "P", "red");
}

Game._createBeing = function(what, freeCells) {
    var index = Math.floor(ROT.RNG.getUniform() * freeCells.length);
    var key = freeCells.splice(index, 1)[0];
    var parts = key.split(",");
    var x = parseInt(parts[0]);
    var y = parseInt(parts[1]);
    return new what(x, y);
}

Game._generateMap = function() {
    /* ...previous stuff... */
        
    this.player = this._createBeing(Player, freeCells);
    this.pedro = this._createBeing(Pedro, freeCells);
}

Game.init = function() {
    /* ...previous stuff... */

    this.engine.addActor(this.player);
    this.engine.addActor(this.pedro);
}

This might be confusing to some, but passing functions around (as function arguments, for instance) is very common in JavaScript.

Pathfinding-based AI

Pedro is missing its act() method so far. We are going to use one of rot.js's pathfinding functions to implement Pedro's behavior.

And that's all for part 3. The whole working code is available at jsfiddle.net.