Unity

【Unity】パーティクルで色(startColor)をスクリプトで変更するときに見るポイント

どうも、コニーです!

Unityでエフェクトを使う際、パーティクルを使っている方がほとんどだと思います

そして実際にゲームなどで使用する際は
「スクリプト(コード)から色を指定したい!!」
という場面が結構ありますよね!!

自分もそういった場面があり、
「色変更?色情報渡すだけやろ?ちょろいっしょ(笑)」
と思っていたのですが意外と実装に詰まっちゃいました…

同じ壁にぶち当たっている同志も多いでしょう

そこでこの記事では色(特にstartColor)をスクリプトで変更する方法と、
その際にハマりやすい落とし穴をまとめて紹介します

【結論】startColorを変更するスクリプト

まずは実際に使う際のコードをドン!!

public class ParticleController : MonoBehaviour
{
    [SerializeField] ParticleSystem particle;//パーティクルを参照
    [SerializeField] Color color;//インスペクターから色を指定する

    private void Start()
    {
        //mainをローカル変数に入れる(直接は値を代入出来ない)
        //MinMaxGradientという型に変換

        var main = particle.main;
        main.startColor = new ParticleSystem.MinMaxGradient(color);
    }
}

前提

いろいろ紹介する前に今回の前提をいくつか説明します!!

  1. 今回紹介するコードはパーティクルに直接アタッチするのではなく、
    コントローラー用オブジェクトにつける
  2. インスペクターから色を指定する

この2点だけです!

パーティクルに直接付けるやり方でも良いっちゃ良いんですけど、
実際のプロジェクトだとこういうやり方の方が一般的かなと思うのでそっちにします
(画像参照)

パーティクルのスクリプト設定

…そしてこのやり方だからこそ、次みたいな落とし穴があるんですけどね(笑)

【パーティクルが表示されない場合】Colorのデフォルトアルファ値(透明度)は0

親愛なる
『スクリプトでstartColorは指定できるしパーティクルは出てるけど、なんか透明になっている人』

colorデフォルトのアルファ値

Colorのデフォルト値の透明度(アルファ値)は0なので、
特に弄らなければずっと透明のままです…!!

なんでやねん!!!!!!!!!(台パン)

ログとかでも中々発見できず沼にハマる方もいると思うので共有です

 

…私?ハマらなければ書かないですよ

非推奨という表示が出るやり方

まずは一番パッと思いつくやり方で書いた場合、
次のようなコードになるのではないでしょうか?

public class ParticleController : MonoBehaviour
{
    [SerializeField] ParticleSystem particle;
    [SerializeField] Color color;

    private void Start()
    {
        //非推奨のやり方と表示が出る
        particle.startColor = color;
    }
}

 

これでも一応色は変えられるのですが、非推奨って言われると
「じゃあ推奨ってなんだよ」
ってなりますよね(笑)

実は今は直接参照するやり方から、
mainモジュール(startColorとか変えられる箇所をモジュールと呼びます)から設定するやり方が推奨されています

次の章で詳しいやり方を解説します

色だけなら直接書き換えできるのですが、mainモジュールの他の値には直接参照できないものもあるので「じゃあ全部mainモジュールから参照しよう」ってノリです

mainモジュールから変更するときの落とし穴

mainモジュールはParticleSystemから簡単に参照できるので、
次のように書いてみます

public class ParticleController : MonoBehaviour
{
    [SerializeField] ParticleSystem particle;
    [SerializeField] Color color;

    private void Start()
    {
        //mainモジュールを参照してColorを渡すとエラー
        particle.main.startColor = color;
    }
}

「なるほどね!ParticleSystem.mainで参照するのか!ハイ、勝ち―!!」

….ブーーーーーーー!!!!!!
残念!!こちらエラーでぇっす!!!

…ごめんなさい(笑)
一見正しそうに見えるこのやり方も実は文法的にダメなんですよね~

実はmainの実装を見てみると、
「mainの値を取得することはできるけど、直接書き換えはできない」
というようになっています

mainモジュール

【オススメ】mainモジュールからstartColorを変更する

新しい値をモジュールに割り当てるには

  1. ローカル変数にmainを入れる
  2. ①の変数に新しい値を入れる

というやり方をしないといけません

実際のコードがこちらです

public class ParticleController : MonoBehaviour
{
    [SerializeField] ParticleSystem particle;//パーティクルを参照
    [SerializeField] Color color;//インスペクターから色を指定する

    private void Start()
    {
        //mainをローカル変数に入れる(直接は値を代入出来ない)
        //MinMaxGradientという型に変換

        var main = particle.main;
        main.startColor = new ParticleSystem.MinMaxGradient(color);
    }
}

 

var main = particle.main;
でmainモジュールをローカル変数に代入しています

さらにmainモジュールのstartColorは普通のColorではなく、
MinMaxGradientというグラデーションにも対応した型を使っています

なのでColorをそれように変更する処理も入れるとstartColorを変えることができます

【オススメ2】さらに丁寧に設定する書き方

MinMaxGradientとかいうよくわからんやつが出てきましたが、
これは「どんな色を使いますか?」という設定(ParticleSystemGradientMode)に合わせた色です

ParticleSystemGradientModeは
デフォルトでは単色(Color)ですが、グラデーション、ランダムな色など様々な色を表現できます

※startColorのこの箇所です

ParticleSystemGradientMode

それらの設定をしたい場合は下のコードをベースに、
設定を拡張していくとやりたい表現ができます!

public class ParticleController : MonoBehaviour
{
    [SerializeField] ParticleSystem particle;
    [SerializeField] Color color;

    private void Start()
    {
        //丁寧に書くやり方
        var main = particle.main;
        var gradientColor = new ParticleSystem.MinMaxGradient();

        //単色、グラデーション、ランダムなど5つのモードがある
        gradientColor.mode = ParticleSystemGradientMode.Color;
        gradientColor.color = color;//モードによって参照する値が異なる
        main.startColor = gradientColor;
    }
}