Parallels Desktop 35%OFF セール

【Unity】タワーディフェンス(23) ビジュアルエフェクトの追加【クソゲー制作】

タワーディフェンスを作る(23)

Unity初心者が2Dタワーディフェンスゲームを制作しております。

今回は、敵を攻撃したときや城が攻撃されたときのビジュアルエフェクトを追加していきます。これでゲーム画面がグッと華やいでお客様の満足度も急上昇するのではないでしょうか。

環境
  • Mac mini (M1, 2020)
  • Unity 2022.3.36f1
  • Cartoon FX Remaster Free R 1.5.0
目次

敵が攻撃されたときに動きを止める

敵が攻撃されたときに一瞬動きを止める処理を追加したいと思います。

EnemyControllerスクリプトを修正します。

using UnityEngine;
using DG.Tweening;
using System.Linq;
// ここから追加
using System.Collections; // IEnumerableを使用するために必要
// ここまで

public class EnemyController : MonoBehaviour
{
    // ...省略...

    /// <summary>
    /// ダメージを受ける
    /// </summary>
    /// <param name="damageAmount">ダメージ量</param>
    public void TakeDamage(int damageAmount)
    {
        if (currentHp <= 0) return; // すでに死亡していたら何もしない

        // HPの値を減算した結果値を、最小値と最大値の範囲内に収まるようにして更新
        currentHp = Mathf.Clamp(currentHp - damageAmount, 0, maxHp);
        // HPバーの更新
        if (hpBar != null)
            hpBar.UpdateHpBar(currentHp);

        // ここから追加
        StartCoroutine(StopMoveForSeconds(0.1f));
        // ここまで

        if (currentHp <= 0)
        {
            // HPが0以下になったら敵を破壊
            DefeatEnemy();
        }
    }

    // ここから追加
    /// <summary>
    /// 一時的に移動を停止する
    /// </summary>
    /// <param name="seconds">停止する秒数</param>
    private IEnumerator StopMoveForSeconds(float seconds)
    {
        if (moveTween != null && moveTween.IsPlaying())
        {
            moveTween.Pause();
            yield return new WaitForSeconds(seconds);
            if (moveTween != null && !moveTween.IsPlaying())
            {
                moveTween.Play();
            }
        }
    }
    // ここまで

    // ...省略...
}

敵の移動を一時的に停止するコルーチンStopMoveForSeconds()を追加して、TakeDamage()内で呼び出します。

StopMoveForSeconds()では、moveTweenを一時停止(Pause)して、指定時間後に再生(Play)しています。moveTweenには敵が経路に沿って移動するDOTweenの処理が入っています。

この処理を追加することで、攻撃されている敵が視覚的にわかりやすくなりました。また、等間隔で並んで移動していた敵の車間距離(?)が乱れるという効果もありました。ゲーム性が高まったと思います。

Cartoon FX Remaster Freeを使う

さあ、このゲームにもっとクールな華やぎをもたらすために、アセットを導入しましょう。Cartoon FX Remaster Freeです。安心してください、無料です。

Cartoon FX Remaster Freeのインポート

STEP

Unityエディタのメニューの「Window > Package Manager」を選択して、Package Managerを開きます。

My AssetsCartoon FX Remaster Freeを選択して、右上の「Download」ボタンでダウンロードし、「Import」ボタンでインポートします。

タワーディフェンス231
STEP

Import Unity Packageウインドウが表示されたら「Import」ボタンをクリックします。

タワーディフェンス232
STEP

インポートが完了すると以下のウェルカムウインドウが開くので「Close and don’t show again」ボタンを押して閉じます。「Close」ボタンを押すと、Unityエディタを起動するたびにこのウインドウが開きます。お好みでどうぞ。

タワーディフェンス233
STEP

インポートに成功すると「Assets > JMO Assets」フォルダが作成されます。

「JMO Assets > Cartoon FX Remaster > CFXR Prefabs」にエフェクトのプレハブが入っています。プレハブをダブルクリックすると、Sceneタブでどんなエフェクトなのか確認できます。

敵がダメージを受けたときのエフェクト

敵がダメージを受けたときのエフェクトをCartoon FX Remaster Freeを使って実装します。

STEP

EnemyControllerスクリプトを修正します。

public class EnemyController : MonoBehaviour
{
    // ...省略...
    // ここから追加
    [SerializeField, Tooltip("ダメージエフェクトのプレハブ")] private GameObject damageEffectPrefab;
    // ここまで

    // ...省略...

