初投稿です。よろしくお願いします。
目次
概要
2Dゲーム制作において、「キャラクターがスイッチを要求数踏むと扉が開く」の実装方法について記述します。また、以下のことが学べます:
- 上記ギミックの実装方法
- クラスを跨いだ変数の受け渡し
こんな感じのギミックが作れます:
(カメラの動作は実装しません)
(権利表記:TheCogen-City AllStars_Unity-chan_PixelArtPack_ActionGames Vol.2 © UTJ/UCL)
実装概要
要点は「スイッチを押すと変数の値が増え、その値が一定以上になると扉が開く」なので、最低限以下をすればよい:
- 扉に現在起動しているギミック数"ActiveSymbolCount"と発動のために必要なギミック数"requiredCount"という変数を持たせる。
- スイッチを踏んだ時、スイッチ側でActiveSymbolCountを増加させる。
- 要求数回スイッチを押す(ActiveSymbolCount >= requiredCount)と、扉が開くようにする。
この際に気を付けるべきことは、同一スイッチによる二重判定である。また、要求数としてsymbolリストというものを用いている。これは、スイッチを押すと光るオブジェクトを格納するリストであり、現在何個起動したかをわかりやすくするためのものである。
注意
2Dのコライダーを使用するので、それを発動できるように環境を整えておく必要がある(Rigidbody2Dと2Dのコライダーを持つSpriteを用意すればよい)。また、それのタグを"Player"として下さい。
作業手順
1. 扉とスイッチとシンボルのプレハブ作成
2. 扉と複数個のスイッチを含むプレハブの作成と配置
3. 扉とスイッチ用のスクリプトを作成
4. 実装確認
実装方法
1. 扉とスイッチとシンボルのプレハブ作成
- 扉(GimmickDoor.prefab)の作成
- Spriteを作成し、好みの画像を設定。
- Box Collider 2D(Is Triggerをオフ)を付与。
- 扉のOrder in Layerを-1とする。 (扉の上にシンボルを配置するため)
- 扉をAssets下のフォルダに入れ、シーン上の物は消す。
(AudioSourceをつけていると、中央のマークが出ます。今回は実装しないので無視してください。)
- スイッチ(GimmickSwitch.prefab)の作成
- シンボル(Symbol.prefab)の作成
2. 扉と複数個のスイッチを含むプレハブの作成と配置
- 空のオブジェクト(GimmickDoorGroup)を作成し、 1つのGimmickDoor.prefabと4つのGimmickSwitch.prefabを下記のように子として持たせる。(今回は4つのスイッチを押すと起動するようにするので。)
- これをAssets下のフォルダに入れ、シーン上の物は消す。
- シーン上にGimmickDoorGroup.prefabを置き、扉やスイッチをいい感じに配置する。
3. 扉とスイッチ用のスクリプトを作成
- GimmickDoor.csとGimmickSwitch.csを作成し、それぞれをGimmickDoor.prefabとGimmickSwitch.prefabに付与。
- 下記のようにスクリプトを記述。
- GimmickDoor.prefabを選択し、Gimmick Door (Script)コンポーネントのsymbolsのサイズを4にし、子のシンボルを代入。
- GimmickDoorGroup.prefab内のGimmickSwitchを選択し、Gimmick Switch (Script)コンポーネントのGimmickDoorに、GimmickDoorGroup.prefab内のGimmickDoorを代入。
GimmickDoor.cs (tap)
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)
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