Undefined

この記事は1年以上前に書かれたものです。現在の状況にそぐわない場合がございますのでご注意ください。

JavaScriptで三目並べゲームをつくる 第5回

ゲームボードクラスオブジェクトを実装する

この記事について

今回は過去回の記事でご紹介したクラスモジュールを使用して、ゲームボードクラスオブジェクトの実装をご紹介したいと思います。

三目並べゲームの完成形はこちらです。

クラスオブジェクト

クラスの概要

概要
ゲームボードの情報を受け持つクラスオブジェクトです。
ゲームボードの設定情報やマス目の状態・更新を管理します。ゲームスタート時にはゲームボードの準備をします。

どんな情報を受け持つ? (プロパティ) どんな仕事を受け持つ? (メソッド)
  •  何目並べか(各辺のマス目数)
  • 全マス目数
  • 全マス目の配列
  • 選択済みのマス目
  • 現在選択されたマス目
  • (リ)スタート時、プレイデータを(リ)セットする
  • ゲームボードの作成をする
  • 選択されたマス目を記録する
  • マス目の表示を更新する

プライベートな静的変数(定数)

// マス目要素の識別子
var UNIT_PREFIX = 'data-board-unit';

// マス目選択不可状態時の表示テキスト 
var DISABLED_STR = {
    thinking: 'が考え中です…'
};

ふたつの静的変数を持っています。

  • UNIT_PREFIXは各マス目を識別するためのインデックス番号に使用する独自データ属性の属性名です。
  • DISABLED_STRはオートプレイヤーのターン時に、マス目を選択不可にするためにゲームボードに被せるレイヤーのテキスト表示に使います。

各マス目を識別するためのインデックス番号

ゲームボードのマス目のインデックス番号対応図です

コンストラクタ

/* コンストラクタ */
var that = function Board(unitNum) {
  :
}

このゲームボードインスタンスオブジェクトはゲームの初回プレイ開始時のみ生成されます。引数unitNumはゲーム設定オプションで設定されている何目並べかの情報です。

どんな情報を持っているか (プロパティ)

// 各辺のマス目数(何目並べか)
this.unitNum       = unitNum,
// 全マス目数
this.allUnitNum    = Math.pow(this.unitNum, 2);
// 全マス目の配列
this.allUnitsArray = this.createAllUnitsArray();
// 選択済みのマス目
this.selectedNum;
// 現在選択されたマス目
this.curSelect;
// カスタムイベント
this.ev = {};

/* DOMアクセス */
// ゲームボード
this.boardEl    = document.querySelector('#js-board');
// マス目を選択不可にする
this.disabledEl = document.querySelector('#js-disabled');
// マス目を選択不可にする
this.infoEl     = document.querySelector('#js-disabled-info');
// マス目 
this.unitsEls;

ゲームボードクラスオブジェクトが受け持つ情報はゲームボードに関わるものです。各プロパティが保持する情報はコメントの通りです。

DOMアクセスのためのプロパティthis.disabledElthis.infoElはともに、オートプレイヤーのターン時に、マス目を選択不可にするためにゲームボードに被せる要素のためのものです。

this.unitsElsは初回ゲーム開始時にマス目が生成されるとき、各マス目のノードリストが保存されます。

どんな通知を受け取るか(イベント)

/* カスタムイベント設定 */
// ゲームがスタートされたとき
this.ev.init = document.createEvent('Event');
this.ev.init.initEvent('board.init', false, true);
// マス目が選択されたとき
this.ev.autoClick = document.createEvent('Event');
this.ev.autoClick.initEvent('click', false, true);
// ゲームのターンが進んだとき
this.ev.disabled = document.createEvent('Event');
this.ev.disabled.initEvent('board.disabled', false, true);

/* イベント */
// ゲームがスタートされたとき
this.boardEl.addEventListener('board.init', this.init.bind(this), false);
// ゲームのターンが進んだとき
this.disabledEl.addEventListener('board.disabled', this.toggleDisabled.bind(this), false);

