Tile.js

/**
 * Represents a single Tile object to be contained within a Grid.
 * @constructor
 * @param {number} tileW - The width of this tile in WC.
 * @param {number} tileH - The height of this tile in WC.
 * @param {number} tileX - The x coordinate of this tile in WC.
 * @param {number} tileY - The y coordinate of this tile in WC.
 * @param {boolean} isEdge - The property determining if this tile is on the edge of the Grid its in.
 */
function Tile(tileW, tileH, tileX, tileY, isEdge) {
  this.mXPos = tileX;
  this.mYPos = tileY;
  this.mWidth = tileW;
  this.mHeight = tileH;
  this.mTexture = null;
  this.mRenderComponent = null;
  this.mCollidable = false;
  this.mVisible = false;
  this.mGridLinesVisible = false;
  this.mWallsVisible = false;
  this.mWalls = [];
  this.mMoves = [];
  this.mIsEdge = isEdge;
  this.mCost = 0;
  this.mHCost = 0;
  this.mDirection = [0, 0]; // code for stop
  this.mParent = [-1, -1];
  this.mWallLines = [];
  
  // initialize moves
  this.mMoves.push([1, 0]);
  this.mMoves.push([-1, 0]);
  this.mMoves.push([0, 1]);
  this.mMoves.push([0, -1]);
  
  // now, create the edge lines
  this._createEdgeLines(tileW, tileH, tileX, tileY);
}

// Draw the tile as LineRenderables around the bounds of the tile.

/**
 * Draws the tile as visible lines around its bounds. Also draws its texture if it has one and is set to visible.
 * @param {Camera} cam - The Camera object to draw the tile to.
 */
Tile.prototype.draw = function(cam) {
  // draw the renderable of the texture if exists and is visible
  if (this.mVisible === true && this.mRenderComponent !== null) {
    this.mRenderComponent.draw(cam);
  }
  // if we have set the edges to be visible
  if (this.mGridLinesVisible === true) {
    // if this is an edge tile, draw the top and left LineRenderables
    if (this.mIsEdge === true) {
      // draw left and top LineRenderables
      this.mEdgeLines[0].draw(cam); // the left line
      this.mEdgeLines[1].draw(cam); // the top line
    }
    // draw bottom and right LineRenderables
    this.mEdgeLines[2].draw(cam); // the right line
    this.mEdgeLines[3].draw(cam); // the bottom line
  }

  // draw wall lines
  if (this.mWallsVisible) {
    for (var i = 0; i < this.mWalls.length; i++) {
        // if this is top or bottom
        if (this.mWalls[i][0] === 0) {
            if (this.mWalls[i][1] === -1) {
                // bottom wall
                this.mWallLines[3].draw(cam);
            } else {
                // top wall
                this.mWallLines[1].draw(cam);
            }
        }
        else {
            // else, this is a left or right wall
            if (this.mWalls[i][0] === -1) {
                // left wall
                this.mWallLines[0].draw(cam);
            } else {
                // right wall
                this.mWallLines[2].draw(cam);
            }
        }
    }
  } 
};

/**
 * Gets the x position of the center of the tile in WC.
 * @returns {number} The x position of the tile center in WC.
 */
Tile.prototype.getXPosWC = function() {
  return this.mXPos;
};

/**
 * Gets the y position of the center of the tile in WC.
 * @returns {number} The y position of the tile center in WC.
 */
Tile.prototype.getYPosWC = function() {
  return this.mYPos;
};

/**
 * Gets the collision property of this tile.
 * @returns {boolean} True if this tile has collision on, false otherwise.
 */
Tile.prototype.getCollision = function() {
  return this.mCollidable;
};

/**
 * Sets the collision property of this tile.
 * @param {boolean} bool - The value to set the collision property of this tile to.
 */
Tile.prototype.setCollision = function(bool) {
  this.mCollidable = bool;
};

// Push given direction to the walls array.
// Might also want a func that can remove walls.
// Return true if new wall was added, false if the wall already exists.

/**
 * Adds the given direction to the walls array for this particular tile.
 * @param {Direction} direction - The direction to add a wall to for this tile.
 * @returns {boolean} True if the wall was able to be added, false otherwise.
 */
