Board Game Experiment, with JS Prototypes and Canvas

The User Player

This particular object is the person that plays. It’s a child of our Player object.

function User(i, base, limit) {
  'use strict';
  this.setName();
  // Call the parent constructor
  Player.call(this, i, base, limit);
}
// Inherit Player
User.prototype = Object.create(Player.prototype);

Events Handlers

Our player is using his mouse to play. Right. So we need events handlers. We’re going to use jQuery here as well.

For a click, we attempt to execute the action. When the mouse moves, we attempt to preview it. If the mouse is out, we simply refresh the rendering.

User.prototype.play = function () {
  'use strict';
  // We won't be able to access "this" in the coming event-handlers
  var user = this;
  // Reset the action
  user.action = false;
  jQuery(game.canvas).click(function (event) {
    // If the user clicked, we get the action corresponding to the current mouse position
    user.setAction(event);
    if (!user.action) {
      // Wrong action : let's display the concerned rule
      user.alert(game.rule);
    } else {
      // Good action : Let's unbind those handlers and execute it !
      jQuery(game.canvas).unbind();
      if (user.action instanceof Square) { user.move(user.action); } else { user.putUp(user.action); }
    }
  });
  jQuery(game.canvas).mousemove(function (event) {
    // Every time the mouse is moving over the canvas, we get the action that its position would trigger on a click
    if (user.setAction(event)) {
      // We render and preview that action
      game.render(user.action);
      // And we update the cursor
      jQuery(game.canvas).css('cursor', (user.action !== false) ? 'default' : 'not-allowed');
    }
  });
  // If the mouse is exiting the board, we reset and redraw
  jQuery(game.canvas).mouseout(function () {
    user.action = false;
    game.render();
  });
};

Action Detection

For a given event (an object containing our mouse position), we can guess which object to return.

If the pointer is over a span (a gap between two squares), we guess a fence. Otherwise (and as long as it is over a pattern unit) we guess a Square. Then if we have a valid Object, we return it. We return false in any other situation.

User.prototype.setAction = function (event) {
  'use strict';
  // Get the mouse position from the event object
  var offset = jQuery(game.canvas).offset(),
    pointer = {x: (event.pageX - offset.left) / game.pattern, y: (event.pageY - offset.top) / game.pattern},
    // From this position we deduce the action implied
    action = this.getSpan(pointer) || this.getSquare(pointer);
  // Was this action already requested ? Are we actually talking about an action currently showed as a preview ?
  if ((action.a === this.action.a) && (action.b === this.action.b) && ((action instanceof Square && this.action instanceof Square) || (action.horizontal === this.action.horizontal))) {
    // If yes, then our job here is done.
    return false;
  }
  // Is this a valid action ?
  if (((action instanceof Square) && this.validSquare(action)) || (!(action instanceof Square) && game.validFence(action, this.limit))) {
    // If yes, let's set it up and return true
    this.action = action;
    return true;
  }
  // Was the last action invalid as well ?
  action = !!this.action;
  this.action = false;
  // And we return the answer to the question : was a new action set ?
  return action;
};

Action Getters

Those methods attempt to catch a particular action (a fence or a square).

User.prototype.getSpan = function (pointer) {
  'use strict';
  // "a" and "b" here are the pattern coordinates, and "x" and "y" the coordinates of the pointer within this pattern unit.
  var shift = game.units.square / 2,
    a = Math.floor(pointer.x),
    b = Math.floor(pointer.y),
    x = pointer.x - a,
    y = pointer.y - b,
    horizontal;
  // If we don't have any fences left, no need to continue
  if (this.left === 0) { return false; }
  // Is our pointer over a span (a gap between two squares) ?
  if ((x > game.units.square) || (y > game.units.square)) {
    horizontal = (x < y);
    a = (horizontal && (x < shift)) ? a - 1 : a;
    b = (!horizontal && (y < shift)) ? b - 1 : b;
    // Avoid the fence to be defined out of the board
    if (a < 0) { a = 0; } else if (a >= game.size) { a = game.size - 1; }
    if (b < 0) { b = 0; } else if (b >= game.size) { b = game.size - 1; }
    // Yep, let's return the corresponding fence
    return {a: a, b: b, horizontal: horizontal};
  }
  // Nope, no fence to return
  return false;
};

User.prototype.getSquare = function (pointer) {
  'use strict';
  // Returning the closest Square.
  return game.board[Math.floor(pointer.x)][Math.floor(pointer.y)];
};

Alert Messages

Displays a given rule in the game’s caption.

User.prototype.alert = function (rule) {
  'use strict';
  // Remind the user of a rule
  jQuery('#caption').html(jQuery('#rule-' + rule).html());
};