みっつのカスタムイベントを使用しています。

  1. イベントタイプboard.initは、ゲームの初回のプレイが開始されたとき発生します。
  2. イベントタイプ clickは、オートプレイヤー時マス目自動選択されたときに発生します。
  3. イベントタイプboard.disabledは、ターンが進んだときに発生します。

 クリックイベントをわざわざカスタムイベントで設定しているのは、マス目自動選択という実動作(クリック)のエミュレーションを通知する術が他に見つけられなかったためです。イベントはその通知先の要素に対して、引数で該当するイベントオブジェクトを渡したdispatchEventメソッドを実行することで呼び出します。マス目の持つデフォルトのクリックイベントオブジェクトをdispatchEventメソッドに渡す方法がわからなかったので、カスタムイベントとしてクリックのベントオブジェクトを用意してそれをdispatchEventメソッドに渡しているのが実情です。

マス目自動選択(クリック)をエミュレートしている箇所

GAME.board.ev.autoClickがカスタムイベントオブジェクト

GAME.board.unitsEls[selectInd].dispatchEvent(GAME.board.ev.autoClick);

どんな仕事道具を持っているか

initメソッド

/**
 * init
 * ゲームボードの準備をする
 */
init: function() {
  // ゲームボードの状態をリセットする
  this.reset();

  // ゲームボードを作成する
  this.create();
},

ゲームボードの持つ状態と見栄えをプレイ可能な状態にするためのメソッドです。ゲームが(リ)スタートされたときに実行されます。

resetメソッド

/**
 * reset
 * ゲームを始められる状態にする
 */
reset: function() {
  // マス目
  if (this.unitsEls) {
    for (var i = 0, l = this.unitsEls.length; i < l; i++) {
      this.update(this.unitsEls[i], ''); // 選択済みのマス目の色をリセット
    }
  }

  this.selectedNum = []; // 選択済みのマス目リスト
  this.curSelect   = ''; // 最後に選択されたマス目情報
},

ゲームボードの持つ状態と見栄えをリセットするメソッドです。

createメソッド

/**
 * create
 * ゲームボードを作成する
 *
 * @param string UNIT_PREFIX data属性のプレフィックス
 */
create: function() {
  if (this.unitsEls) { return; }

  // 仮の空ノード
  var docfrg = document.createDocumentFragment();

  // マス目をつくる
  for (var i = 0; i < this.allUnitNum; i++) {
    var unit = document.createElement('div'); // マス目要素
    unit.setAttribute(UNIT_PREFIX, i); // data属性セット
    docfrg.appendChild(unit); // マス目を仮の空ノードに追加

    // 列の右端で回り込み解除
    if (0 !== i && 0 === i % this.unitNum) {
      unit.style.clear = 'left';
    }
  }
  
  // マス目をゲームボードに追加
  this.boardEl.appendChild(docfrg);
  // マス目要素
  this.unitsEls = document.querySelectorAll('#js-board > *');

  // マス目
  for (var i = 0, l = this.unitsEls.length; i < l; i++) {
    // マス目が選択されたとき
    this.unitsEls[i].addEventListener('click', this.selected.bind(this), false);
  }
},

ゲームボードのマス目を作成してマス目が選択されたときのイベントリスナーthis.selected.bind(this)を設定するメソッドです。

8行目:マス目のノードリストthis.unitsElsがすでにある場合(リスタートのとき)は何もしません。

16行目:各マス目に独自データ属性でインデックス番号を持たせます。

20〜22行目:何目並べかに応じてマス目を折り返します。

31〜34行目:マス目が選択されたときのイベントリスナーを設定します。

selectedメソッド

/**
 * selected
 * マス目が選択されたときの処理を実行する
 *
 * @param object e イベントオブジェクト
 */
selected: function(e) {
  var unitEl = e.target,
      ind    = parseInt( unitEl.getAttribute(UNIT_PREFIX), 10),
      color;

  // 既に選択されていたら何もしない
  if (this.isSelected(ind)) { return; }

  // 選択されたマス目
  this.curSelect = ind;

  // 選択済みマス目リストに選択されたマス目番号を追加する
  this.add(ind);

  // マス目の表示を更新する
  color = GAME.gameControl.players[GAME.gameControl.curPlayer].color;
  this.update(unitEl, color);

  // ゲーム進行管理に通知
  GAME.gameControl.gameEl.dispatchEvent(GAME.gameControl.ev.selected);
},

