JSでオセロ盤表示

Canvasタグでオセロ盤表示
JSとCanvasタグを利用してオセロ盤の表示を行います。
最近はJSでゲームを作る場合enchant.jsやtmlib.jsなどといったフレームワーク
充実しているようだが基礎を大切にしたいのでまずは素のJSで作ってみようと思う。

○作成に当たって
 jsでの開発用環境としてBracketsを利用することにした。まだあまり
使い慣れていないが補間の能力がすごく優れていた。それからライブプレビューで編集結果の
リアルタイム反映でデザイン調整には便利な機能に力を入れている。
 またNode.jsが標準で同梱されているなど、jsでの開発を行う人にはとってもお勧めできそうな気がする。

○まずは、canvasタグ
 オセロ盤の表示にはhtml5Canvasタグを使う。Html5を使う場合ブラウザにもそのことを明示
 的に伝えることが推奨であるので、気にするのであればドキュメントタイプは
 で指定する。
 それから以下のようにcanvasタグをどっかに記述しておく。

 <canvas id="otthelo_canvas"></canvas>

 中身なしのcanvasタグだけを用意しておいて画面初期化時にJSでオセロ盤描画の処理を行う。

○次に、canvasタグの基本の確認
 ・コンテキストの取得
 JSを使ったcanvasへの描画には、canvasタグエレメントのコンテキストを使って行う。
 サンプルのようにidが"otthelo_canvas"のcanvasタグがあったなら、以下のようにして
 canvasタグのコンテキストを取得できる。

 var canvasElement = document.getElementById("otthelo_canvas");
 var ottheloContext = canvasElement.getContext('2d');

 これでcanvasタグへの描画を行うためのコンテキストが取得できた。あくまでcanvasタグ内の描画
 になるので、大きく表示する場合はタグのwidth, heightの調節が必要になる。
 それから、getContext('2d')で2Dとなっているので取得できるコンテキストが使用できるメソッド
 は主に2D向けのものになっている。

 ・まずは線を引いてみよう
 contextを取得した後に線を引く場合は、以下のようにする。

 ottheloContext.beginPath();
 ottheloContext.moveTo( x座標始点, y座標始点);
 ottheloContext.lineTo( x座標終点, y座標終点);
 this.boardContext.strokeStyle = "#000";
 this.boardContext.stroke();

 これで( x座標始点, y座標始点)から( x座標終点, y座標終点)へstrokeStyleで指定した黒線を1本引くことができる。
 ちなみに以下のようにlineToの後にlineToを重ねるとどうなるかというと( x座標途中, y座標途中)でつながった2本
 の線を引くことができる。

 ottheloContext.beginPath();
 ottheloContext.moveTo( x座標始点, y座標始点);
 ottheloContext.lineTo( x座標途中, y座標途中);
 ottheloContext.lineTo( x座標終点, y座標終点);
 this.boardContext.strokeStyle = "#000";
 this.boardContext.stroke();

 離れた線を複数書きたい場合はlineToの後にmoveToをするか、lineTo後のstroke後にbeginPathをしなければ行けない。

 ・次に曲線を描く
 それから曲線を描きたいなら以下のようにする。

 ottheloContext.beginPath();
 ottheloContext.strokeStyle = "#000";
 ottheloContext.arc(x座標, y座標, 半径, 書き込み開始角度, 書き込み終了角度, false);
 ottheloContext.storke();

 これで(x座標, y座標)を中心とした半径の円の書き込み開始角度から書き込み終了角度までが
 表示される。最後の引数は円を書く向きでありfalseを指定すると時計回りで描画してくれる。
 (20, 30)を中心とする半径5の円を書く場合は以下のようになる。

 ottheloContext.arc(20, 30, 5, 0, Math.PI*2, false);

 また、円の塗りつぶしを行う場合はstrokeではなくfillを使い、塗りつぶしの色はfillStyleで指定
 する。
 例をあげると以下のようになる。

 ottheloContext.beginPath();
 ottheloContext.fillStyle = "#000";
 ottheloContext.arc(x座標, y座標, 半径, 書き込み開始角度, 書き込み終了角度, false);
 ottheloContext.fill();

○オセロ盤を描画してみる
 canvasタグの基本がわかったのでオセロ盤を書いてみる。
 オセロ盤表示を行うためのオブジェクトはここ説明した方法を使う。
 オセロ盤表示のためにはオセロのマス数(縦、横)とマスの高さ、幅を
 決める。それからオセロ盤のpaddingも決めておく。まとめると以下のような
 オブジェクトになる。

