LoginSignup
3
2

【Unity2D】爆発を簡単に実装する方法

Posted at

IPFactory Advent Calender 2023 11日目の記事です。

はじめに

Unity2Dを用いた爆発の実装方法をまとめた記事が見当たらなかったので、かみ砕いて解説してみました。
ぜひお手元で実装してみてください!

目次

用意するもの

1.爆弾の画像

こちらの画像を使わせていただきました。

2.エフェクト

今回はこちらの動画をもとにParticleSystemを用いて自作しました。
非常に分かりやすい動画ですので是非参考にしてみてください。

自作しない場合はAssetStoreから持ってくるか、用意できない場合は無くても大丈夫です。

download.gif

下準備

1.ステージ

舞台となるステージを用意します。
Hierarchy ビューで右クリック → 2D Object → Sprite から好きな形を選びScene上に配置してください。

配置できましたら当たり判定をつけるため Inspector ビューでAdd Componet → Physics2D → Boc Collider 2D を選びステージの大きさに合うように調整してください。

スクリーンショット 2023-12-11 000944.png

2.箱

爆発の対象となる箱を用意します。
ステージと同じように、Scene上にbox配置し、コライダーをアタッチしてください。

スクリーンショット 2023-12-11 001241.png

また、箱には重力を適用したいため Inspector ビューでAdd Componet → Physics2D → Rigidbody 2D を選んでください。

ここでゲームを開始すると箱がステージの上に落ちるかと思います。

3.爆弾

爆弾ですが、基本的には箱と同じですのでboxをコピーしてbombに名前を変更してください。

bombは分かりやすいよう見た目を変えます。用意した爆弾の画像を Inspector ビューのSprite Render → Sprite にアタッチしてください。

爆弾は丸いのにboxをそのまま使っているためコライダーが BoxCollider2D になっています。

BoxCollider2Dを削除後、Inspector ビューでAdd Componet → Physics2D → Circle Collider 2D をアタッチし、画像に合わせて形を変更してください。

スクリーンショット 2023-12-11 093409.png

これで下準備は完了です。
箱は多いほど爆発の影響を感じやすいのでお好きな数配置してください。

爆発スクリプトの作成

Assetsで右クリック → Create → C# Script でスクリプトを作成し、名前をBombに変更してください。

スクリプトをダブルクリックで開き、以下のコードを張り付けてください。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Bomb : MonoBehaviour
{
    [SerializeField] private ParticleSystem explosionParticleSystemPrefab; // 爆発時のパーティクルシステム
    [SerializeField] private float explosionForce; // 爆発力
    [SerializeField] private float explosionRadius; // 爆発半径

    private void OnMouseDown()
    {
        Detonate();
    }

    // 爆発処理
    void Detonate()
    {
        // パーティクルシステムを生成して爆発エフェクトを再生
        ParticleSystem explosionParticleSystem = Instantiate(explosionParticleSystemPrefab, transform.position, Quaternion.identity);
        explosionParticleSystem.Play();

        // パーティクル再生時間が終了したらパーティクルシステムを破棄
        Destroy(explosionParticleSystem.gameObject, explosionParticleSystem.main.duration);

        // 爆風の範囲内のオブジェクトを検出
        Collider2D[] colliders = Physics2D.OverlapCircleAll(transform.position, explosionRadius);
        foreach (Collider2D collider in colliders)
        {
            ApplyExplosionForce(collider);
        }

        // 爆弾オブジェクトを破棄
        Destroy(gameObject);
    }

    // 吹き飛ばしの処理
    void ApplyExplosionForce(Collider2D targetCollider)
    {
        Rigidbody2D targetRigidbody = targetCollider.GetComponent<Rigidbody2D>();

        if (targetRigidbody != null)
        {
            // 爆心からの距離に応じて力を計算
            Vector2 explosionDirection = targetCollider.transform.position - transform.position;
            float distance = explosionDirection.magnitude;
            float normalizedDistance = distance / explosionRadius;
            float force = Mathf.Lerp(explosionForce, 0f, normalizedDistance);

            // 力を加える
            targetRigidbody.AddForce(explosionDirection.normalized * force, ForceMode2D.Impulse);
        }
    }
}

コードの解説

上記のコードをかみ砕いて解説していきます。
コピペで動きますので実装だけしたい方は飛ばしてください。skip→

1.変数定義

[SerializeField] private ParticleSystem explosionParticleSystemPrefab; // 爆発時のパーティクルシステム
[SerializeField] private float explosionForce; // 爆発力
[SerializeField] private float explosionRadius; // 爆発半径

変数は上から順番に

  • 爆発エフェクト
  • 爆発力
  • 爆発半径

になります。爆発力・爆発半径ともに9を代入しているという前提で進めていこうと思います。

※ 変数はスクリプト上で値を代入せず、後で Inspector 上で変更していきます。

2.クリックで爆発

private void OnMouseDown()
{
    Detonate();
}

OnMouseDownメソッドはオブジェクトがクリックされたときに呼び出されます。

要するにクリックされたときに爆発するようになっています。

3エフェクトの生成

    void Detonate()
    {
        // パーティクルシステムを生成して爆発エフェクトを再生
        ParticleSystem explosionParticleSystem = Instantiate(explosionParticleSystemPrefab, transform.position, Quaternion.identity);
        explosionParticleSystem.Play();

        // パーティクル再生時間が終了したらパーティクルシステムを破棄
        Destroy(explosionParticleSystem.gameObject, explosionParticleSystem.main.duration);

        // ----- 省略 -----
    }

explosionParticleSystem変数にtransform.position(爆弾の位置)に生成したexplosionParticleSystemPrefab(爆発のエフェクト)を代入しています。

