Unity&C言語の初心者がUnity上でのルービックキューブ再現に挑戦してみたというお話の第四弾です。今回は、キューブを一面ずつ回転させることにチャレンジしました。
今回キューブを一面ずつ回転させるに当たり、キューブの立方体の作り方を少し変更しましたので、そこから解説していきます。
Contents
キューブの立方体の作り方の見直し
経緯
当初、Quad(平面)を6枚使ってキューブの立方体を作成していました。
ルービックキューブの立方体は、各面の色が異なります。Unityで作成したCube(立方体)では、各面の色分けが結構面倒です。このような経緯があり、一端、Quad(平面)を6枚使ってキューブの立方体を作成するやり方に落ち着きました。
ところで、Quad(平面)を6枚使って作成した立方体は、あくまで平面の集合体ですので、立方体の内部は空っぽの状態です。キューブを一面ずつ回すチャレンジを進めるに当たり、中身が空っぽというところが非常に都合が悪かったので、立方体の作り方を見直すことにしました。
見直し後の立方体の作り方
Unityで作成したCube(立方体)と、色分けしたQuad(平面)を、一つのゲームオブジェクトにまとめて管理する方法に変更しました。こうすれば、立方体の中身は空っぽにならず、立方体の各面に自由に色づけできます。気づいてみると大して難しい方法ではありませんでしたが、Unity初心者の僕にはこの発想まで思い至らなかったということで、少し反省しています。
イメージ図を貼り付けておきます。
ルービックキューブ一面の回転方法
今回採用したやり方
まず、立方体と同じ空間にSphere(球体)を27個設置しました。そして、以下の流れで、ルービックキューブ一面を回転させることにしました。
① 回転させたい一面にあるSphere(球体)と選ぶ
② ①のSphere(球体)と干渉しているゲームオブジェクトを取得
③ ②で取得したゲームオブジェクトを回転移動させる
CubeとSphereにRigidbodyを付与
まず、CubeとSphereの間で干渉チェックを行うために、それぞれにRigidbodyを付与しました。また、Rigidbodyのuse gravityについてはチェックを外し、is Kinematicについてはチェックを入れました。
それから、SphereのSphere ColliderのIs triggerについては、チェックマークを入れました。
Sphereに干渉オブジェクト名を取得するスクリプトを追加
27個全てのキューブに、干渉オブジェクト名を取得するためのスクリプトを追加しました。
using System.Collections; using System.Collections.Generic; using UnityEngine; public class ConfirmTargetCube: MonoBehaviour { public string ObjectName; void OnTriggerStay(Collider collision) { ObjectName = collision.transform.parent.gameObject.name; Debug.Log(ObjectName); } }
ボタンを設置
マウスのクリックでキューブを操作したかったので、ボタンを設置することにしました。もっとコンパクトにプログラムできるのかもしれませんが、UnityもC言語も初心者なので以下の長文プログラムで試してみました。
対象1~9、XMove~ZMove、Speedなどは、Unity内でゲームオブジェクトをアタッチしたり、直接値を入力したりして対応しました。
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Rotation : MonoBehaviour { public GameObject 対象1; public GameObject 対象2; public GameObject 対象3; public GameObject 対象4; public GameObject 対象5; public GameObject 対象6; public GameObject 対象7; public GameObject 対象8; public GameObject 対象9; public GameObject obj01; public GameObject obj02; public GameObject obj03; public GameObject obj04; public GameObject obj05; public GameObject obj06; public GameObject obj07; public GameObject obj08; public GameObject obj09; string ObjLeft1; string ObjLeft2; string ObjLeft3; string ObjLeft4; string ObjLeft5; string ObjLeft6; string ObjLeft7; string ObjLeft8; string ObjLeft9; public int XMove; public int YMove; public int ZMove; public int Speed; public int Count; public bool RotationCheck=false; // Start is called before the first frame update public void OnClick() { if (RotationCheck == false) { RotationCheck = true; StartCoroutine("Delay"); } } IEnumerator Delay() { ObjLeft1 = 対象1.GetComponent<ConfirmTargetCube>().ObjectName; ObjLeft2 = 対象2.GetComponent<ConfirmTargetCube>().ObjectName; ObjLeft3 = 対象3.GetComponent<ConfirmTargetCube>().ObjectName; ObjLeft4 = 対象4.GetComponent<ConfirmTargetCube>().ObjectName; ObjLeft5 = 対象5.GetComponent<ConfirmTargetCube>().ObjectName; ObjLeft6 = 対象6.GetComponent<ConfirmTargetCube>().ObjectName; ObjLeft7 = 対象7.GetComponent<ConfirmTargetCube>().ObjectName; ObjLeft8 = 対象8.GetComponent<ConfirmTargetCube>().ObjectName; ObjLeft9 = 対象9.GetComponent<ConfirmTargetCube>().ObjectName; obj01 = GameObject.Find(ObjLeft1); obj02 = GameObject.Find(ObjLeft2); obj03 = GameObject.Find(ObjLeft3); obj04 = GameObject.Find(ObjLeft4); obj05 = GameObject.Find(ObjLeft5); obj06 = GameObject.Find(ObjLeft6); obj07 = GameObject.Find(ObjLeft7); obj08 = GameObject.Find(ObjLeft8); obj09 = GameObject.Find(ObjLeft9); Count = 90 / Speed; for (int i = 0; i <Count; i++) { yield return new WaitForSeconds(0.001f); obj01.transform.RotateAround(new Vector3(0.0f, 0.0f, 0.0f), new Vector3(XMove, YMove, ZMove), Speed); obj02.transform.RotateAround(new Vector3(0.0f, 0.0f, 0.0f), new Vector3(XMove, YMove, ZMove), Speed); obj03.transform.RotateAround(new Vector3(0.0f, 0.0f, 0.0f), new Vector3(XMove, YMove, ZMove), Speed); obj04.transform.RotateAround(new Vector3(0.0f, 0.0f, 0.0f), new Vector3(XMove, YMove, ZMove), Speed); obj05.transform.RotateAround(new Vector3(0.0f, 0.0f, 0.0f), new Vector3(XMove, YMove, ZMove), Speed); obj06.transform.RotateAround(new Vector3(0.0f, 0.0f, 0.0f), new Vector3(XMove, YMove, ZMove), Speed); obj07.transform.RotateAround(new Vector3(0.0f, 0.0f, 0.0f), new Vector3(XMove, YMove, ZMove), Speed); obj08.transform.RotateAround(new Vector3(0.0f, 0.0f, 0.0f), new Vector3(XMove, YMove, ZMove), Speed); obj09.transform.RotateAround(new Vector3(0.0f, 0.0f, 0.0f), new Vector3(XMove, YMove, ZMove), Speed); } RotationCheck = false; } }
最終的な動作確認
最終的に、ルービックキューブを一面ずつ回転させるという目標を達成することができました。ルービックキューブをUnity上で再現することに挑戦してきたので、このあたりで概ね目標を達成できました。
自動的にシャッフルして、完成までの時間を表示して・・・というようなゲームらしさは求めていなかったので、この先続けるかどうかは気分次第です。