📑

【Unity】画面をタップしたときにエフェクトを表示させる方法

2023/11/19に公開

スマホで画面をタップしたときに何らかのエフェクトが表示されるアプリは多いと思います。
今回はそのエフェクトを実装してみたいと思います。
分かりやすく画像をこまめに挟んでいます。

全体的なイメージ

この機能ではエフェクトを表示させるための親オブジェクトと、そこから生成されるエフェクトオブジェクトの2種類で構成されています。
※本記事ではシーンのワールド座標上に直接エフェクトを表示させているので、カメラのズーム率等でエフェクトの大きさが変わってしまう点にご注意ください。(UI Canvas上に表示させる方法も考えられます。)

前提

  • 2Dのプロジェクトを想定しています。

手順

  1. Hierarchy上にMain Cameraがあることを確認します。
    (新規作成時の初期状態で存在しているはず)

    この状態から始めます

  2. エフェクトのオブジェクトを作成
    まずはHierarchy上の+ボタンからエフェクト用のオブジェクトを作成します。
    今回はエフェクト画像としてデフォルトの円系を設定します。
    ※お好みで画像を変更してください。
    2D Object > Sprites > Circle
    オブジェクト名をEffectにします。

  1. エフェクトオブジェクトの設定(任意)
    エフェクトの見た目を調整します。
    白い丸のままだと味気ないので、半透明化します。
    Hierarchy上のEffectオブジェクトを選択し、Inspector上のSprite Renderer > Colorをダブルクリックし、Colorパレットで透明度を128に変更します。

  1. エフェクトのオブジェクトをプレハブ化
    Hierarchy上のEffectオブジェクトをProjectパネルのAssets配下へドラッグ&ドロップします。
    Assets上に格納しプレハブとして登録しておきます。
    Hierarchy上のEffectオブジェクトは削除します。

  1. 空のオブジェクトを作成します。
    Hierarchy上にて+ボタンからCreate Emptyを選択します。(Ctrl + Shift + N でもできます。)
    これをエフェクトを生成させる親オブジェクトとして扱っていきます。
    名前はEffectControllerとします。

  1. スクリプトの作成
    エフェクトを表示させるためのスクリプトを作成します。
    ProjectパネルのAssets配下でCreate > C# Scriptを選択します。

ファイル名はEffectとします。
以下コードを貼付け保存します。
※コードの説明は後述します。

using UnityEngine;
using System.Collections;

public class Effect : MonoBehaviour
{
    public GameObject effectPrefab; // エフェクトのプレハブ
    public float maxScale = 1.5f; // エフェクトが広がる大きさ
    public float duration = 0.3f; // エフェクトの表示時間

    private Camera mainCamera;

    void Start()
    {
        // メインカメラを取得
        mainCamera = Camera.main;
    }

    private void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            // 画面をタップしたときの処理
            Vector2 tapPosition = mainCamera.ScreenToWorldPoint(Input.mousePosition);

            // エフェクトを生成
            GameObject effect = Instantiate(effectPrefab, tapPosition, Quaternion.identity, this.transform);
            Destroy(effect, duration);

            StartCoroutine(ScaleEffect(effect.transform));
        }
    }

    IEnumerator ScaleEffect(Transform effectTransform)
    {
        // 経過時間を定義
        float elapsedTime = 0f;

        // エフェクトの表示時間中繰り返し
        while (elapsedTime < duration)
        {
            // オブジェクトが破棄されたかどうかを確認
            if (effectTransform == null)
            {
                yield break; // メソッドを終了
            }

            // ローカルスケールを変更
            float scale = Mathf.Lerp(1f, maxScale, elapsedTime / duration);
            effectTransform.localScale = new Vector2(scale, scale);

            // 経過時間を進める
            elapsedTime += Time.deltaTime;

            // 1フレーム進める
            yield return null;
        }
    }
}
  1. スクリプトをアタッチします。
    Hierarchy上のEffectControllerを選択した状態で、ProjectパネルのEffectスクリプトをドラッグ&ドロップでEffectControllerのInspector上に持っていき、コンポーネントとして追加します。

動作確認

ゲームを開始して動作確認をしてみます。
画面をクリックすると半透明の円がクリックした位置に一瞬だけ表示されるかと思います。

コードの説明

  public GameObject effectPrefab; // エフェクトのプレハブ
  public float maxScale = 1.5f; // エフェクトが広がる大きさ
  public float duration = 0.3f; // エフェクトの表示時間

  private Camera mainCamera;

グローバル変数を定義しています。
effectPrefabはエフェクトのプレハブを設定する部分です。
maxScaleはエフェクトが広がる大きさを保持しています。ここを調整するとエフェクトの大きさを変えられます。
durationはエフェクトが消えるまでの時間を保持しています。これもInspector上で調整できます。
mainCameraは後述するメインカメラの取得処理で取得した情報を変数として保持します。privateなのでInspector上で表示されません。

  void Start()
  {
      // メインカメラを取得
      mainCamera = Camera.main;
  }

EffectControllerオブジェクトがシーン上にある状態で一番初めに実行される処理です。
メインカメラの情報を取得します。
これでmainCamera変数からカメラに関する情報を引き出せるようになります。

  private void Update()
  {
      if (Input.GetMouseButtonDown(0))
      {
          // 画面をタップしたときの処理
          Vector2 tapPosition = mainCamera.ScreenToWorldPoint(Input.mousePosition);

          // エフェクトを生成
          GameObject effect = Instantiate(effectPrefab, tapPosition, Quaternion.identity, this.transform);
          Destroy(effect, duration);

          StartCoroutine(ScaleEffect(effect.transform));
      }
  }

EffectControllerオブジェクトがシーン上にある間中実行され続ける処理です。
ここではクリックやタップされた位置の座標を取得(tapPositionにて保持)して、その位置にプレハブ化しておいたエフェクトをシーン上に出現させます。
次にグローバル変数で定義したduration(エフェクトの表示時間)の時間後にエフェクトオブジェクトを削除します。
最後にScaleEffectメソッドをコルーチン(並列で非同期実行するための処理)として呼び出します。

  IEnumerator ScaleEffect(Transform effectTransform)
  {
      // 経過時間を定義
      float elapsedTime = 0f;

      // エフェクトの表示時間中繰り返し
      while (elapsedTime < duration)
      {
          // オブジェクトが破棄されたかどうかを確認
          if (effectTransform == null)
          {
              yield break; // メソッドを終了
          }

          // ローカルスケールを変更
          float scale = Mathf.Lerp(1f, maxScale, elapsedTime / duration);
          effectTransform.localScale = new Vector2(scale, scale);

          // 経過時間を進める
          elapsedTime += Time.deltaTime;

          // 1フレーム進める
          yield return null;
      }
  }

コルーチンの部分です。
while文で指定時間まで繰り返し処理します。
エフェクトオブジェクトのサイズを大きくして1フレーム待機することで、エフェクトが徐々に広がっていくような表現を実現します。
呼び出し元でDestroyしているので、オブジェクトが破棄されたらコルーチンも終了するようにします。
コルーチンで実行させることで非同期処理になるので、連続タップしても複数のオブジェクトがちゃんと表示されるようになります。連続タップしてもエフェクトが終わるまでは次のエフェクトを表示させたくない場合は、コルーチンで実行させない方がいいかもしれません。

まとめ

以上、Unityで画面上にエフェクトを表示させる方法でした。
この機能の中に画面のタップ、オブジェクトの生成、破棄、非同期処理の実行など色々と応用がきくと思います。

Discussion