Unityでルービックキューブ

Unity初心者✕ルービックキューブ#004 キューブを一面ずつ回転させる

Unity&C言語の初心者がUnity上でのルービックキューブ再現に挑戦してみたというお話の第四弾です。今回は、キューブを一面ずつ回転させることにチャレンジしました。

今回キューブを一面ずつ回転させるに当たり、キューブの立方体の作り方を少し変更しましたので、そこから解説していきます。

キューブの立方体の作り方の見直し

経緯

当初、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上で再現することに挑戦してきたので、このあたりで概ね目標を達成できました。
自動的にシャッフルして、完成までの時間を表示して・・・というようなゲームらしさは求めていなかったので、この先続けるかどうかは気分次第です。

Unity初心者✕ルービックキューブ#001 立方体の各面の色分けに悩むUnityどころか、C言語とか、そもそもプログラミングとかもやったことがありません。ですが、前回ルービックキューブの解き方を解説する記事...
Unity初心者✕ルービックキューブ#002 キューブを回転させるUnityどころか、C言語とか、そもそもプログラミングとかもやったことがありません。ですが、前回ルービックキューブの解き方を解説する記事...
Unity初心者✕ルービックキューブ#003 ボタン操作でキューブを90度だけ回転させるUnity&C言語の初心者がUnity上でのルービックキューブ再現に挑戦してみたというお話の第三弾です。 キューブの回転方法 前...