var Board = Object.subClass({
	boardContext: '',
	collNum: 8,
	rowNum: 8,
	cellWidth: 50,
	cellHeight: 50,
    paddingColl: 20,
    paddingRow: 30,
    boardWidth: 400,
    boardHeight: 400,
    init: function(canvasTag, collNum, rowNum){
        this.boardContext = canvasTag.getContext("2d");
        this.collNum = collNum;
        this.rowNum = rowNum;
        this.boardWidth = this.collNum * this.cellWidth;
        this.boardHeight = this.rowNum * this.cellHeight;
    }
});

 boardオブジェクトの生成時にオセロ盤の幅と高さも求めている。

 それから、オセロ盤表示のためのメソッドも含めると以下のようになる。

var Board = Object.subClass({
	boardContext: '',
	collNum: 8,
	rowNum: 8,
	cellWidth: 50,
	cellHeight: 50,
    paddingColl: 20,
    paddingRow: 30,
    boardWidth: 400,
    boardHeight: 400,
    init: function(canvasTag, collNum, rowNum){
        this.boardContext = canvasTag.getContext("2d");
        this.collNum = collNum;
        this.rowNum = rowNum;
        this.boardWidth = this.collNum * this.cellWidth;
        this.boardHeight = this.rowNum * this.cellHeight;
    },
    boardTotalWidth: function(){
        return this.boardWidth + this.paddingColl * 2;  
    },
    boardTotalHeight: function(){
        return this.boardHeight + this.paddingRow * 2;
    },
    show: function(){
        this.boardContext.beginPath();
	//塗りつぶし
        this.boardContext.fillStyle = "rgb(34, 128, 31)";
        this.boardContext.fillRect(0, 0, this.boardTotalWidth(), this.boardTotalHeight());
            //縦線
	    for (var i = 0, x = this.paddingColl; i <= this.rowNum; i++, x += this.cellWidth) {
			this.boardContext.moveTo( x, this.paddingRow);
			this.boardContext.lineTo( x, this.boardHeight + this.paddingRow);
	    }
	    //横線
	    for (var j = 0, y = this.paddingRow; j <= this.rowNum; j++, y += this.cellHeight) {
			this.boardContext.moveTo(this.paddingColl,  y);
			this.boardContext.lineTo(this.boardWidth + this.paddingColl,  y);
	    }
	    this.boardContext.strokeStyle = "#000";
	    this.boardContext.stroke();
        
        this.boardContext.beginPath();
        this.boardContext.fillStyle = "#000";
        this.boardContext.arc(this.paddingColl + this.cellWidth * 2,
		 this.paddingRow + this.cellHeight * 2, 5, 0, Math.PI*2, false);
        this.boardContext.moveTo(this.paddingColl + this.cellWidth * 6,
		 this.paddingRow + this.cellHeight * 2);
        this.boardContext.arc(this.paddingColl + this.cellWidth * 6,
		 this.paddingRow + this.cellHeight * 2, 5, 0, Math.PI*2, false);
        this.boardContext.moveTo(this.paddingColl + this.cellWidth * 2, 
		this.paddingRow + this.cellHeight * 6);
        this.boardContext.arc(this.paddingColl + this.cellWidth * 2, 
		this.paddingRow + this.cellHeight * 6, 5, 0, Math.PI*2, false);
        this.boardContext.moveTo(this.paddingColl + this.cellWidth * 6, 
		this.paddingRow + this.cellHeight * 6);
        this.boardContext.arc(this.paddingColl + this.cellWidth * 6, 
		this.paddingRow + this.cellHeight * 6, 5, 0, Math.PI*2, false);
        this.boardContext.fill();
    }
});

 まあ、データに従ってそのままオセロ盤の表示を行っているだけである。
  また、駒の表示などもオセロ盤に依存することになるのでコマ表示メソッドもboardオブジェクトに持たせるようにしようと思う。
 以下の方法では、2次元配列でコマの情報を表しており、1なら白,2なら黒と扱うようにして表示を行うようにしている。

  showPieces: function(pieces){
        for(var i = 0; i < pieces.length; i++){
            for(var j = 0; j < pieces.length; j++){
                if(pieces[i][j] != 0){
                    this.showPiece(i, j, pieces[i][j]);
                }
            }
        }
   },
  showPiece: function(col, row, piece, alpha){
        this.boardContext.beginPath();
        this.boardContext.globalAlpha = alpha;
        if(piece == 1){
            this.boardContext.fillStyle = "#000";
        }else{
            this.boardContext.fillStyle = "#fff";
        }
        this.boardContext.arc(this.paddingColl + this.cellWidth/2 + this.cellWidth * col,
                               this.paddingRow + this.cellHeight/2 + this.cellHeight * row,
                              20, 0, Math.PI*2, false);
        this.boardContext.fill();
        this.boardContext.globalAlpha = 1;
    },