前回、Three.js 備忘録を作ったので忘れないうちにルービックキューブを作ってみることにしました。

HTML部分

最初にHTML部分を示します。

style.css

グローバル変数と定数

グローバル変数と定数を示します。

index.js

ページが読み込まれたときの処理

ページが読み込まれたときにおこなわれる処理を示します。

イベントリスナの追加

ボタンがクリックされたらゲーム開始の処理やキューブの回転処理がおこなわれるようにします。

光源とキューブの追加

光源とキューブの追加する処理を示します。

キューブは立方体の3Dオブジェクトに色がついた板を結合させたものです。平面だと見た目がイマイチなので低い錐台形にしています。これを全部で3×3×3個生成して適切な位置に移動します。

色がついた平面に近い錐台形を生成して立方体の表面に貼り付ける処理を示します。錐台形を生成して回転、平行移動させたあとcubeに追加しています。

cubeをsceneに追加する処理を示します。

cubeが初期位置の上から左から手前から何番目にあるのかを指定すればsceneにおける初期座標が決まります。cubeをその位置に移動させてsceneに追加します。また同じ3Dオブジェクトを配列cubesにも追加しておきます。

ボリューム設定可能に

レンジスライダーでボリューム設定可能にする処理を示します。これは定番の処理です。

ゲーム開始の処理

ゲームを開始するための処理を示します。効果音、消費時間のリセット、スタートボタンの非表示などの処理が終わったら問題をつくります。引数は初期状態からの回転の回数です。

‘front’, ‘back’, ‘left’, ‘right’, ‘top’, ‘bottom’をランダムに組み合わせて回転させるのですが、Easyは3回しか回転させないのであまりに簡単な問題にならないように、最初の3回は同じものが重ならないようにしています。

回転の種類と順番が決まったら実際に回転させます。そしてタイマーのカウントアップを開始します。

キューブの回転

キューブを回転させる処理を示します。

回転させたいキューブをgroupに追加します。そしてgroupごと回転させます。第三引数がtrueの場合、16回の更新で90度回転させます。falseの場合はただちに回転させます(問題生成のときはアニメーションさせる必要がない)。

回転処理が終わったらsceneからgroupを削除しますが、group内の3Dオブジェクトをsceneに追加しなおす処理が必要です。このとき回転による座標のズレの補正もしています。

ゲームクリア時の処理

ゲームクリア判定の処理を示します。

ここでやっているのは各キューブの向きを調べています。初期状態ではキューブは同じ方向を向いています。回転させることでキューブの向きが変わります。すべて揃っているのであればすべてのキューブは同じ方向を向いているはずです。

rotation.xは -π以上π未満です。この値にπを足したものを π / 2 で割り四捨五入すると 0 ~ 3 の整数が得られます(小数点以下X桁の誤差対策)。これを比較することですべてのキューブは同じ方向を向いているかどうかがわかります。

ゲームクリア時の処理を示します。noMeve = trueにしてキューブがこれ以上回転しないようにしたあとsetInterval関数で開始したタイマー処理を停止させたあと、効果音の再生、スタートボタンの再表示などの処理をおこなっています。