Tile.prototype.addWall = function(direction) {
  for (var i = 0; i < this.mWalls.length; i++) {
      if (direction === this.mWalls[i]) {
          return false;
      }
  }
  var temp = this.mMoves.indexOf(direction);
  if (temp > -1) {
      this.mMoves.splice(temp, 1);  // remove the direction from moves
  }
  this.mWalls.push(direction);
  return true;
};

/**
 * Removes the given direction to the walls array for this particular tile.
 * @param {Direction} direction - The direction to remove a wall to for this tile.
 * @returns {boolean} True if the wall was able to be removed, false otherwise.
 */
Tile.prototype.removeWall = function(direction) {
    for (var i = 0; i < this.mWalls.length; i++) {
        if (direction[0] === this.mWalls[i][0] && direction[1] === this.mWalls[i][1]) {
            this.mWalls.splice(i, 1);
            this.mMoves.push(direction);
            return true;
        }
    }
    return false;
};

/**
 * Gets all the walls currently assigned to this tile.
 * @returns {array} All the directional walls assigned to this tile.
 */
Tile.prototype.getWalls = function() {
  return this.mWalls;
};

/**
 * Gets all the valid moves out of a particular tile. That is, any side of this tile that doesn't have a wall.
 * @returns {array} All the directional movements possible out of this tile.
 */
Tile.prototype.getMoves = function() {
  return this.mMoves;
};

// May modify later to support passing specific texture renderables to fill a tile with, 
// rather than just a texture path corresponding to a loaded texture asset.

/**
 * Sets the texture for this tile to the texture corresponding to a given filepath.
 * @param {String} texture - The filepath to an already loaded texture to set the tile to contain.
 */
Tile.prototype.setTexture = function(texture) {
  this.mRenderComponent = new TextureRenderable(texture);
  this.mRenderComponent.setColor([1, 1, 1, 0]);
  this.mRenderComponent.getXform().setPosition(this.mXPos, this.mYPos);
  this.mRenderComponent.getXform().setSize(this.mWidth, this.mHeight);
  this.mTexture = texture;
};

/**
 * Gets the visibility property of this tile.
 * @return {boolean} True if this tile is set to visible, false otherwise.
 */
Tile.prototype.isVisible = function() {
  return this.mVisible;
};

/**
 * Sets the visibility of the tile. Cannot set a tile to visible if it doesn't have an assigned texture.
 * @param {boolean} setTo - The value to set the visibility property to.
 * @returns {boolean} True if the settting was successful, false otherwise.
 */
Tile.prototype.setVisible = function(setTo) {
  if (this.mTexture === null) { // No texture, so don't modify visibility.
    return false;
  } else {
    this.mVisible = setTo;
    return true;
  }
};

/**
 * Sets the visibility property of the grid lines around this tile.
 * @param {boolean} setTo - The value to set the grid line visibility to.
 */
Tile.prototype.setGridLineVisibility = function(setTo) {
  this.mGridLinesVisible = setTo;
};


/**
 * Sets the visibility property of the wall lines around this tile.
 * @param {boolean} setTo - The value to set the wall line visibility to.
 */
Tile.prototype.setWallVisibility = function(setTo) {
  this.mWallsVisible = setTo;
};

/**
 * Generates the edge line renderables around this particular tile on creation.
 * @private
 * @param {number} tileW - The width of this tile in WC.
 * @param {number} tileH - The height of this tile in WC.
 * @param {number} tileX - The x coordinate of this tile in WC.
 * @param {number} tileY - The y coordinate of this tile in WC.
 */
Tile.prototype._createEdgeLines = function(tileW, tileH, tileX, tileY) {
  this.mEdgeLines = [];
  var leftX = tileX - (tileW / 2);
  var rightX = tileX + (tileW / 2);
  var topY = tileY + (tileH / 2);
  var bottomY = tileY - (tileH / 2);
  var leftLine = new LineRenderable(leftX, topY, leftX, bottomY);
  var rightLine = new LineRenderable(rightX, topY, rightX, bottomY);
  var topLine = new LineRenderable(leftX, topY, rightX, topY);
  var bottomLine = new LineRenderable(leftX, bottomY, rightX, bottomY);
  this.mEdgeLines.push(leftLine);
  this.mEdgeLines.push(topLine);
  this.mEdgeLines.push(rightLine);
  this.mEdgeLines.push(bottomLine);
};


