絶対に完成させるゲーム制作#4|星を集めたら、扉が開く

生け垣の迷路で、スライムちゃんが星を1つずつ取っていく。取るたびにキラキラと「+1」が出て、左上の「のこり」の数が3→2→1と減り、最後の星で扉が開いて「扉が ひらいた!」に。開いた扉に入るとエンディングへ

前回は、生け垣の迷路を作って、スライムちゃんが向きを変えながら歩けるようにしました。でも、今のステージは扉に入るだけでクリアなので、迷路を抜ければすぐに終わってしまいます・・・。今回は、いよいよ星を置きます。星を3つ全部集めないと扉が開かないようにして、取ったときにはキラキラと「+1」が出る演出も付けますよ!

目次

今回作るもの

今回のゲームの流れ。「タイトル」から「はじめる」で「ステージ」へ、「扉に入る」で「エンディング」へ、「タイトルへ」でタイトルに戻る。流れは前回と同じで、「ステージ」の中に星・残りの数・扉が開くを足す

ゲームの流れは、今回も同じです。ステージの中に、「星を集める」という目的を足します。

  • ステージに星を3つ置く。星は、その場でふわふわ浮いている
  • 画面の左上に、残りの星の数を出す
  • 星を取ると、キラキラと「+1」が出る
  • 扉は最初は閉じていて、星を全部集めると開く。開いた扉に入るとエンディング

作るスクリプトは3つ、前回までのスクリプトを1つ書きかえます。