    /// <summary>
    /// ダメージを受ける
    /// </summary>
    /// <param name="damageAmount">ダメージ量</param>
    public void TakeDamage(int damageAmount)
    {
        if (currentHp <= 0) return; // すでに死亡していたら何もしない

        // HPの値を減算した結果値を、最小値と最大値の範囲内に収まるようにして更新
        currentHp = Mathf.Clamp(currentHp - damageAmount, 0, maxHp);
        // HPバーの更新
        if (hpBar != null)
            hpBar.UpdateHpBar(currentHp);

        // ここから追加
        // ダメージエフェクトを表示
        if (damageEffectPrefab != null)
        {
            // エフェクトを敵の位置に生成
            GameObject effect = Instantiate(damageEffectPrefab, transform.position, Quaternion.identity);
            Destroy(effect, 2f); // エフェクトの長さに応じて調整
        }
        // ここまで

        StartCoroutine(StopMoveForSeconds(0.1f));

        if (currentHp <= 0)
        {
            // HPが0以下になったら敵を破壊
            DefeatEnemy();
        }
    }

    // ...省略...
}
  • エフェクトのプレハブを入れる変数damageEffectPrefabを定義します。
  • TakeDamage()内で、ダメージエフェクトを表示します。
    • プレハブからエフェクトを生成。
    • 2秒後にエフェクトを削除。
STEP

damageEffectPrefabにプレハブをアサインします。

Enemyプレハブをダブルクリックしてプレハブの編集モードに入ります。インスペクターの「Enemy Controller (Script) > Damage Effect Prefab」「JMO Assets > CFXR Prefabs > Misc > CFXR3 Hit Misc A」をアサインします。

タワーディフェンス234
STEP

以上で、敵が攻撃されたときにエフェクトが表示されるようになったのですが、エフェクトが最前面に表示されません。表示の重なり順を調整する必要がありそうです。

「JMO Assets > CFXR Prefabs > Misc > CFXR3 Hit Misc A」をダブルクリックしてプレハブの編集モードに入ります。

インスペクターの「Particle System > Renderer > Sorting Layer ID」「Object」に変更します。子オブジェクトのSorting Layer IDも同様に変更します。

タワーディフェンス235

ちなみに、Sorting Layerは以下の3層構造になっています。

  • Default: 奥。草原を配置。
  • Way: 中。道と障害物を配置。
  • Object: 手前。砲台や敵を配置。
STEP

エフェクトの大きさを調整します。

これは「Transform > Scale」でいけました。

タワーディフェンス236
STEP

Cartoon FX Remaster Freeのエフェクトは、実行時にカメラを揺らす効果がついているものが多いのですが、敵が攻撃されるたびに揺れるのは鬱陶しいので無効化します。

「CFRX_Effect (Script) > Camere Shake > Enabled」のチェックを外します。

タワーディフェンス237

「Shake Strength」の値を0にしてもOKです。ということは、この値を大きくすると揺れが大きくなるっちゅーことですね。

敵が撃破されたときのエフェクト

敵が撃破されたときのエフェクトを実装します。ダメージを受けたときのエフェクトとほぼ同じ手順です。

STEP

EnemyControllerスクリプトを修正します。

public class EnemyController : MonoBehaviour
{
    // ...省略...
    // ここから追加
    [SerializeField, Tooltip("撃破エフェクトのプレハブ")] private GameObject defeatEffectPrefab;
    // ここまで

    // ...省略...

    /// <summary>
    /// 敵を撃破する
    /// </summary>
    private void DefeatEnemy()
    {
        // ここから追加
        // 撃破エフェクトを表示
        if (defeatEffectPrefab != null)
        {
            GameObject effect = Instantiate(defeatEffectPrefab, transform.position, Quaternion.identity);
            Destroy(effect, 2f); // エフェクトの長さに応じて調整
        }
        // ここまで

        // ...省略...
    }

    // ...省略...
}
  • エフェクトのプレハブを入れる変数defeatEffectPrefabを定義します。
  • DefeatEnemy()内で、撃破エフェクトを表示します。
    • プレハブからエフェクトを生成。
    • 2秒後にエフェクトを削除。
STEP

defeatEffectPrefabにプレハブをアサインします。

Enemyプレハブをダブルクリックしてプレハブの編集モードに入り、インスペクターの「Enemy Controller (Script) > Defeat Effect Prefab」「JMO Assets > CFXR Prefabs > Explosions > CFXR Explosion 1」をアサインします。

STEP

CFXR Explosion 1プレハブをダブルクリックして、インスペクターで以下の設定を修正します。

  • 表示の重なり順の設定。「Particle System > Renderer > Sorting Layer ID」をObjectに変更。子オブジェクトも同様に。
  • 「Transform > Scale」で、エフェクトの大きさの調整。
  • カメラを揺らす効果の無効化。「CFRX_Effect (Script) > Camere Shake > Enabled」のチェックを外す。

城がダメージを受けたときのエフェクト

城がダメージを受けたときのエフェクトを実装します。

STEP

FortressControllerスクリプトを修正します。

public class FortressController : MonoBehaviour
{
    // ...省略...
    // ここから追加
    [SerializeField, Tooltip("ダメージエフェクトのプレハブ")] private GameObject damageEffectPrefab;
    // ここまで