/**
 * Generates the wall line renderables around this particular tile on creation.
 * @private
 * @param {number} tileW - The width of this tile in WC.
 * @param {number} tileH - The height of this tile in WC.
 * @param {number} tileX - The x coordinate of this tile in WC.
 * @param {number} tileY - The y coordinate of this tile in WC.
 */
Tile.prototype._createWallLines = function(tileW, tileH, tileX, tileY) {
  
  var leftX = tileX - (tileW / 2);
  var rightX = tileX + (tileW / 2);
  var topY = tileY + (tileH / 2);
  var bottomY = tileY - (tileH / 2);
  var leftLine = new LineRenderable(leftX, topY, leftX, bottomY);
  leftLine.setColor([1, 1, 1, 1]);
  var rightLine = new LineRenderable(rightX, topY, rightX, bottomY);
  rightLine.setColor([1, 1, 1, 1]);
  var topLine = new LineRenderable(leftX, topY, rightX, topY);
  topLine.setColor([1, 1, 1, 1]);
  var bottomLine = new LineRenderable(leftX, bottomY, rightX, bottomY);
  bottomLine.setColor([1, 1, 1, 1]);
  this.mWallLines.push(leftLine);
  this.mWallLines.push(topLine);
  this.mWallLines.push(rightLine);
  this.mWallLines.push(bottomLine);
};

/**
 * Resets any data stored from previous A* searches to their default values.
 */
Tile.prototype.readySearch = function() {
    this.mCost = 0;
    this.mHCost = 0;
    this.mDirection = [0, 0];
    this.mParent = [-1, -1];
};


/**
 * Used for A* search. Sets the cost for the tile.
 * @param {number} c The total cost of reaching this tile.
 */
Tile.prototype.setC = function(c) { this.mCost = c; };

/**
 * Used for A* search. Retrieves the cost for the tile.
 * @returns {number} The total cost of reaching this tile.
 */
Tile.prototype.getC = function() { return this.mCost; };

/**
 * Used for A* search. Stores the given heuristic estimate for the tile.
 * @param {number} h The estimate to the goal given by a heuristic.
 */
Tile.prototype.setH = function(h) { this.mHCost = h; };

/**
 * Used for A* search. Retrieves the given heuristic estimate for the tile.
 * @returns {number} The estimate to the goal given by a heuristic.
 */
Tile.prototype.getH = function() { return this.mHCost; };

/**
 * Used for A* search. Returns the combined total of the tile's cost and heuristic.
 * @returns {number} The combined total of the tile's cost and heuristic..
 */
Tile.prototype.getF = function() { return this.mCost + this.mHCost; };

/**
 * Used for A* search. Sets the direction we took to get to this tile.
 * @param {array} d Array containing a direction.
 */
Tile.prototype.setD = function(d) { this.mDirection = d; };

/**
 * Used for A* search. Returns the direction we took to get to this tile.
 * @returns {array} Array containing a direction.
 */
Tile.prototype.getD = function() { return this.mDirection; };

/**
 * Used for A* search. Sets the predecessor to this tile.
 * @param {array} p Array containing the index of the predecessor tile.
 */
Tile.prototype.setP = function(p) { this.mParent = [p[0], p[1]]; };

/**
 * Used for A* search. Returns the predecessor to this tile. If no predecessor,
 * returns [-1, -1].
 * @returns {array} Array containing the index of the predecessor tile.
 */
Tile.prototype.getP = function() { return this.mParent; };

/**
 * Method used during A* search. Determines if this tile has a predecessor tile or not.
 * @returns {boolean} Whether this tile has a predecessor tile or not.
 */
Tile.prototype.hasP = function() {
    return ((this.mParent[0] > -1) && (this.mParent[1] > -1));
};