HTMLのcanvasでリバーシ（オセロ）ゲームを作る#1

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2729479/d43940ee-03b8-668f-6ad9-98bb3035530b.png)

　Qiita初投稿です。趣味で簡単なゲーム制作をしています。
　なんか記事を書いてみたいなと思ったので、需要があるかわかりませんが、HTMLのcanvasという要素でリバーシ（オセロ）を制作する方法を記事に残したいと思います。至らぬ点も多いかと思いますが、温かい目でご覧ください。あと、飽き性なので細々とやっていきます。

# 目次
- はじめに
- canvasについて
- 準備
- ボードの表示
- まとめ


# はじめに
　HTML5のcanvas要素を使うと、ブラウザ上に図形を自由に描画することができます。今回は、このcanvasを使ってリバーシを作る方法を紹介したいと思います。
　第一回にあたる今回はcanvasの紹介からボードの表示までを書きたいと思います。

# canvasについて
- canvasは以下のようにHTML内に記述します。
```diff_html
<canvas id="canvas" width="400" height="300"></canvas>
```
※ <img&gt;タグなどとは異なり、閉じタグ</canvas&gt;が必要なので、注意してください。
※ width, heightはそれぞれcanvasの「横の長さ」と「縦の長さ」を表しています。

- javascriptでこのcanvasを扱うためには、以下のように記述します。
```diff_javascript
let canvas = document.getElementById("canvas");
let ctx = canvas.getContext("2d");
```

- canvasには長方形、円、直線、多角形など様々な図形を描画することができます。たとえば、
```diff_javascript
ctx.strokeStyle = "black"; // 線の色を黒に
ctx.fillStyle = "green"; // 塗る色を緑に
ctx.rect(10, 20, 150, 200); // 長方形
ctx.fill(); // 塗る
ctx.stroke(); // 線を引く
ctx.beginPath(); // パスをリセット
ctx.moveTo(200, 160); // 直線のはじまり
ctx.lineTo(250, 250); // 直線を引く
ctx.lineTo(350, 230); // 直線を引く
ctx.lineTo(200, 160); // 直線を引く
ctx.fillStyle = "red"; // 塗る色を赤に
ctx.fill(); // 塗る
ctx.stroke(); // 線を引く
ctx.beginPath(); // パスをリセット
ctx.arc(250, 90, 60, 0, Math.PI*2); // 円
ctx.fillStyle = "gray"; // 塗る色をグレーに
ctx.fill(); // 塗る
ctx.stroke(); // 線を引く
```
と書けば、以下のように図形を描くことができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2729479/d3dc9430-8433-50c9-46fd-87cfc38b3c92.png)
- canvasの座標は左上が(0, 0)で、x座標の方向は左→右、y座標の方向は上→下になっています。
- 詳しくは[Canvasリファレンス](http://www.htmq.com/canvas/)を参照してください。

# 準備
　では、さっそくリバーシを作っていきましょう。以下の手順で準備を進めてください。
- 新規フォルダ"reversi"を作成し、中身に"index.html"と"script.js"を用意する。
- index.htmlを以下のように書く。
```index.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Reversi</title>
    <style>
        body {
            background-color: whitesmoke;
        }
        /* 2枚のcanvasを同じ場所に重ねるための設定 */
        .canvas-wrap{
            position: relative;
            padding: 0;
            box-sizing: content-box;
        }
        .canvas_warp:before{
            content:"";
            display: block;
            padding-top: 50%;
        }
        .canvas-wrap > canvas {
            position: absolute;
            left:0;
            top:0;
            border: 0;
            box-sizing: content-box;
            padding: 0;
            margin: 0;
        }
    </style>
</head>
<body>
    <h1>Reversi</h1>
    <div>
        <!-- 黒と白の石の数を表示する-->
        <span id="num"></span>
        <!-- メッセージを表示する-->
        <span id="msg"></span>
        <!-- 「待った」ボタン-->
        <button id="matta_btn" type="button">待った</button>
        <!-- 「はじめから」ボタン-->
        <button id="hajime_btn" type="button">はじめから</button><br>
    </div><br>
    <div class="canvas-wrap">
        <!-- ボードを表示するためのcanvas-->
        <canvas id="canvas1" width="500" height="500"></canvas>
        <!-- 石などを表示するためのcanvas-->
        <canvas id="canvas2" width="500" height="500"></canvas>
    </div>
    <script type="text/javascript" src="script.js"></script>
</body>
</html>
```
※canvasが2つあるのは、リバーシのボード（＝変わらないもの）と石など（＝変化するもの）を分けて描画するためです。canvasにはレイヤー機能がないので、このように複数のcanvasを重ねることによって、レイヤー機能を実現させることができます。

- index.htmlをブラウザで開いてみる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2729479/ed8a66a6-932a-bde8-6146-4ebdc8e06bd0.png)
　まだ、script.jsで何も書いていないので、タイトルと2つのボタンが表示されているだけです。ブラウザと開発者ツールのコンソール画面を確認しながらゲーム制作を進めることおすすめします。

# ボードの表示

　実際にcanvasでリバーシのボードを描画してみたいと思います。
- script.jsの中身を以下のように書いてみてください。

```script.js
const canvas1 = document.getElementById("canvas1");
const canvas2 = document.getElementById("canvas2");
let {width, height} = canvas1; // canvasのwidthとheightを取得
let a = width / 8; // 1マスの一辺の長さ
let bg_color = "seagreen"; // ボードの色

drawBoard(); // ボードの表示

function drawBoard() {
    let ctx = canvas1.getContext("2d"); // canvas1
    ctx.fillStyle = bg_color; // 塗る色をbg_colorに
    ctx.fillRect(0, 0, width, height); // ボードを塗る
    ctx.strokeStyle = "black"; // 線の色を黒に
    for(let i = 0; i <= 8; i++) {
        // i番目の縦線
        ctx.beginPath();
        ctx.moveTo(a*i, 0);
        ctx.lineTo(a*i, height);
        ctx.stroke(); // 線を引く
        // i番目の横線
        ctx.beginPath();
        ctx.moveTo(0, a*i);
        ctx.lineTo(width, a*i);
        ctx.stroke(); // 線を引く
    }
    drawPochi(); // 謎の黒い点
};

function drawPochi() {
    let ctx = canvas1.getContext("2d"); // canvas1
    for(let i = 2; i <= 6; i+=4) {
        for(let j = 2; j <= 6; j+=4) {
            let x = a*j; // x座標
            let y = a*i; // y座標
            let r = a*0.08; // 半径
            ctx.beginPath(); // パスのリセット
            ctx.arc(x, y, r, 0, 2*Math.PI, false); // 小さい円
            ctx.fillStyle = "black"; // 塗る色を黒に
            ctx.fill(); // 塗る
        }
    }
}
```
　ここでやっていることは、背景を緑で塗って、縦線と横線を9本ずつ等間隔に引き、謎の黒い点（小さい円）を4か所描いています。座標は紙とペンで計算するといいかもしれないです。

- index.htmlをブラウザで開いてみましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2729479/de557f38-fad6-e6de-a4cb-a631b76adbdf.png)
リバーシのボードが表示されました！謎の黒い点もしっかり描画されています。

# まとめ
　今回はここまでにしたいと思います。わかりにくい点や間違っている点があればコメントでご指摘ください。近々第二回の記事を書こうと思います。