作成したゲーム
四次元の回転をテーマにした迷路ゲームを作りました。
ステージを回転させることで、ステージの形状を変え、プレイヤーをゴールまで導くというルールです。
画面下部は、プレイヤーやゴールのxyz空間上の位置や、ステージの形状を示し、実際にプレイヤーが動き回るステージになります。
画面上部は、プレイヤーやゴールのxwz空間上の位置を示し、4次元上の位置を確認するマップとなります。
マップをダイヤルのように回転させることで、
w軸上の別の位置にあったブロックが見えるようになります。
道ができ、ゴールまで渡れるようになりました。
システム
ステージの各ブロックは4次元配列によって管理され、配列のindexはブロックの4次元上の位置と同期させています。
配列の各要素のindexに四次元の回転行列を適用し、入れ替えることでステージの回転を実装しています。
また、プレイヤーとゴールの位置にも回転行列を適用し、ステージの回転と同期しています。
四次元の回転行列
\begin{eqnarray}
R_{XY}(\theta)=\begin{pmatrix}
1 & 0 & 0 & 0\\
0 & 1 & 0 & 0\\
0 & 0 & \cos\theta & -\sin\theta\\
0 & 0 & \sin\theta & \cos\theta
\end{pmatrix},
~R_{YZ}(\theta)=\begin{pmatrix}
\cos\theta & 0 & 0 & -\sin\theta\\
0 & 1 & 0 & 0\\
0 & 0 & 1 & 0\\
\sin\theta & 0 & 0 & \cos\theta
\end{pmatrix},
~R_{XZ}(\theta)=\begin{pmatrix}
1 & 0 & 0 & 0\\
0 & \cos\theta & 0 & -\sin\theta\\
0 & 0 & 1 & 0\\
0 & \sin\theta & 0 & \cos\theta
\end{pmatrix},\\
R_{XW}(\theta)=\begin{pmatrix}
1 & 0 & 0 & 0\\
0 & \cos\theta & -\sin\theta & 0\\
0 & \sin\theta & \cos\theta & 0\\
0 & 0 & 0 & 1\\
\end{pmatrix},
~R_{YW}(\theta)=\begin{pmatrix}
\cos\theta & 0 & -\sin\theta & 0\\
0 & 1 & 0 & 0\\
\sin\theta & 0 & \cos\theta & 0\\
0 & 0 & 0 & 1\\
\end{pmatrix},
~R_{ZW}(\theta)=\begin{pmatrix}
\cos\theta & -\sin\theta & 0 & 0\\
\sin\theta & \cos\theta & 0 & 0\\
0 & 0 & 1 & 0\\
0 & 0 & 0 & 1\\
\end{pmatrix}
\end{eqnarray}
四次元の描画
画面上には
プレイヤーのw座標と同じw座標のブロックが表示され、
ステージを回転させることで表示されるブロックが切り替わります。
上記の方法だけでは、表示されるブロックの切り替わりが滑らかではないので、
回転の進み具合に応じてブロックの表示が変わるようにします。
表示するブロックを、
・回転前に表示されていたブロック
・回転後に表示されるブロック
の二種類にすることで大量のオブジェクトを呼び出すことなく、滑らかな四次元の描画を行えます。
この二つは回転前と回転後のプレイヤーとw座標が等しいブロックのように言い換えられ、
回転前に表示されていたブロックはプレイヤーの回転前の座標から求められ、
回転後に表示されるブロックはプレイヤーの回転後の座標から逆算することによって求められます。
// 回転前のブロックのインデックス
Vector4 befBlockIndex = new Vector4(x, y, z, playerPos.w);
// 回転後のブロックのインデックス
Vector4 aftBlockIndex = Rot(-Mathf.PI / 2, new Vector4(x, y, z, aftPlayerPos.w));
ブロックの位置の変化を滑らかにするために、ブロックの位置を時間に応じて変化するようにします。
for(float t = 0.0f; t < 1.0f; t+=s) //sは回転するスピード
{
// 回転前のブロックの位置
Vector4 befBlockPos = Rot(t * Mathf.PI / 2, new Vector4(x, y, z, playerPos.w));
// 回転後のブロックの位置
Vector4 aftBlockPos = Rot((-1 + t) * Mathf.PI / 2, new Vector4(x, y, z, aftPlayerPos.w));
yield return null;
}
また、ブロックのw座標はプレイヤーのw座標との差に応じてブロックのサイズを変化させることで表現しました。
float size = Mathf.Clamp(1 - Mathf.Abs(playerPos.w - blockPos.w), 0, 1);
おわりに
四次元の回転をテーマにした迷路ゲームを作りましたが、ルールの理解までが、ものすごく難しいゲームとなりました。
四次元のステージの管理や、回転の描写などは開発していて面白い部分でしたので共有させていただきました。