ReactApps

2019年4月7日

5x5のボードでコマを動かす。

vmmfy0q3n

はじめに

ローカル環境でこのサンプルを動かすには以下の手順に従ってください。

$ git close git@github.com:reiwa/reactapps.git
$ cd reactapps
$ yarn
$ yarn workspace square start

※ $の部分はペーストしないでください。

内容

チェスやオセロのようなボードをつくります。
キーボードの十字キーを操作するとボード内のグレーのマスを動かせます。ボードゲームを開発するヒントになるかも。

コード

import React, { FunctionComponent, useEffect, useState } from 'react'

const App: FunctionComponent = () => {
  const [[x, y], setPosition] = useState([0, 0])

  useEffect(() => {
    const [KEY_LEFT, KEY_UP, KEY_RIGHT, KEY_DOWN] = [37, 38, 39, 40]
    const listener = (event: any) => {
      if (event.keyCode === KEY_LEFT && 0 < x && x < 5) {
        setPosition([x - 1, y])
      } else if (event.keyCode === KEY_UP && 0 < y && y < 5) {
        setPosition([x, y - 1])
      } else if (event.keyCode === KEY_RIGHT && -1 < x && x < 4) {
        setPosition([x + 1, y])
      } else if (event.keyCode === KEY_DOWN && -1 < y && y < 4) {
        setPosition([x, y + 1])
      }
    }
    document.addEventListener('keydown', listener)
    return () => {
      document.removeEventListener('keydown', listener)
    }
  }, [x, y])

  return (
    <table>
      <tbody>
        {createSquares().map((numbers, i) => (
          <tr key={i}>
            {numbers.map((j) => (
              <td
                key={j}
                style={{ background: y === i && x === j ? 'gray' : 'white' }}
              >
                {`${i}${j}`}
              </td>
            ))}
          </tr>
        ))}
      </tbody>
    </table>
  )
}

const createSquares = () => {
  return new Array(5).fill(null).map(() => [0, 1, 2, 3, 4])
}

export default App

いくつかポイント

このコンポーネントはボード内の位置を状態として持ちます。

const [[x, y], setPosition] = useState([0, 0])

この関数は、5x5のボードを作る為の5x5の二次元配列を返します。

const createSquares = () => {
  return new Array(5).fill(null).map(() => [0, 1, 2, 3, 4])
}

ボードはCSSを使わない為にtableで表現しています。また、現在のマスの位置では背景色がグレーになるようにしています。

return (
  <table>
    <tbody>
      {createSquares().map((numbers, i) => (
        <tr key={i}>
          {numbers.map(j => (
            <td
              key={j}
              style={{ background: y === i && x === j ? 'gray' : 'white' }}
            >
              {`${i}${j}`}
            </td>
          ))}
        </tr>
      ))}
    </tbody>
  </table>
)

addEventListener関数を用いてキーバインドを設定しています。十字キー操作されボード内にある場合は現在の位置を更新します。一回のキー操作で二回以上呼び出されないように変数が変わるごとにremoveEventListener関数を呼び出しています。

useEffect(() => {
  const [KEY_LEFT, KEY_UP, KEY_RIGHT, KEY_DOWN] = [37, 38, 39, 40]
  const listener = (event: any) => {
    if (event.keyCode === KEY_LEFT && 0 < x && x < 5) {
      setPosition([x - 1, y])
    } else if (event.keyCode === KEY_UP && 0 < y && y < 5) {
      setPosition([x, y - 1])
    } else if (event.keyCode === KEY_RIGHT && -1 < x && x < 4) {
      setPosition([x + 1, y])
    } else if (event.keyCode === KEY_DOWN && -1 < y && y < 4) {
      setPosition([x, y + 1])
    }
  }
  document.addEventListener('keydown', listener)
  return () => {
    document.removeEventListener('keydown', listener)
  }
}, [x, y])