VFX Graphにおける当たり判定

# はじめに
今回はシューティングゲームなどで、 __Particle System__ のように一つ一つのParticleの衝突判定を、 __VFX Graph__ でしたいと思ったので、 __VFX Graph__ の当たり判定について、自分が調べたことをまとめていきます。

こちらが使用しているバージョンです。

**Unity：** 2020.3.26f1
**VFX：** 10.8.1
**ShaderGraph：** 10.8.1

## 当たり判定実装方法
結論から言うと __VFX Graph__ には、 __Particle System__ のように衝突判定を追加する機能はありませんでした。
詳しくはこちらのサイトをhttps://forum.unity.com/threads/vfx-graph-collision.813231/

だからといってここで諦めるのは何なので、疑似的に当たり判定っぽいものを作っていきたいと思います。

***

### 手段
VFXに当たり判定っぽいものを実装する方法は、今回はVFX Graphをスクリプトで制御することでやっていきたいと思います。

***

### VFX
こちらが __VFX Graph__ のノードです。

`DstPos`__：__ 弾の目標地点
`SrcPos`__：__ 弾の発射地点
`Color`__：__ 弾のカラー
`Speed`__：__ 弾の速度
![スクリーンショット (263).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2532480/998f0fd4-70c7-414b-9b0b-c5e056db4ead.png)

`DstPos`から`SrcPos`の差分から弾のベクトルを求めています。そして求めたベクトルを正規化しと`Speed`乗算することで、弾の速度を`Speed`で制御できる形にしています。
![Qiita_VFX001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2532480/af4b66a1-f382-a331-a3fd-5d3891cf130c.png)

`DstPos`から`SrcPos`の差分から求めたベクトルの大きさを、弾の速度の大きさで割ることで弾が`SrcPos`に到達する時間を求め、それを`LifeTime`にしています。
![スクリーンショット (265).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2532480/4a78729b-77b7-dc86-f238-bee501775f7f.png)

***

### スクリプト
サンプルコードでは、 `IEnumerator`と`yield return`を用いて一定秒数ごとにエフェクトを繰り返すようになってます。
弾の始点と弾のベクトルを元に`ray`を飛ばし、VFX Graphに値を返すようにすることで疑似的に当たり判定を再現しました。

<details><summary> サンプルコード </summary>

```BulletVFX.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.VFX;

/// <summary>
/// 一定時間ごとにBulletを撃つMonoBehaviourクラス
/// </summary>
public class BulletVFX : MonoBehaviour
{
    [SerializeField] private VisualEffect _visualEffect; // 弾VisualEffect
    [SerializeField] private Transform BulletTarget; // 弾が狙い撃ちする対象
    [SerializeField] private float interval = 4f; // 弾を撃つ間隔

    //Interval秒感覚でエフェクトを繰り返す
    private IEnumerator Start()
    {
        while (true)
        {
            yield return new WaitForSeconds(interval);

            _visualEffect.SendEvent("OnPlay");
            Debug.Log("OnPlay");
        }
    }

    void Update()
    {
        // Ray情報の作成
        var origin = _visualEffect.GetVector3("SrcPos"); // 弾の始点
        var direction = (BulletTarget.position - origin).normalized; // 弾の向きベクトル
        var ray = new Ray(origin, direction);
        
        // Raycast実行
        if (Physics.Raycast(ray, out RaycastHit hit))
        {
            // Rayが当たった位置を弾の終点に設定
            _visualEffect.SetVector3("DstPos", hit.point);
        }
        else
        {
            // 弾の終点の設定
            _visualEffect.SetVector3("DstPos", BulletTarget.position);
        }

    }
}
```
</details>

## 実行結果
<iframe width="560" height="315" src="https://www.youtube.com/embed/If-AvL5F_2U" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

不可全ながらもVFX Graphで当たり判定っぽいものを実装できました。

## 問題点
無事にVFX Graphに当たり判定っぽいものを実装出来ましたが、いくつか問題点があります。
- スクリプトで制御しなければならないため、めんどくさい。
- 弾幕ゲーのようなものに実装するにはスクリプトやVFXが複雑になってしまう。
- 動いているものに対して、判定をとるのが難しい。
# まとめ
VFX Graphには衝突判定そのものを実装する方法はない。スクリプトで制御することで疑似的に再現することは可能だが、いくつかの問題点がある。なので、エフェクトで衝突判定を行いたければ、 __Particleシステム__ を利用するのがいい。

# 参考文献

https://qiita.com/tbpgr/items/989c6badefff69377da7

https://www.fenet.jp/dotnet/column/language/1612/

https://forum.unity.com/threads/vfx-graph-collision.813231/