    // ...省略...

    /// <summary>
    /// ダメージを受ける
    /// </summary>
    public void TakeDamage()
    {
        // HPを1減らす
        currentHp--;
        // HPスライダーを更新
        UpdateHpSlider();

        // ここから追加
        // ダメージエフェクトを表示
        if (damageEffectPrefab != null)
        {
            Vector3 effectPos = transform.position + new Vector3(0, -0.5f, 0); // エフェクトの位置を調整
            GameObject effect = Instantiate(damageEffectPrefab, effectPos, Quaternion.identity);
            Destroy(effect, 2f); // エフェクトの長さに応じて調整
        }
        // ここまで

        // HPが0以下になったらゲームオーバー
        if (currentHp <= 0)
        {
            GameOver();
        }
    }

    // ...省略...
}
  • エフェクトのプレハブを入れる変数damageEffectPrefabを定義します。
  • TakeDamage()内で、ダメージエフェクトを表示します。
    • エフェクトの位置を少し下にずらす。
    • プレハブからエフェクトを生成。
    • 2秒後にエフェクトを削除。

デフォルトのエフェクトの表示位置が気に入らなかったので半マス分下にずらしました。最初、エフェクトプレハブの「Transform > Position」で設定を変更しようとしたのですが、うまくいかなかったのでスクリプトで変更しました。なんでだろう。

STEP

damageEffectPrefabにプレハブをアサインします。

Map1プレハブをダブルクリックしてプレハブの編集モードに入り、子オブジェクトのFortressのインスペクターの「Fortress Controller (Script) > Damage Effect Prefab」「JMO Assets > CFXR Prefabs > Explosions > CFXR2 WW Explosion」をアサインします。

WWってWorld Warのことかしら。だとしたら、これは原爆の爆発のことだよね。

STEP

CFXR2 WW Explosionプレハブをダブルクリックして、インスペクターで以下の設定を修正します。

  • 表示の重なり順の設定。「Particle System > Renderer > Sorting Layer ID」をObjectに変更。子オブジェクトも同様に。
  • 「Transform > Scale」で、エフェクトの大きさの調整。
  • カメラを揺らす効果は、そのまま残します。
STEP

Map2〜5Fortressにもエフェクトのプレハブをアサインします。

ゲームの初期化時にエフェクトを削除

ゲーム終了時に表示されていたエフェクトは、次のゲーム開始時にも残ったままになってしまうので、ゲームの初期化メソッドInitializeGame()にエフェクトを削除する処理を追加します。

STEP

GameManagerスクリプトを修正します。

public class GameManager : MonoBehaviour
{
    // ...省略...

    /// <summary>
    /// ゲーム全体の初期化(スコア・ゴールド・城HP・敵・砲台などのリセット)
    /// </summary>
    private void InitializeGame()
    {
        // スコア初期化
        if (ScoreManager.Instance != null)
            ScoreManager.Instance.ResetScore();

        // ゴールド初期化
        if (GoldManager.Instance != null)
            GoldManager.Instance.ResetGold();

        // 城HP初期化
        if (FortressController.Instance != null)
            FortressController.Instance.ResetHp();

        // 敵の生成をリセット
        var spawner = FindObjectOfType<EnemySpawner>();
        if (spawner != null)
            spawner.ResetSpawner();

        // 砲台の設置情報をリセット
        var turretGenerator = FindObjectOfType<TurretGenerator>();
        if (turretGenerator != null)
            turretGenerator.ResetTurretPlacements();

        // tileHighlighterを非表示
        if (tileHighlighter != null)
            tileHighlighter.SetActive(false);

        // マップ上の敵・HPバー・砲台・インジケータ削除
        foreach (var enemy in GameObject.FindGameObjectsWithTag("Enemy"))
            Destroy(enemy);
        foreach (var hpBar in GameObject.FindGameObjectsWithTag("HpBar"))
            Destroy(hpBar);
        foreach (var turret in GameObject.FindGameObjectsWithTag("Turret"))
            Destroy(turret);
        foreach (var indicator in GameObject.FindGameObjectsWithTag("Indicator"))
            Destroy(indicator);
        // ここから追加
        foreach (var effect in GameObject.FindGameObjectsWithTag("Effect"))
            Destroy(effect);
        // ここまで
    }

    // ...省略...
}
STEP

このゲームで使用するエフェクトのプレハブに「Effect」タグを設定します。全部で3つあります。

タワーディフェンス238

動作確認

動作確認をします。いい感じですね。

さいごに

はい、ほぼ完成ですね。次回はBGMと効果音をつけたいと思います。

でわでわ

タワーディフェンスを作る(23)

この記事が気に入ったら
いいね または フォローしてね!

シェアしてね

コメント

コメントする

目次