スクリプト役割付ける場所
Star取ったら、キラキラと「+1」を出して消える星
StarCounter残りの数を表示する。全部集めたら扉を開く左上の文字
PopupText文字を浮かせながら消す「+1」の文字
Door(#2で作ったもの)星を全部集めるまで開かないようにする扉

星を置こう

Stage1シーンを開いたエディタ。HierarchyにStars(Star1・Star2・Star3)と、Canvasの下にStarText。Gameビューに、生け垣の迷路と星が3つ、左上に星のマークと「のこり 3」、右上に閉じた扉

まずは、星を1つ作って、プレハブにします。

  • Sprites/ItemsのstarをHierarchyにドラッグ&ドロップして、名前をStarにする
  • Scaleを(0.8, 0.8, 1)にする
  • Add ComponentでCircle Collider 2Dを付ける
    • Is Triggerにチェック(ぶつかるのではなく、重なったら取れるように)
    • Radius:0.4
  • Add ComponentでFloating Motionを付ける
    • Height:0.1、Speed:3

Floating Motionは、#1でタイトルの文字をふわふわさせたスクリプトです。Heightは、Canvasの文字ではピクセル(20)でしたが、ステージではマス(1マスが1)なので、0.1にします。作ったスクリプトは、数字を変えるだけで別のものにも使えます。

Star1のInspector。TransformのScaleが0.8, 0.8, 1、Circle Collider 2DのIs Triggerにチェック、Radiusが0.4。Floating MotionのHeightが0.1、Speedが3。StarのSparkle PrefabにStarSparkle、Popup PrefabにPlusOne

Starスクリプトは、あとで作って付けます(上の画像は、全部付け終わった後のものです)。

出来たら、HierarchyのStarをPrefabsフォルダにドラッグしてプレハブにし、Hierarchyのほうは消します。前回の壁と同じように、空のゲームオブジェクトStarsを作って、その子にプレハブを3つ置きます。

名前Position
Star1(-7, 3)
Star2(-1, -3.8)
Star3(5, -3.8)

左の通路の上、まん中の通路の下、右の通路の下に1つずつ。迷路をぐるっと回らないと、全部は取れない置き方です。

全部集めたら扉が開くようにしよう

扉のまわりを3コマ並べたもの。木の扉が閉じている → 最後の星を取った瞬間に、扉のまわりにキラキラが出る → 明かりのついた開いた扉になる

次は、扉を最初は閉じておいて、星を全部集めたら開くようにします。閉じた扉の絵と、開いた扉の絵を入れかえるだけで、「開いた!」が伝わります。

Doorスクリプトを書きかえよう

#2で作ったDoorスクリプトを、次のように書きかえます。

using UnityEngine;

// 扉:星を全部集めると開き、開いた扉にスライムちゃんが入ったら、次のシーンへ
public class Door : MonoBehaviour
{
    [SerializeField] private string nextSceneName = "Ending"; // 入ったら行くシーンの名前
    [SerializeField] private ScreenFlash screenFlash;          // 画面を光らせて、シーンを切り替える
    [SerializeField] private Sprite openSprite;                // 開いた扉の絵
    [SerializeField] private GameObject openEffectPrefab;      // 開いたときのキラキラ

    private bool isOpen;    // 開いているか
    private bool isEntered; // もう入ったか(2回入らないように)

    // 扉を開く(StarCounter が、星を全部集めたときに呼ぶ)
    public void Open()
    {
        isOpen = true;
        GetComponent<SpriteRenderer>().sprite = openSprite;
        Instantiate(openEffectPrefab, transform.position, Quaternion.identity);
    }

    private void OnTriggerStay2D(Collider2D other)
    {
        if (!isOpen || isEntered)
        {
            return;
        }
        PlayerMove player = other.GetComponent<PlayerMove>();
        if (player == null)
        {
            return;
        }
        isEntered = true;
        player.Stop();
        screenFlash.FlashAndLoad(nextSceneName);
    }
}
  • isOpenとOpen()
    • 最初は閉じている(false)。Open()が呼ばれたら開いて、扉の絵をopenSprite(開いた扉)に替え、キラキラを出す
  • OnTriggerStay2D
    • #2では「重なった瞬間」のOnTriggerEnter2Dでしたが、「重なっている間ずっと」のOnTriggerStay2Dに変えました。閉じた扉の前で待っているうちに扉が開いても、ちゃんと入れるようにするためです
  • !isOpen || isEntered
    • 「開いていない」か「もう入った」なら、何もしない。||は「または」

扉のゲームオブジェクト(HierarchyのDoor)を選んで、2か所を変えます。

  • Sprite RendererのSpriteをdoor_closed(閉じた扉)にする
  • DoorスクリプトのOpen Spriteにdoor_openを入れる(Open Effect Prefabは、あとでキラキラを作ってから入れます)
扉のゲームオブジェクト(Door)のInspector。Sprite RendererのSpriteがdoor_closed。DoorスクリプトのOpen Spriteにdoor_open、Open Effect PrefabにStarSparkle

残りの数を表示しよう

画面の左上に、星のマークと「のこり 3」を出します。

  • Canvasを右クリック>UI (Canvas)>Text – TextMeshPro、名前をStarTextにする
    • アンカーを左上(top-left)にして、Pivotを(0, 1)、Pos X:150、Pos Y:-40、Width:600、Height:100
    • Text:「のこり 3」、Font Size:64、太字、色:#FFE08A、左寄せ・上下はまん中
  • StarTextを右クリック>UI (Canvas)>Image、名前をStarIconにする
    • アンカーを左のまん中にして、Pos X:-60、Pos Y:0、Width・Height:96
    • Source Imageにstarを入れる
  • Flashを、Canvasの子の一番下にドラッグし直す(StarTextより手前に光らせるため)

ScriptsフォルダにStarCounterを作ります。

using TMPro;
using UnityEngine;

// 残りの星の数を表示する。全部集めたら扉を開く
public class StarCounter : MonoBehaviour
{
    [SerializeField] private Door door; // 全部集めたら開く扉

    private TMP_Text countText;
    private int remainingStars;

    private void Start()
    {
        countText = GetComponent<TMP_Text>();
        // ステージに置いてある星を数える
        remainingStars = FindObjectsByType<Star>(FindObjectsSortMode.None).Length;
        UpdateText();
    }

    // 星を1つ取ったときに呼ぶ
    public void CollectStar()
    {
        remainingStars--;
        UpdateText();
        if (remainingStars == 0)
        {
            door.Open();
        }
    }

    private void UpdateText()
    {
        if (remainingStars > 0)
        {
            countText.text = $"のこり {remainingStars}";
        }
        else
        {
            countText.text = "扉が ひらいた!";
        }
    }
}
  • FindObjectsByType<Star>(…).Length
    • シーンにあるStarを全部探して、その数を数える。星を増やしたり減らしたりしても、数を書き直さなくてよい
  • CollectStar()
    • 星が取られたら、残りを1つ減らして表示を直す。0になったらdoor.Open()で扉を開く
  • UpdateText()
    • 残りがあれば「のこり 2」、0なら「扉が ひらいた!」。数字だけでなく、何が起きたかも文字で伝えます

UIの文字をスクリプトから変える方法は、9-4 スクリプトからUIを更新しようで紹介しています。

StarCounterの中で使っているStarは、まだ作っていないので、次の節でStarを作るまではエラーになります。StarCounterをStarTextに付けて、Doorの欄に扉のゲームオブジェクト(Door)をドラッグするのは、Starを作ったあとにしましょう。

StarTextのInspector(Starを作って、StarCounterを付けたあとのもの)。Rect Transformのアンカーが左上、Pos Xが150、Pos Yが-40、Widthが600、Heightが100。Star CounterのDoorにDoor

取ったらキラキラと「+1」

星を取る瞬間を3コマ並べたもの。スライムちゃんが星に近づく → 星が消えて、キラキラの粒と「+1」が出る → 粒が広がり、「+1」が上に浮かんで薄くなる

星を取ったときに、何も出ずに消えるだけだと、取れたのかどうか分かりにくいですよね。そこで、キラキラの粒と「+1」の文字を出して、「取った!」をはっきり見せます。

どちらも、星を取るたびに作って、終わったら消すものなので、プレハブにしておきます。

キラキラを作ろう

StarSparkleのプレハブのInspector。Particle SystemのDurationが0.5、Loopingのチェックなし、Start Lifetimeが0.6、Start Speedが4、Start Sizeが0.4と0.8、Start Colorが黄色、Simulation SpaceがWorld

キラキラは、Particle System(パーティクル)で作ります。たくさんの小さな粒を、まとめて飛ばせる仕組みです。

  • Hierarchyで右クリック>Effects>Particle System、名前をStarSparkleにする
  • TransformのPositionとRotationを、どちらも(0, 0, 0)にする
  • Particle Systemのメインの欄(StarSparkleと書かれた欄)
    • Duration:0.5、Looping:チェックを外す
    • Start Lifetime:0.6、Start Speed:4
    • Start Size:右の▼からRandom Between Two Constantsにして、0.4と0.8
    • Start Color:#FFE08A(星と同じ黄色)
    • Simulation Space:World
    • Stop Action:Destroy
  • Emission:Rate over Timeを0にして、Burstsの+で1つ足す(Time:0、Count:20)
  • Shape:ShapeをCircle、Radiusを0.1
  • Size over Lifetimeにチェックを入れて、Sizeを右下がりの線(だんだん小さくなる)にする
  • Texture Sheet Animationにチェックを入れて、ModeをSprites、SpriteにSprites/Effectsのfx_sparkleを入れる
  • RendererのOrder in Layer:5(スライムちゃんより手前)

出来たら、Prefabsフォルダにドラッグしてプレハブにし、Hierarchyのほうは消します。扉のゲームオブジェクト(Door)のDoorスクリプトのOpen Effect Prefabにも、このStarSparkleを入れておきましょう。扉が開くときにも、同じキラキラを使い回します。

Burstは「一度にまとめて出す」設定です。Rate over Timeを0にして、Burstで20個出すと、ポンッと一度だけはじけるキラキラになります。Stop Action:Destroyにしておくと、粒が全部消えたあとに、StarSparkleのゲームオブジェクトも自動で消えます。パーティクルのくわしい使い方は、12-4 パーティクルで演出しよう:Particle Systemの基本で紹介しています。

「+1」を作ろう

PlusOneのプレハブのInspector。TextMeshPro - TextのText Inputが「+1」、Font Sizeが10、Bが押されて太字、Vertex Colorが黄色

「+1」は、星のあった場所に出したいので、Canvasの文字ではなく、ステージの中に置ける文字を使います。

  • Hierarchyで右クリック>3D Object>Text – TextMeshPro、名前をPlusOneにする
    • Positionを(0, 0, 0)、Rect TransformのWidth:3、Height:1.5
  • TextMeshPro – Text
    • Text:「+1」、Font Size:10、太字、Vertex Color:#FFE08A、まん中寄せ
    • Extra SettingsのOrder in Layer:10(キラキラより手前)

ScriptsフォルダにPopupTextを作ります。

using TMPro;
using UnityEngine;

// 文字を上に浮かせながら、だんだん消す
public class PopupText : MonoBehaviour
{
    [SerializeField] private float riseSpeed = 1.5f;   // 1秒に上がる高さ
    [SerializeField] private float lifeSeconds = 0.8f; // 消えるまでの時間

    private TMP_Text popupText;
    private float time;

    private void Start()
    {
        popupText = GetComponent<TMP_Text>();
    }

    private void Update()
    {
        time += Time.deltaTime;
        transform.position += Vector3.up * riseSpeed * Time.deltaTime;
        // 時間がたつほど、透明にしていく
        Color color = popupText.color;
        color.a = 1f - time / lifeSeconds;
        popupText.color = color;
        if (time >= lifeSeconds)
        {
            Destroy(gameObject);
        }
    }
}
  • transform.position += Vector3.up * …
    • 毎フレーム、少しずつ上に動かす
  • color.a = 1f - time / lifeSeconds
    • aは透明度(1で見える、0で透明)。0.8秒かけて、1から0へだんだん透明にする
  • Destroy(gameObject)
    • 消えきったら、自分のゲームオブジェクトを消す。残しておくと、星を取るたびに見えない「+1」がたまっていく

PlusOneにPopupTextを付けたら、Prefabsフォルダにドラッグしてプレハブにし、Hierarchyのほうは消します。

Starスクリプトを作ろう

最後に、星を取ったときの処理です。ScriptsフォルダにStarを作ります。

using UnityEngine;

// 星:スライムちゃんが取ったら、キラキラと「+1」を出して消える
public class Star : MonoBehaviour
{
    [SerializeField] private GameObject sparklePrefab; // 取ったときのキラキラ
    [SerializeField] private GameObject popupPrefab;   // 取ったときの「+1」

    private void OnTriggerEnter2D(Collider2D other)
    {
        PlayerMove player = other.GetComponent<PlayerMove>();
        if (player == null)
        {
            return;
        }
        Instantiate(sparklePrefab, transform.position, Quaternion.identity);
        Instantiate(popupPrefab, transform.position + Vector3.up * 0.8f, Quaternion.identity); // 星の少し上に出す
        FindAnyObjectByType<StarCounter>().CollectStar();
        Destroy(gameObject);
    }
}
  • Instantiate(プレハブ, 位置, 向き)
    • プレハブから、ゲームオブジェクトを新しく作る。星のあった位置にキラキラ、少し上に「+1」を作る
  • FindAnyObjectByType<StarCounter>()
    • シーンにあるStarCounterを探して、CollectStar()を呼ぶ
  • Destroy(gameObject)
    • 取った星を消す

StarCounterをInspectorでつながずにFindAnyObjectByTypeで探しているのは、Starがプレハブだからです。プレハブには、シーンの中のゲームオブジェクトを入れておけません(シーンが変わると、相手がいなくなるため)。

付けていきます。

  • PrefabsフォルダのStarのプレハブを選んで、Starスクリプトを付ける
    • Sparkle PrefabにStarSparkle、Popup PrefabにPlusOneを入れる
  • StarTextにStarCounterを付けて、Doorの欄に扉のゲームオブジェクト(Door)をドラッグ

プレハブに付けたので、置いてある3つの星にもまとめて付きます。再生して、星を取ってみましょう。

星に重なってもキラキラが出ず、星も消えないときは、Consoleにエラーが出ていないか見てみましょう。Sparkle PrefabやPopup Prefabが空のままだと、Instantiateでエラーになって、そこで処理が止まってしまいます。

左から歩いてきたスライムちゃんが星に重なると、星が消えて、キラキラの粒が丸く広がり、「+1」が上に浮かびながら消えていく
スライム

キラキラッて出ると、思わず全部取りたくなりますね!

完成チェック

タイトルでEnterを押すとステージへ。迷路を歩いて星を3つ取ると、左上の数が3→2→1と減り、最後の星で扉が開いて「扉が ひらいた!」に。開いた扉に入ると白く光ってエンディングへ。Enterで「タイトルへ」を押すとタイトルに戻る。右下に押したキーが出る

Titleシーンを開いて再生し、最初から最後まで通して遊びます。

  • ステージに星が3つあって、ふわふわ浮いている。左上に「のこり 3」
  • 星を取ると、キラキラと「+1」が出て、「のこり」の数が1つ減る
  • 星を全部集める前は、扉に重なってもエンディングに行かない
  • 最後の星を取ると、扉が開いてキラキラが出て、「扉が ひらいた!」になる
  • 開いた扉に入ると、白く光ってからエンディングへ。「タイトルへ」でタイトルに戻る

これで、「星を集めて、扉を開けて、帰る」という、このゲームの遊びがそろいました!

ビルドして遊ぼう

Build ProfilesでWindowsがActive。Scene ListにTitle・Stage1・Endingの3つが入っていて、右下にBuildのボタン

今回も、ビルドして.exeで遊びます。

  • Stage1シーンを保存(Ctrl+S)してから、File>Build Profilesを開いてBuild
  • 前回と同じBuild/StarGardenのフォルダを選ぶ(上書きしてOK)
  • 出来たStarGarden.exeで、星を3つ集めて扉から帰れるか遊んでみる

あとがき

今回は、星を置いて、残りの数を表示し、全部集めたら扉が開くようにしました。キラキラのパーティクルと「+1」の文字で、取ったときの気持ちよさも付きました。目的があって、達成したら扉が開く。ちいさくても、ちゃんと「ゲーム」の形です。

次回は、迷路の中におばけを出します。行ったり来たりするおばけに当たると、画面が揺れてやり直し。緊張感が出てきますよ!

スライム

星を全部集めて扉が開いたとき、ちょっとうるっとしちゃいました・・・

フェアリー

まだ泣くのは早いよ!次はおばけが出るから、よけながら集めてね!

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

コメント

コメント一覧 (1件)

コメントする

目次