LoginSignup
1
0

More than 1 year has passed since last update.

[Unity] [ゲーム制作] 簡易的なギミックの実装方法

Last updated at Posted at 2022-12-04

初投稿です。よろしくお願いします。

目次

  1. 概要
  2. 実装概要
  3. 作業手順
  4. 実装方法
  5. 最後に

概要

2Dゲーム制作において、「キャラクターがスイッチを要求数踏むと扉が開く」の実装方法について記述します。また、以下のことが学べます:

  • 上記ギミックの実装方法
  • クラスを跨いだ変数の受け渡し
こんな感じのギミックが作れます:

ezgif.com-gif-maker.gif
(カメラの動作は実装しません)
(権利表記:TheCogen-City AllStars_Unity-chan_PixelArtPack_ActionGames Vol.2 © UTJ/UCL)

実装概要

要点は「スイッチを押すと変数の値が増え、その値が一定以上になると扉が開く」なので、最低限以下をすればよい:

  1. 扉に現在起動しているギミック数"ActiveSymbolCount"と発動のために必要なギミック数"requiredCount"という変数を持たせる。
  2. スイッチを踏んだ時、スイッチ側でActiveSymbolCountを増加させる。
  3. 要求数回スイッチを押す(ActiveSymbolCount >= requiredCount)と、扉が開くようにする。

この際に気を付けるべきことは、同一スイッチによる二重判定である。また、要求数としてsymbolリストというものを用いている。これは、スイッチを押すと光るオブジェクトを格納するリストであり、現在何個起動したかをわかりやすくするためのものである。

注意
2Dのコライダーを使用するので、それを発動できるように環境を整えておく必要がある(Rigidbody2Dと2Dのコライダーを持つSpriteを用意すればよい)。また、それのタグを"Player"として下さい。

作業手順

1. 扉とスイッチとシンボルのプレハブ作成
2. 扉と複数個のスイッチを含むプレハブの作成と配置
3. 扉とスイッチ用のスクリプトを作成
4. 実装確認

実装方法

1. 扉とスイッチとシンボルのプレハブ作成

  • 扉(GimmickDoor.prefab)の作成
  1. Spriteを作成し、好みの画像を設定。
  2. Box Collider 2D(Is Triggerをオフ)を付与。
  3. 扉のOrder in Layerを-1とする。 (扉の上にシンボルを配置するため)
  4. 扉をAssets下のフォルダに入れ、シーン上の物は消す。
    image.png
    (AudioSourceをつけていると、中央のマークが出ます。今回は実装しないので無視してください。)
  • スイッチ(GimmickSwitch.prefab)の作成
  1. 扉プレハブをコピペし、名前を付ける。
  2. 画像をスイッチ用に差し替え、Box Collider 2DのIs Triggerをオンにする。
    image.png
  • シンボル(Symbol.prefab)の作成
  1. Spriteを作成し、子としてPoint Light 2D(アクティブはオフ)を持たせる。
  2. シンボルをAssets下のフォルダに入れ、シーン上の物は消す。
    image.png
  • 扉(GimmickDoor.prefab)の子として4つのシンボル(Symbol.prefab)を持たせる。
    image.png

2. 扉と複数個のスイッチを含むプレハブの作成と配置

  1. 空のオブジェクト(GimmickDoorGroup)を作成し、 1つのGimmickDoor.prefabと4つのGimmickSwitch.prefabを下記のように子として持たせる。(今回は4つのスイッチを押すと起動するようにするので。)
    image.png
  2. これをAssets下のフォルダに入れ、シーン上の物は消す。
  3. シーン上にGimmickDoorGroup.prefabを置き、扉やスイッチをいい感じに配置する。
    image.png

3. 扉とスイッチ用のスクリプトを作成

  1. GimmickDoor.csとGimmickSwitch.csを作成し、それぞれをGimmickDoor.prefabとGimmickSwitch.prefabに付与。
  2. 下記のようにスクリプトを記述。
  3. GimmickDoor.prefabを選択し、Gimmick Door (Script)コンポーネントのsymbolsのサイズを4にし、子のシンボルを代入。
  4. GimmickDoorGroup.prefab内のGimmickSwitchを選択し、Gimmick Switch (Script)コンポーネントのGimmickDoorに、GimmickDoorGroup.prefab内のGimmickDoorを代入。
GimmickDoor.cs (tap)
GimmickDoor.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GimmickDoor : MonoBehaviour
{
    private const float WaitTime = 0.5f;
    private const int OpeningTime = 120;
    private const int OpenHeight = 7;

    public List<GameObject> symbols;

    private int requiredCount;
    private int prevActiveSymbolCount;

    public int ActiveSymbolCount { get; set; } // 外部で参照するのでプロパティを使う

    private void Start()
    {
        requiredCount = symbols.Count; // 要求数 = 代入したシンボル数
    }

    private void Update()
    {
        if (ActiveSymbolCount > requiredCount || prevActiveSymbolCount == ActiveSymbolCount) { return; } // 要求数以上押しても無効 または ActiveSymbolCountに変動があった場合のみ通す
        prevActiveSymbolCount = ActiveSymbolCount;

        ActiveSymbolAction(ActiveSymbolCount);
    }

    private void ActiveSymbolAction(int count)
    {
        symbols[count - 1].transform.GetChild(0).gameObject.SetActive(true); // シンボルを点灯
        if (count >= requiredCount)
        {
            StartCoroutine(nameof(OpenDoor));
        }
    }

    private IEnumerator OpenDoor()
    {
        yield return new WaitForSeconds(WaitTime);
        for (var i = 0; i < OpeningTime; i++)
        {
            transform.position += Vector3.up * OpenHeight * 1 / OpeningTime; // OpeningTime/60秒かけて扉が上昇
            yield return null;
        }
        DisableSymbols();
    }

    private void DisableSymbols()
    {
        foreach (var symbol in symbols)
        {
            symbol.transform.GetChild(0).gameObject.SetActive(false);
        }
    }
}

ポイント:

  • 要求数をシンボル数としているので、必ずすべてのシンボルが光った瞬間に開く
  • 要求数以上押しても無効
  • prevActiveSymbolCountを用いて、ActiveSymbolCountに変動があった場合のみActiveSymbolAction()を実行
GimmickSwitch.cs (tap)
GimmickSwitch.cs
using UnityEngine;

public class GimmickSwitch : MonoBehaviour
{
    private const float PressedDiffPositionY = -0.3f;

    [Tooltip("対応する扉")]
    public GimmickDoor gimmickDoor;

    private bool isOn;

    private void OnTriggerEnter2D(Collider2D collision)
    {
        if (gimmickDoor && !isOn && collision.gameObject.tag == "Player") // プレイヤーが踏むと、
        {
            isOn = true; // 二重判定回避
            transform.position += Vector3.up * PressedDiffPositionY; // 踏むと凹むように見えるようにする
            gimmickDoor.ActiveSymbolCount++; // 扉が開くためのフラグ
        }
    }
}
    

ポイント:

  • 扉側の変数ActiveSymbolCountをプレイヤーの接触に応じて増加
  • isOn変数を用いることで二重判定を回避

4. 実装確認

最後に、プレーヤーを用いて4つのスイッチを押し、扉が開けば実装完了。(参考)

最後に

どうでしたか、わかりやすかったでしょうか。外部へのセーブや位置を指定したシーン遷移などネタはあるので気が向いたら記述します。それでは。

宣伝:暇でしたら、私が作ったゲームで遊んでいただけると嬉しいです↓
https://www.freem.ne.jp/win/game/29100

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0