生成したエフェクトexplosionParticleSystemを再生し、再生が終わり次第破棄するという流れになっています。

※ エフェクト(パーティクル)が用意できなかった方は上のコードは消してください。

4.爆発範囲にいるオブジェクトの取得

    void Detonate()
    {
        // ----- 省略 -----

        // 爆風の範囲内のオブジェクトを検出
        Collider2D[] colliders = Physics2D.OverlapCircleAll(transform.position, explosionRadius);
        foreach (Collider2D collider in colliders)
        {
            ApplyExplosionForce(collider);
        }

        // 爆弾オブジェクトを破棄
        Destroy(gameObject);
    }

Physics2D.OverlapCircleAllで爆弾を中心とした半径explosionRadiusの当たり判定を生成し、範囲内のオブジェクト全てがApplyExplosionForce(爆風を加える)メソッドを実行させています。

スクリーンショット 2023-12-11 105518.png

爆弾は爆発によってなくなりますのでDestroy(gameObject);で破棄します。

5.Rigidbody2Dの取得

    // 吹き飛ばしの処理
    void ApplyExplosionForce(Collider2D targetCollider)
    {
        Rigidbody2D targetRigidbody = targetCollider.GetComponent<Rigidbody2D>();

        if (targetRigidbody != null)
        {
            // ----- 省略 -----
        }
    }

targetRigidbodyに取得したオブジェクトのRigidbody2Dを取得し、代入します。
このRigidbody2Dは後で爆風を与える時に使います。

基本的にはtargetRigidbodyにRigidbody2Dが代入されているはずです。
しかしステージなどのコライダーを持っていながらRigidbody2Dを持っていないオブジェクトによりエラーが起きる可能性があるためif (targetRigidbody != null)でnull検知を忘れないでください。

スクリーンショット 2023-12-11 112948.png

6.オブジェクト間のベクトルと距離を求める

// 爆心からの距離に応じて力を計算
Vector2 explosionDirection = targetCollider.transform.position - transform.position;
float distance = explosionDirection.magnitude;

boxが受ける爆発力を計算していきます。
ここではbombの座標を(1, 2)boxの座標を(8, 5)だと仮定して進めていきます。

最初に、爆弾から箱へのベクトルを

Vector2 explosionDirection = targetCollider.transform.position - transform.position;

で計算します。
boxの座標 - bombの座標 → (8, 5) - (1, 2) = (7, 3)でオブジェクト間のベクトルが(7, 3)と求まりました。

スクリーンショット 2023-12-11 123133.png

ベクトルが求まりオブジェクト間の角度が分かるようになりましたが、肝心なオブジェクト間の距離が分かりません。

そこで先ほど求めたベクトルを用いてオブジェクト間の距離を

float distance = explosionDirection.magnitude;

で計算します。
magnitudeは、与えられたベクトルから自動的に距離に変換してくれるプロパティのため、7.615773と距離が求まりました。

\text{magnitude} = \sqrt{x^2 + y^2}

スクリーンショット 2023-12-11 131031.png

7.爆風を計算し力を加える

float normalizedDistance = distance / explosionRadius;
float force = Mathf.Lerp(explosionForce, 0f, normalizedDistance);

// 力を加える
targetRigidbody.AddForce(explosionDirection.normalized * force, ForceMode2D.Impulse);

最初に先ほど求めたdistance(距離)を正規化していきます。
ここでの正規化とはdistanceexplosionRadius(爆発半径)の何倍になるかを指します。

float normalizedDistance = distance / explosionRadius;

先ほど求めた距離7.615773から爆発半径である9で割ると正規化された距離である0.8461975が求まりました。

これにより、半径91としたときにboxは0.8461975の位置にいるということが分かりました。

スクリーンショット 2023-12-11 133128.png

次にboxが受ける爆発力を求めます。

爆発力explosionForce9と定義したので爆発力と位置の関係を表すと以下のようになります。

スクリーンショット 2023-12-11 140205.png

爆発の威力は爆発の中心が一番が高いので、爆発力9になります。
また、爆発半径は9なので、爆発を中心とした半径9を超えると爆発力が0になることが分かります。

この関係から

float force = Mathf.Lerp(explosionForce, 0f, normalizedDistance);

を用いて最大値9を始点、最小値0を終点として爆発の中心からの距離である0.8461975で線形補完することで、box位置の爆発力である1.384223という値が求まりました!

最後に、対象オブジェクトのRigidbody2Dに今求めた力を加えます。

targetRigidbody.AddForce(explosionDirection.normalized * force, ForceMode2D.Impulse);

加える力はForceMode2D.Impulseにすることで爆発のような瞬間的な力がかかるようになります。
力を加える角度は最初に求めたオブジェクト間のベクトル(bombからboxの角度)に設定し、その角度にいま求めたfornce(box位置の爆発力)を加えると...

スクリーンショット 2023-12-11 141206.png

/
ドカーーーン!!
\

スクリーンショット 2023-12-11 142238.png

飛びました!!

爆弾の仕上げ

完成したBombスクリプトをBombにアタッチしていきます。

Hierarchy ビューからBombを選択 → Inspector ビューにBombスクリプトをドラッグアンドドロップ

変数にはそれぞれ

  • 用意したエフェクトをアタッチ
  • 爆発力9を入力
  • 爆発半径9を入力

エフェクトがない場合は空でも大丈夫ですが、こちらの3行を消しておいてください。

xplosion ForceExplosion Radiusには色々な値を入れて動きの違いを確かめてみてください。

スクリーンショット 2023-12-11 142956.png

動かす

完成です!

爆弾をクリックしてみると...

吹き飛びました!!

さいごに

できるだけかみ砕いて解説してみました。

ゲーム制作の参考になれば嬉しいです!

参考資料

3
2
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
3
2