Unityで簡単な2D脱出ゲームを作ってウェブサイトで公開してみよう 〜画像をそろえるパスワード〜

この記事はだいぶ前に書かれたものなので情報が古いかもしれません
画像をそろえるパスワード

この記事を三行にまとめると

フォフォイのフォイだと思います
前回とほぼ同じです
あだち充作品のヒロインくらい似通っている
今回は画像をそろえるパスワードを作ってみましょう。基本的には前回と同じようなことをやるので、前回の動画や記事を見て「おめーのコードは完全に理解した」って人にとっては今日の内容はフォフォイのフォイだと思います。

動画はこちらです。





画像を順番に変える

ではまずは画像を順番に変える処理から。前回で言うところのテキストを順番に変える部分ですね。

必要な変数も前回とほぼ一緒で、順番に変える画像の一覧とボタンのImageコンポーネントをまとめて扱うための配列を用意します。

public class CabinetHigh : MonoBehaviour {
  public Sprite[] flags;
  public Image[] images;
}

「flags」が使用する画像の一覧用の変数で「images」がボタンのコンポーネントを扱うための変数です。

前回のcharsみたいにスクリプトの中だけでflagsに画像を入れることもできなくはないのですが、たぶん画像の場合はインスペクターを使ってドラッグ&ドロップでバーっと画像をセットしちゃった方が楽だと思います。スクリプトでセットする場合は「AssetDatabase」やら「GetAssetPath」やらを使って画像がAssetsのどこにあるかを見に行ったりしなきゃいけないので。

画像を順番に入れ替える処理は前回とほぼ一緒です。

public class CabinetHigh : MonoBehaviour {
  public Sprite[] flags;
  public Image[] images;
  private int[] nows = {2, 0, 3, 1, 0};

  public void ChangeFlag(int n) {
    nows[n] += 1;

    if(nows[n] >= flags.Length) {
      nows[n] = 0;
    }

    images[n].sprite = flags[nows[n]];    
  }
}

引数でn番目のボタンがクリックされたことを判定できるようにしておいて、nows[n]でflagsの何番目の画像をボタンにセットしているかを判定して、nows[n]を+1して次の画像をセットするという処理内容です。images[n]はn番目のボタンのImageコンポーネントです。

前回は文字列の変数に対してLengthを使用して文字数を取得しましたが、配列にもLengthは使用できます。配列の場合は要素数が取得できるので、flagsの中に5枚の画像を入れていたらLengthは5になります。インスペクターのSizeと同じ値になるって覚えておけば大丈夫です。

nowsの初期値を適当に変えていますが、これは最初にボタンをクリックした時に表示される画像をボタンごとに変えるためです。こうすればちょっとランダムっぽく見えます(実際は同じ順番で画像が変更されますが)



正解の判定

正解の判定も前回とほぼ同じです。ただし画像そのものを正解の判定に使うのはちょっと大変かもしれないので、今回はnowsの値を正解判定に使います。

public class CabinetHigh : MonoBehaviour {
  public Sprite[] flags;
  public Image[] images;
  private int[] nows = {2, 0, 3, 1, 0};

  public void CheckAnswer() {
    string answer = "";
    foreach(int now in nows) {
      answer += now.ToString();
    }

    if(answer == "01234") {
      //パスワード解除成功
    }
  }
}

nowsには各ボタンの画像がflagsの何番目の画像かという情報が入っているわけですが、例えば0番目のボタン(Button1)の正解の画像がflagsの0番目の場合、nows[0]は0なら正しい画像がセットされた状態ということになります。1番目のボタン(Button2)の正解画像がflagsの1番目ならnows[1]の値が1になっていれば正しい。他も同様です。

ということは、全部のボタンに正しい画像がセットされていればnowsのそれぞれの値も正しい数字が入った状態になっているので、nowsの数字を連結して一つの文字列を作れば正解の判定ができることになります。

そこでanswer変数にnowsの数字を順番に連結していって、それが正解の文字列と一致していれば解除成功という処理を行なっています。

ここで気をつけたいのは、nowsの中身はint型の数字なので、そのまま足してしまうと通常の足し算になってしまいます。今回は文字の連結を行いたいので、ToStringを使って数字をstring型の文字に変換しています。

