C#でゲームの進行状況(キャラクターのHP低下、衝突位置、呪文のチャージ完了など)を検知し、それに応じてVFX Graphのエフェクトのスピードや発光色、放出量を動的にコントロールする処理は、ゲーム開発における演出の基本です。しかし、スクリプトに正しいコードを書いたはずなのにエフェクトが一切無反応というトラブルは、非常に多くの現場で頻発します。本記事では、この通信不通バグのメカニズムを『オフィスの内線つなぎ忘れ』の例え話を交えて分かりやすく解説し、正しく動かすための確認手順と、高効率な最適化コードを提示します。

1. 例え話で理解する:『受付での内線登録漏れとスペルミス』

このC#からVFXへの値が届かないバグを直感的に理解するために、『オフィスの外部取引先から社内の担当者へ電話をかけるプロセス』を例えに考えてみましょう。

あなたが取引先(C#スクリプト)として、ある会社(VFX Graph)にいる『色変え担当(プロパティ)』に電話をかけて『色を赤に変えてくれ(SetVector4)』と指示を出したいとします。しかし、会社の受付(VFXのBlackboard設定)で、その担当者が外部からの直通連絡を受け付けるための『内線公開設定(Exposed)』がOFFになっていました。さらに、あなたが呼び出そうとした名前のスペル(C#の指定名)と、受付の名簿に登録されている担当者の『正式な本名(Reference Name)』が一致しておらず、あだ名(Display Name)で呼び出そうとしてしまいました。

受付は『そんな内線番号および名前の担当者は社内に登録されていません』と静かに電話を切り、この命令を完全に握り潰します。そして、オフィスの外にいるあなたには何のエラー通知も届かないため、あなたは『命令は正常に伝わったはずだ』と思い込み、社内では担当者が何もしないまま初期設定(Default Value)の作業を繰り返してしまうのです。

このすれ違いが、『Exposed公開漏れ』と『Reference Nameの不一致バグ』の真相です。VFX Graphは、安全のため外部(C#)に明示的に公開された変数しか書き換えを許可しません。また、識別には表示上の名前ではなく、システム用の内部名前を厳密に使用します。これらがずれていると、Unityは警告エラーすら吐かずに処理をスルー(無視)してしまいます。

2. 解決策A:BlackboardでのExposedチェックとReference Nameの同期

このバグを解決するには、VFX Graphアセット側の設定を開き、内線の公開設定と名簿登録を正しく同期させます。

設定手順:

  1. 対象のVFX Graphアセットを開きます。
  2. エディタ左上にある『Blackboard』という変数リストパネルを確認します。もし表示されていない場合は、メニューバーの『Blackboard』ボタンをオンにします。
  3. C#から変更したい変数の左端を確認します。丸いチェックマークマーク(Exposed)が灰色(非公開)になっている場合は、これをクリックして**緑色の点灯状態(公開/Exposed)**にします。
  4. その変数を選択し、インスペクターウィンドウのプロパティを確認します。
  5. Reference』という項目に書かれている名前(例: `_BaseColor` ではなく `BaseColor` など)を確認し、大文字小文字、アンダースコア(`_`)の有無などを正確にメモします。
  6. C#スクリプト側で値を設定する際、文字列引数にこの『Reference』の名前を寸分狂わず入力します。

※よくあるミスとして、Blackboard上の表示名である『Display Name』(例: `Base Color` ※スペースあり)でC#からアクセスしようとすることがありますが、これは動作しません。必ず『Reference』に入力されている名前に統一してください。

3. 解決策B:ハッシュIDを用いた高速なスクリプト実装(プロ用最適化)

C#から毎フレーム(`Update` 内などで)文字列を使用して `vfx.SetFloat("MyParameter", value)` を呼び出すと、Unityは内部的に毎フレーム文字列検索を実行するため、CPU負荷(GC Alloc)が発生し、塵も積もればフレームレート低下に繋がります。

実務では、文字列検索を回避するため、事前に名前をハッシュ値(`int`)に変換しておき、ID指定で値を渡すのがプロフェッショナルな最適化手法です。

using UnityEngine;
using UnityEngine.VFX;

[RequireComponent(typeof(VisualEffect))]
public class VfxParameterController : MonoBehaviour
{
    private VisualEffect vfx;
    private float currentCharge = 0f;

    // 1. 静的ハッシュIDをキャッシュする変数を用意 (文字列参照を排除する)
    private static readonly int ChargeAmountID = Shader.PropertyToID("ChargeAmount");
    private static readonly int CoreColorID = Shader.PropertyToID("CoreColor");

    void Start()
    {
        vfx = GetComponent<VisualEffect>();
    }

    void Update()
    {\
        currentCharge += Time.deltaTime * 0.5f;
        if (currentCharge > 1.0f) currentCharge = 0f;

        if (vfx != null)
        {
            // 2. キャッシュした整数型(int)のIDを使用してパラメータをセットする
            // これにより、毎フレームの文字列検索オーバーヘッドとメモリ確保がゼロになります
            vfx.SetFloat(ChargeAmountID, currentCharge);
            vfx.SetVector4(CoreColorID, Color.Lerp(Color.blue, Color.red, currentCharge));
        }
    }
}

このコード構成を徹底することで、C#からの値の反映が100%保証されるだけでなく、毎フレーム実行してもガベージコレクションを一切発生させない、極めて軽量で滑らかな演出コントロールが可能になります。