脱出ゲームでよくあるオブジェクトの位置を交換するギミックを作ってみました。
まずはペットボトルのクラスを作り列挙型COLORで色を管理することにしました。
public class Petbottle : MonoBehaviour { public enum COLOR { BLACK, BLUE, RED, GREEN, WHITE, YELLOW }; public COLOR color; public void onClickThis() { SwitchObj.instance.onClickPetbottle(color, gameObject.transform); } }
このように列挙型enumを使ってペットボトルの色を判定できるようにしています。
次にペットボトルがクリックされた時の処理をSwitchObjクラスに実装していきます。
使用する変数は以下のとおりです。
using System.Linq; using UnityEngine; using UnityEngine.Events; public class SwitchObj : MonoBehaviour { //クリック数をカウントする int clickcnt; //オブジェクトの位置を管理する配列 [SerializeField] Transform[] trans; //他から呼び出せるようにするためのインスタンス static public SwitchObj instance; //ゲーム中のペットボトルの位置を保存する配列 public Petbottle.COLOR[] input; //ペットボトルの並びの正解 public Petbottle.COLOR[] correct; //配列の添字 int index1, index2; //正解時に発生するイベント public UnityEvent someEvent;
input,correct,someEventはpublicにしておくことでUnityエディタ上で設定することができます。
フレキシブルにデフォルトのペットボトルの配置を変えたり、正解順序を変えたり、正解時に発生するイベントを設定できるので便利です。
次に大事なクリック時の処理を実装します。
仕組みとしては以下の通り。
- クリックされたらオブジェクトの位置を保存する
- クリックが2回目だったら位置を交換する
コードを見ていきましょう。
public void onClickPetbottle(Petbottle.COLOR color,Transform transform) { //クリックされたらオブジェクトの位置を保存 //2回目のクリックでスワップする if(clickcnt == 0) { trans[0] = transform; index1 = Array.IndexOf(input, color); clickcnt++; }else if(clickcnt == 1) { trans[1] = transform; index2 = Array.IndexOf(input, color); // オブジェクトの位置を交換する SwapObj(); // 配列の位置を交換する SwapArray(); //正解かチェックする if (input.SequenceEqual(correct)) { //正解だったら何かしらのイベントを発生させる someEvent.Invoke(); } clickcnt = 0; } }
正解をチェックする時にはSequenceEqualを使っています。
これはデフォルトでは使えないので`using System.Linq;`を忘れないようにしましょう。
またクリックされたペットボトルの順番を検索するために`Array.IndexOf`を使って配列の添字を検索しています。
ペットボトルの位置が左から1番目だったら0、2番目だったら1、、、というようにインデックスで順番を覚えておきます。
これは後で色のスワップをする時に必要な情報となります。
スワップする時には、オブジェクトの位置をスワップする関数と色をスワップする2つがあります。
それぞれの処理は以下の通りです。
void SwapObj() { // オブジェクトの位置関係をスワップする Vector3 tmp = new Vector3(trans[0].position.x, trans[0].position.y, trans[0].position.z); trans[0].position = trans[1].position; trans[1].position = tmp; } public void SwapArray() { // 色をスワップする var tmp = input[index1]; input[index1] = input[index2]; input[index2] = tmp; }
一度変数の中身を退避してからスワップするようにしています。
配列やインデックスをグローバルに宣言しているので関数に引数を持たなくて良いのです。
おわり。