はじめに (対象読者・この記事でわかること)

この記事は、JavaScriptを使ってゲーム開発を行っている方、特にパズルゲームのブロック回転機能を実装中の方を対象としています。この記事を読むことで、一次変換を使ってパズルのブロックを回転させる際に、同じ角度にしか回転しない問題の原因を理解し、正しく回転させるための解決策を実装できるようになります。また、回転処理の基本的な仕組みについても理解を深めることができます。

前提知識

この記事を読み進める上で、以下の知識があるとスムーズです。 - JavaScriptの基本的な知識 - Canvas APIの基本的な使い方 - 行列と一次変換の基本的な概念

一次変換を使ったブロック回転の基本と問題点

パズルゲームにおいて、ブロックを回転させる処理はゲームのプレイ性に直結する重要な機能です。多くの場合、ブロックの回転には一次変換(線形変換)が利用されます。一次変換は、行列を使って座標変換を行う数学的な手法で、回転、拡大縮小、傾きなどの変換を表現できます。

ブロックを回転させる際には、回転行列を使って各頂点の座標を計算します。例えば、90度回転させる場合、以下のような回転行列を使います。

[ cos(90°)  -sin(90°) ]   [ 0  -1 ]
[ sin(90°)   cos(90°) ] = [ 1   0 ]

この行列を使ってブロックの各頂点の座標を計算することで、ブロック全体が回転したように見せることができます。

しかし、実際に一次変換を使ってブロックを回転させようとすると、ブロックが同じ角度にしか回転しないという問題に遭遇することがあります。これは、主に以下の原因が考えられます。

  1. 回転角度の固定: 回転処理を実装する際に、回転角度が固定されてしまっている。例えば、90度回転させる処理しか実装されておらず、45度や180度などの他の角度に回転させることができない。

  2. 座標系の誤解: JavaScriptのCanvas APIでは、座標系の原点が左上隅にあり、Y軸が下向きになっています。この座標系を理解せずに回転行列を適用すると、期待通りの回転結果が得られない。

  3. 回転中心の指定不足: 回転行列は、原点(0,0)を中心に回転させます。しかし、ゲームのブロックは通常、ブロックの中心を回転中心としたい場合があります。回転中心を指定していないと、ブロックが意図しない位置に移動してしまいます。

  4. 行列の適用順序の誤り: 複数の変換(例:回転と移動)を適用する場合、適用する順序によって結果が異なります。行列の適用順序を誤ると、期待通りの回転結果が得られない。

解決策:正しいブロック回転の実装方法

これらの問題を解決するための具体的な方法を以下に示します。

回転角度の動的指定

回転角度を固定せず、動的に指定できるようにします。例えば、キー入力に応じて回転角度を変更するように実装します。

Javascript
// 回転角度を保持する変数 let rotationAngle = 0; // キー入力に応じて回転角度を変更 document.addEventListener('keydown', (e) => { if (e.key === 'ArrowLeft') { rotationAngle -= 90; // 左回転 } else if (e.key === 'ArrowRight') { rotationAngle += 90; // 右回転 } }); // ブロックを描画する関数 function drawBlock() { // Canvasのクリア ctx.clearRect(0, 0, canvas.width, canvas.height); // ブロックの描画 ctx.save(); // ブロックの中心に座標系を移動 ctx.translate(block.x + block.width / 2, block.y + block.height / 2); // 回転角度を適用 ctx.rotate(rotationAngle * Math.PI / 180); // ブロックを描画(原点を中心に描画) ctx.fillStyle = 'blue'; ctx.fillRect(-block.width / 2, -block.height / 2, block.width, block.height); ctx.restore(); }

座標系の考慮

Canvas APIの座標系(原点が左上、Y軸が下向き)を考慮して回転行列を適用します。例えば、90度回転させる場合、通常の数学的な座標系と異なるため、注意が必要です。

回転中心の指定

回転中心をブロックの中心に設定するために、translateメソッドを使って座標系を移動します。上記のコード例では、ctx.translate(block.x + block.width / 2, block.y + block.height / 2)でブロックの中心に座標系を移動しています。

行列の適用順序の正しい指定

複数の変換を適用する場合、適用する順序を正しく指定します。一般的には、1) 移動、2) 回転、3) 拡大縮小、4) 傾き、という順序で適用します。上記のコード例では、translateで移動した後にrotateで回転を適用しています。

ハマった点やエラー解決

実際の開発では、以下のような問題に遭遇することがあります。

問題1: ブロックが回転しても位置がずれる 原因: 回転中心を指定していないため、原点(0,0)を中心に回転してしまう。 解決策: translateメソッドを使ってブロックの中心に座標系を移動する。

問題2: 回転方向が逆になる 原因: Canvas APIの座標系(Y軸が下向き)を考慮していない。 解決策: 回転角度に負の値を指定するか、回転行列の符号を反転させる。

問題3: 複数の回転操作で意図しない角度に回転する 原因: 累積した回転角度を適用しているため。 解決策: 毎回初期状態から回転角度を計算するか、回転角度をリセットする処理を追加する。

まとめ

本記事では、JavaScriptで一次変換を使ってパズルのブロックを回転させる際に、同じ角度にしか回転しない問題の原因と解決法について解説しました。

  • 回転角度の固定を解決するには、回転角度を動的に指定する必要がある
  • 座標系の誤解を解決するには、Canvas APIの座標系を理解し、適切に回転行列を適用する必要がある
  • 回転中心の指定不足を解決するには、translateメソッドを使って座標系を移動する必要がある
  • 行列の適用順序の誤りを解決するには、適用する順序を正しく指定する必要がある

この記事を通して、JavaScriptを使ったパズルブロックの回転処理に関する理解を深めることができたかと思います。今後は、回転アニメーションの滑らかさを向上させる方法や、複数のブロックを同時に回転させる方法についても記事にする予定です。

参考資料