前回は丸のマスの上にきれいにコマを乗せる処理を実装しました。
smooth-pudding.hatenablog.com
今回はマスに対応する場所にそれぞれクリックイベントを割り当ててみたいと思います。
マスの付近でクリックする
Second Best の手番では以下のいずれかの行動のみができます。
- コマを置く
- コマを動かす
- セカンドベスト宣言
セカンドベスト宣言は別のボタンで表現しているので、コマに対する操作さえ実現できればよいはずです。
第二回で検討したように、これはコマの付近でのクリックで表現しようと思っているので、8箇所にクリックできる領域を用意し、そこをクリックしたら反応するようにしておきたいです。つまり下図の黄色い部分で反応するようにするということです。

位置を特定する
コマの配置位置の計算の際に、丸のマスの中心座標を求める計算を行いました。その部分が流用できそうなので、関数として抜き出しておきます。
const calcPosCenter = (canvasWidth: number, posIndex: number) => { const radiusX = 0.358; const radiusY = radiusX * 0.8; const angle = (-3 * Math.PI / 8) + (Math.PI / 4) * posIndex; const [xBase, yBase] = [ radiusX * Math.cos(angle), radiusY * Math.sin(angle) ]; return { x: xBase * canvasWidth, y: yBase * canvasWidth }; };
これを使うと calcPieceCoordinate は次のように書けます。
const calcPieceCoordinate = (canvas: HTMLCanvasElement, pieceWidth: number, piece: Piece) => { const dh0 = 0.12; // コマの底面の中心に補正する項 const dh = 0.19; // コマの高さ const { x: xBase, y: yBase } = calcPosCenter(canvas.width, piece.posIndex); const relativeX = xBase; const relativeY = yBase - (dh0 + dh * piece.heightIndex) * pieceWidth; const canvasCenterX = canvas.width / 2; const canvasCenterY = canvas.height / 2; return { x: relativeX + canvasCenterX, y: relativeY + canvasCenterY }; };
さらに、四角の位置を計算する以下の関数を用意します。円の中心から測って上側の縁と下側の縁に対応するパラメーター (1.2 と 0.5) を導入しています。
const calcPosRect = (canvasWidth: number, pieceWidth: number, posIndex: number) => { const rectWidth = pieceWidth; const rectTopHeight = pieceWidth * 1.2; const rectBottomHeight = pieceWidth * 0.5; const rectHeight = rectTopHeight + rectBottomHeight; const { x: xBase, y: yBase } = calcPosCenter(canvasWidth, posIndex); return { x: xBase - rectWidth / 2, y: yBase - rectTopHeight, width: rectWidth, height: rectHeight, } };
次に、背景のボードを描画した場所の直後に以下を記述します。
// 各コマの位置に対応する場所に四角を描画
少し待つと、以下の実装が生成されたので、Tab を押して確定します。
for (let posIndex = 0; posIndex < 8; posIndex++) { const { x, y, width, height } = calcPosRect(canvas.width, pieceWidth, posIndex); ctx.fillStyle = 'rgba(0, 0, 0, 0.5)'; ctx.fillRect(x, y, width, height); }
この状態で実行してみると、このようになりました。

何かがおかしいですね。そういえば、calcPosRect の計算では中心座標の調整を忘れていました。修正しましょう。引数から canvas を受け取るように変更します。呼び出し部分も忘れず修正しておきます。
const calcPosRect = (canvas: HTMLCanvasElement, pieceWidth: number, posIndex: number) => { const rectWidth = pieceWidth; const rectTopHeight = pieceWidth * 1.2; const rectBottomHeight = pieceWidth * 0.5; const rectHeight = rectTopHeight + rectBottomHeight; const { x: xBase, y: yBase } = calcPosCenter(canvas.width, posIndex); const canvasCenterX = canvas.width / 2; const canvasCenterY = canvas.height / 2; return { x: xBase - rectWidth / 2 + canvasCenterX, y: yBase - rectTopHeight + canvasCenterY, width: rectWidth, height: rectHeight, } };
実行してみると、無事修正できていました。

パラメーターを調整して (0.5, 1.2) → (0.42, 0.97) とすれば、いい感じのサイズになりました。

クリックイベントを実装変更する
クリック判定したい領域を求められたので、クリック判定の実装にはいります。クリックイベントから受け取ったマウスの座標から、どのマスをクリックしたか判定し、そのマスの上にコマをおけばよさそうです。AIはもう少しざっくり命令でも動いてくれるでしょうから、簡単に命令してみます。
calcPosRect を使って、いずれかの posIndex の四角領域内をクリックすると posIndex のところにコマを置くようにして。領域外の場合は何も変化させないようにして。
すると以下のように編集してくれました。
やや複雑なので、すこしだけ手を加えました。for ループの部分については、選択して Ctrl+K で「シンプルにして」と命令しました。動作確認としてランダムにクリックしてみると、いい感じにコマが積まれました。領域外だとちゃんと変化しませんでした。
領域に四角を描く処理はもう不要なので消しておきます。

すこしリファクタ
ところで、calcPosRect のバグ修正で calcPosRect の中で座標の修正の処理を追加しましたが、よく考えたらマスの中心を計算する calcPosCenter の方で調整したほうが見通しが良さそうです。細々と変更するのが面倒くさいので、AIに丸投げしてみます。
calcPosCenter, calcPieceCoordinate, calcPosRect を選択した上で Ctrl+K を押し、以下を命令しました。
calcPosCenter は canvs: HTMLCanvasElement を受け取るようにし、canvasCenterX, canvasCenterY の補正を行ったあとの値を返すようにして
すると以下のように編集してくれました。
若干変数名の付け方が好みと違うので、すこし書き換えます。これですこしスッキリしました。第六回まとめ
今回は8つのマスのあたりにクリックで反応する領域を作りました。「このマスの上に置く」「このマスからこのマスに移動させる」といった指定をするための下準備が整いました。
今回実装した内容は v6-click-rect というタグを貼り付けて push してあります。
github.com
次回は、プレイヤーが操作を行う助けになるような簡単な装飾を行いたいと思います。
ではまた。