マス目が選択されたときの処理を実行するメソッドです。マス目が選択されたときに実行されます。このメソッドはクリックという実動作のとき、オートプレイヤーによるクリックのエミュレートのときに拘わらず実行されます。

13行目:クリックされたマス目が選択済みの場合は何もせず次ターンにも進みません。次ターンに進まないのはここで処理を抜けるためこのメソッド最後にあるゲーム進行管理への通知が行われないからです。

16,19行目:選択されたマス目と選択済みマス目リストに、選択されたマス目番号を追加します。

22〜23行目:選択されたマス目の見栄えをプレイヤーのマス目色に変更します。

26行目:ゲーム進行管理インスタンスオブジェクトにマス目が正しく選択されたことを通知します。

addメソッド

/**
 * add
 * 選択済みマス目リストに選択されたマス目番号を追加する
 *
 * @param number ind 選択されたマス目番号
 */
add: function(ind) {
  this.selectedNum.push(ind);
},

選択済みマス目リストに選択されたマス目番号を追加するメソッドです。this.selectedNumプロパティにマス目番号を入れてるだけです。

isSelectedメソッド

/**
 * isSelected
 * マス目が既に選択されているかどうか
 *
 * @param string ind マス目のインデックス番号
 * @return boolean マス目が既に選択されているか
 */
isSelected: function(ind) {
  return this.selectedNum.indexOf(ind) > -1;
},

マス目が選択済みかどうかチェックするメソッドです。indexOfメソッドで選択済みマス目リストをチェックします。

updateメソッド

/**
 * update
 * マス目の表示を更新する
 *
 * @param object el マス目要素
 * @param string color 色
 */
update: function(el, color) {
  el.style.backgroundColor = color;
},

マス目の表示をプレイヤーのマス目色に更新するメソッドです。要素のstyle プロパティの変更しています。

createAllUnitsArrayメソッド

/**
 * createAllUnitsArray
 * 全マス目リストを作成する
 *
 * @return array 全マス目リスト
 */
createAllUnitsArray: function() {
  var allUnitsArray = [];

  for (var i = 0, l = this.allUnitNum; i < l; i++) {
    allUnitsArray[i] = i;
  }

  return allUnitsArray;
},

ゲームボードのマス目リストを作成するメソッドです。ゲームボードインスタンスオブジェクト生成時に一度だけ実行されます。例えば三目並べのときは1〜9の配列になります。

toggleDisabledメソッド

/**
 * toggleDisabled
 * マス目を選択可・不可にする
 */
toggleDisabled: function() {
  var curPlayer = GAME.gameControl.players[GAME.gameControl.curPlayer],
      auto      = curPlayer.isAuto(),
      display   = '';

  if (auto) {
    display = 'block';
    // コンテンツを作成する
    this.createAutoPlayContent(curPlayer.name + DISABLED_STR.thinking);
  } else {
    display = 'none';
  }

  // 表示変更
  this.disabledEl.style.display = display;
},

オートプレイヤーのときにマス目を選択不可にするメソッドです。ターンが進んだときに実行されます。

6〜7行目:現在のターンのプレイヤー情報を取得します。

10〜16行目:オートプレイヤーの場合には、ゲームボードに透明の要素を被せ、マス目を選択不可にして、「【プレイヤー名】が考え中です…」のコンテンツを作成します。そうでない場合は、透明のレイヤーを非表示にします。

19行目:透明レイヤーの表示を更新します。

createAutoPlayContentメソッド

/**
 * createAutoPlayContent
 * 表示コンテンツを作成する
 * 
 * @param string content 表示内容
 */
createAutoPlayContent: function(content) {
  this.infoEl.innerHTML = content || '';
} 

オートプレイヤーの場合に「【プレイヤー名】が考え中です…」のコンテンツを作成するメソッドです。


お読みいただきありがとうございました!次回はモーダルウィンドウクラスオブジェクトを実装していきたいと思います。

to top