Grid_Objects.js

/*
 * Manages the object interactions explicitly given to the grid object. Defines object
 * behaviors such as movement, pathfinding, etc. Does not define interactions for objs 
 * not explicitly given to the Grid to manage.
 * 
 */


/**
 * Adds an object to the Grid system. Movement & positioning of this object are then 
 * controlled through the Grid object itself.
 * @param {Renderable} obj - The object to be added. MUST have an associated Xform, else the function will error.
 * @returns {number} The ID to use to retrieve this object in the grid to perform future functions on it. -1 If object 
 * couldn't be added.
 */
Grid.prototype.addObjectToGrid = function(obj) {
    // Error chk: Given object must have an Xform to modify position.
    try {
        obj.getXform();
    } catch (error) {
        console.log(error);
        return -1;
    }

    // Add object to mObject array. Put the object in the first available spot.
    var id;
    var added = false;
    for (id = 0; id < this.mObjects.length; id++) {
      if (this.mObjects[id] === null) {
        this.mObjects[id] = obj;
        added = true;
        break;
      }
    }
    // mObjects was not large enough to hold the object; push it to the end.
    if (!added) {
      this.mObjects.push(obj);
      id = this.mObjects.length - 1;
    }

    var pos = obj.getXform().getPosition();
    var tileIndex = this.getTileAtWC(pos[0], pos[1]);
    var tile = null;

    // Invalid init tile position
    if (tileIndex[0] === -1 && tileIndex[1] === -1) {
      var indexX = 0;
      var indexY = 0;

      tile = this.getTileAtIndex(indexX, indexY);

      // Keep looking for a new default tile until we find one that is not occupied.
      while (tile.getCollision()) {
        indexX++;
        tile = this.getTileAtIndex(indexX, indexY);

        // Entire X row searched and no available spots; move up a row.
        if (tile === null) {
          indexX = 0;
          indexY++;
          tile = this.getTileAtIndex(indexX, indexY);
        }

        // Termination case if all grid tiles have been checked & are full. ******
        if (indexY === (this.mGridH - 1) && indexX === (this.mGridW - 1) && tile === null) {
          console.log("Object could not be added; Grid is full!");
          return -1;
        }
      }
    } else {
      tile = this.getTileAtIndex(tileIndex[0], tileIndex[1]);
    }
    
    // We now have our tile to tie the object to; Send it to its position & enable collision.
    obj.getXform().setPosition(tile.getXPosWC(), tile.getYPosWC());
    tile.setCollision(true);

    // Leaving having the size of the object fit within a grid bound up to the game dev to do.

    // Addition successful. Return id.
    return id;
};

// Given the id of an object belonging to the grid, removes the object from grid control.
// Note, this does not remove the object from existence, rather just removes its direct
// ties to the grid. 
// Returns true if removal was successful, false otherwise.
// Requires the array to stay at the same size, else ids may no longer return expected objs.

/**
 * Removes the desired object from Grid system control. This does not remove the object from the 
 * world.
 * @param {number} id - The id of an object currently existing in the grid.
 * @returns {boolean} True if the object corresponding to id was removed, false otherwise.
 */
Grid.prototype.removeObjectFromGrid = function(id) {
  if (this.mObjects[id] === null) {
    return false;
  }

  this.mObjects[id] = null;

  return true;
};

/**
 * Attempts to move the specified object from its current tile position to a given 
 * tile index. Does not check for any collision in the tiles between the current tile 
 * and the desired tile to move to, only checks the desired tile collision property.
 * @param {number} id - The id of the object to move.
 * @param {number} x - The x coordinate of the Grid index to move to.
 * @param {number} y - The y coordinate of the Grid index to move to.
 * @returns {boolean} True if the move was successful, false otherwise.
 */
Grid.prototype.changeObjectPosition = function(id, x, y) {
    var obj = this.mObjects[id];
    if (obj === null || obj === undefined) {
        return false;
    }
    
    var pos = this.getIDPosition(id);
    
    // Tile object is currently in.
    var tile = this.getTileAtIndex(pos[0], pos[1]);
    
    var newTile = this.getTileAtIndex(x, y);
    if (newTile === null || newTile.getCollision()) { //Invalid tile coord given, or has collision already
        return false;
    }
    
    obj.getXform().setPosition(newTile.getXPosWC(), newTile.getYPosWC());
    tile.setCollision(false);
    newTile.setCollision(true);
    
    return true;
};

// A bit redundant w/ above function at the moment, should probably rework a bit.

/**
 * Moves the object specified by the given ID one space in the given direction. Considers collision 
 * property and current walls of the tile to move into.
 * @param {number} id - The id of the object to move.
 * @param {Direction} direction - The direction to move the object one tile space.
 * @returns {boolean} True if move was successful, false otherwise.
 */
Grid.prototype.moveObjectPositionDir = function(id, direction) {
    var obj = this.mObjects[id];
    if (obj === null || obj === undefined) {
        return false;
    }
    
    var pos = this.getIDPosition(id);
    
    // Tile object is currently in.
    var tile = this.getTileAtIndex(pos[0], pos[1]);
    
    // Wall check
    var walls = tile.getWalls();
    for (var i = 0; i < walls.length; i++) {
        if (direction[0] === walls[i][0] && direction[1] === walls[i][1]) { // Given direction has a wall, prevent movement.
            return false;
        }
    }
    
    var newTile = this.getTileAtIndex(pos[0] + direction[0], pos[1] + direction[1]);
    if (newTile === null || newTile.getCollision()) { //Invalid tile coord given, or has collision already
        return false;
    }
    
    obj.getXform().setPosition(newTile.getXPosWC(), newTile.getYPosWC());
    tile.setCollision(false);
    newTile.setCollision(true);
    
    return true;
};

// Returns the position of the specified object in Grid coordinates.
// Returns [-1, -1] if the given ID is invalid.

/**
 * Gets the Grid index position of the specified object.
 * @param {number} id - The id of the object to get the index position of.
 * @return {array} The x & y coordinates in the Grid index of the object, [-1, -1] if object was not found.
 */
Grid.prototype.getIDPosition = function(id) {
    if (this.mObjects[id] === null) {
      return [-1, -1];
    }

    var pos = this.mObjects[id].getXform().getPosition();

    // Object already exists within Grid, so we can assume this will be a valid tile.
    return this.getTileAtWC(pos[0], pos[1]);
};