本作では画像のパスワードを二箇所に設置していますが、flagsとやimagesの中身とnowsの値が違うだけであとは同じ処理です。flagsやimagesはインスペクターで中身をセットするので、スクリプトの中で違うのはnowsの初期値と正解の文字列だけということになります。

つまりコードの内容としてはあだち充作品のヒロインくらい似通っているので、こういう時はクラスの継承を使うのが良いですね。

//親スクリプト
public class Password : MonoBehaviour {
  public Sprite[] flags;
  public Image[] images;
  protected int[] nows;

  public void ChangeFlag() {
    nows[n] += 1;

    if(nows[n] >= flags.Length) {
      nows[n] = 0;
    }

    images[n].sprite = flags[nows[n]];    
  }

  public void CheckAnswer(string right) {
    string answer = "";
    foreach(int now in nows) {
      answer += now.ToString();
    }

    if(answer == right) {
      //パスワード解除成功
    }
  }
}

//キャビネット
public class CabinetHigh : Password {
  void Start() {
    nows = new int[]{2, 0, 3, 1, 0};
  }
}

//ボックス
public class Box : Password {
  void Start() {
    nows = new int[]{3, 2, 4, 0};
  }
}

こんな感じですね。それぞれの子供たちのStart関数でnowsの初期値を入れて、あとの処理は親に任せました。正解の文字列はrightという引数を作ってインスペクターでセットできるようにしています。ChangeFlagのif文のところもLengthにしといたおかげで共通化に困らずに済みました。あとnows変数のスコープがprivateだと子供側で初期値をセットできないのでprotectedに変更しています。

こうすれば前回みたいにlocked変数を作って解除した後はパスワード画面を出さないようにする処理も親スクリプトに書けば両方に一挙に適用できるので楽ですね。



nowsの値に関する注意点

これは動画の方では説明が漏れてしまってるんですが……というか僕も後から気づいたんですけど、nowsの値について一点だけ注意しておかなきゃいけないことがあります。

僕の書いたコードだとnowsの初期値が0の場合、それは初期値の0なのか0番目の画像を選択した状態なのかが区別できません。つまり正解が0番目のところの初期値が0だと、画像を何も選択しなくてもスクリプトは正解だと判断しちゃうことになります。正確に言うと0以外でも初期値と正解の値が同じ場合は同様の現象が起こりえます。本作は初期値を適当に変えて初期値と正解の値が全て一致しない状態になっているので正しい画像を選択しないと正解できないようになっていますが、初期値と正解の値が一致してしまう場合は注意が必要です。

本作のように適当に初期値を変えてしまうのも一つの手なのですが、仕様的にそれが厳しい場合はゲーム中に選択されることのない値を初期値にしておくなどの対応がお手軽ですかね。例えば配列の要素数(Length)以上の値にしておけば絶対に一度はボタンを押さないと正解になりません。Length以上の値ならどんな数でも一度目のクリックでnowsの値は0になるので、プレイ中に値がおかしくなることはないです。






こんなとこですね。キャビネットとボックスの違いとしては、ボックスは椅子を設置した後じゃないと扉に手が届かないという条件があるんですが、それはいつものごとく椅子のアクティブ状態を判定して扉を開くようにするってだけなので、動画の方では一応紹介してますがここでやる必要はないでしょう。過去の記事を読んでくれた方ならもはやそんなことは説明不要なレベルに達しているはずだから大丈夫だ。決して肩こりが悪化して今日はもうこれ以上書けないみたいなことではない。

次はオブジェクトの角度や色を使ったパスワードを実装します……と言いたいところですが、オブジェクトの角度を変える方法はまだ本シリーズではやっていないので、一度その話を挟みます。なので次回はオブジェクトの回転に関する内容になります。

それじゃあ次回もよろしくお願いしーもんきー。



本シリーズの記事の一覧はこちら
Unityで簡単な2D脱出ゲームを作ってウェブサイトで公開してみよう 〜エピローグ〜
 もしかしたら何か関連しているかも? 
 質問や感想などお気軽にコメントしてください