Unity5.3のパーティクルで遊んでみる

この記事はUnityアドベントカレンダー12月25日分の記事です。

前日の記事はtnayukiさんの「宴のカスタムコマンド作成について」です。


Unity5.3になってParticle SysytemのEmitterの形状にSkinned Meshが利用できるようになったということでそれについての記事を書こうと思ったが、なんとバグがあって利用できない(5.3.1p1で未解決)ので、Unity5.3になってスクリプトからアクセスできるようになったParticle Systemのプロパティについて書くことにした。以下が5.3のParticle Systemの変数の一覧である。New!!と書かれているのが新しく追加された変数である。

collision New!! Access the particle system collision module.
colorBySpeed New!! Access the particle system color by lifetime module.
colorOverLifetime New!! Access the particle system color over lifetime module.
duration The duration of the particle system in seconds (Read Only).
emission Access the particle system emission module.
externalForces New!! Access the particle system external forces module.
forceOverLifetime New!! Access the particle system force over lifetime module.
gravityModifier Scale being applied to the gravity defined by Physics.gravity.
inheritVelocity New!! Access the particle system velocity inheritance module.
isPaused Is the particle system paused right now ?
isPlaying Is the particle system playing right now ?
isStopped Is the particle system stopped right now ?
limitVelocityOverLifetime New!! Access the particle system limit velocity over lifetime module.
loop Is the particle system looping?
maxParticles New!! The maximum number of particles to emit.
particleCount New!! The current number of particles (Read Only).
playbackSpeed The playback speed of the particle system. 1 is normal playback speed.
playOnAwake If set to true, the particle system will automatically start playing on startup.
randomSeed Random seed used for the particle system emission. If set to 0, it will be assigned a random value on awake.
rotationBySpeed New!! Access the particle system rotation by speed module.
rotationOverLifetime New!! Access the particle system rotation over lifetime module.
scalingMode New!! The scaling mode applied to particle sizes and positions.
shape New!! Access the particle system shape module.
simulationSpace New!! This selects the space in which to simulate particles. It can be either world or local space.
sizeBySpeed New!! Access the particle system size by speed module.
sizeOverLifetime New!! Access the particle system size over lifetime module.
startColor The initial color of particles when emitted.
startDelay Start delay in seconds.
startLifetime The total lifetime in seconds that particles will have when emitted. When using curves, this values acts as a scale on the curve. This value is set in the particle when it is create by the particle system.
startRotation The initial rotation of particles when emitted. When using curves, this values acts as a scale on the curve.
startRotation3D New!! The initial 3D rotation of particles when emitted. When using curves, this values acts as a scale on the curves.
startSize The initial size of particles when emitted. When using curves, this values acts as a scale on the curve.
startSpeed The initial speed of particles when emitted. When using curves, this values acts as a scale on the curve.
subEmitters New!! Access the particle system sub emitters module.
textureSheetAnimation New!! Access the particle system texture sheet animation module.
time Playback position in seconds.
velocityOverLifetime New!! Access the particle system velocity over lifetime module.

全てについて触れる時間はないので、効果が見て確認しやすいcolorOverLifeTimeを使って簡単なプログラムを組んでみようと思う。

まず最初に断っておきたいのだが、全てにおいてこのようなプロパティをスクリプトでコントロールすることを推奨しない。何故なら「コードを書かずにエディターだけでゲームが作れる」のが最も理想的なUnityの利用方法であって、原則としてコードを書かない手段を優先的に探したほうが良い。今回紹介するランタイムでパーティクルの色を変える方法は色の設定だけ違うprefabを複数用意すれば同じことはできる。しかし、いずれにせよコンポーネントを1つ作るならAssetsフォルダ以下のprefabの数も、一つのシーンにロードするprefabの数も少ない方が良い。そういうわけで1つのParticle SystemのcolorOverLifeTimeを次々と変える方法について紹介する。

interactiveParticleInspector

まずは、色を変更するためのコンポーネントを1つ用意する。ここではInteractiveParticleSystemと名付けた。今回はそこまで紹介できないが、ゲームプレイの展開に合わせてパーティクルの色やサイズを変化させることを想定したためにそのような名称にした。

Gradientの配列でParticleの色の設定を複数用意する。今回はColor Change Timeが経過するとランダムでそれらの設定のどれかに変更するというのを試して見る。

    public ParticleSystem particle;
    public Gradient[] colorOverLifeTime;
    public bool randomColor = false;
    public float colorChangeTime;
    float colTime;

    void Update () {
        if(particle != null && randomColor == true){
            RandomColor();
        }
    }

    public void RandomColor(){
        colTime+=Time.deltaTime;
        if(colTime >= colorChangeTime){
            colTime = 0;
            int i = Random.Range(0,colorOverLifeTime.Length);
            var col = particle.colorOverLifetime;
            col.color = new ParticleSystem.MinMaxGradient(colorOverLifeTime[i]);
        }
    }

実行結果は以下のようになる。左手首のパーティクルをこのInteractiveParticleSystemが管理している。

particleColorChange1

放出済みのパーティクルまで瞬間的に色が変わってしまっている。この表現が適している時もあるが、放出済みのパーティクルについては色を変えずに、新たに放出されるパーティクルだけ色を変えたい。

そこで、1つのParticleSystemのcolorOverLifetimeを変更するのではなく、新たに色を設定しなおしたParticleSystemを生成して、時間差で古いParticleSystemを消すことにした。複数のprefabを用意すれば同じことができると書いたのはこのことである。

   public void RandomColor(){
     colTime+=Time.deltaTime;
     if(colTime >= colorChangeTime){
        colTime = 0;
        int i = Random.Range(0,colorOverLifeTime.Length);
        StartCoroutine(ChangeColor(colorOverLifeTime[i]));
      }
    }

  IEnumerator ChangeColor(Gradient gradient){
     //既存のパーティクルをクローン
     GameObject newParticleObj = Object.Instantiate(particle.gameObject);
     newParticleObj.transform.parent = transform;
     newParticleObj.transform.localPosition = Vector3.zero;
     ParticleSystem newParticleSystem = newParticleObj.GetComponent<ParticleSystem>();
     ParticleSystem.ColorOverLifetimeModule col = newParticleSystem.colorOverLifetime;
     col.color = new ParticleSystem.MinMaxGradient(gradient);
        //既存のパーティクルを削除
     StartCoroutine(DestroyOldParticleSystem(particle));
     particle = newParticleSystem;
     yield return true;
  }

 IEnumerator DestroyOldParticleSystem(ParticleSystem oldParticleSystem){
     yield return new WaitForSeconds(1.0F);
     ParticleSystem.EmissionModule emit = oldParticleSystem.emission;
     //emissionを停止
     emit.enabled = false;
     float duration = oldParticleSystem.duration;
     //放出済みのパーティクルが消えるまで待つ
     yield return new WaitForSeconds(duration);
     Destroy(oldParticleSystem.gameObject);
     yield return true;
 }

すると以下のように自然に色がグラデーションしていく。

particleColorChange2

どちらかというと、先に挙げた放出済みのパーティクルも含めて色を変える方が以前はできなかったことであり、今回のアップデートの恩恵を受けているのだが、いずれにせよcolorOverLifetimeにアクセスできるようになったことにより、色については自由にどうとでも変化させられるようになった。

今回紹介したのは非常に初歩的な手法であるが、スクリプトからいずれの変数にもアクセスできるようになったことで、一段とパーティクルの表現力が増したと思う。

パーティクルを使った表現はモデリングやテクスチャと違って、絵が描けない人でも工夫次第でゲームのグラフィックスの品質をあげることできるし、アニメーションち違ってUnityの中だけで作業が完結する。そしてシェーダーほどプログラミングは難しくない。GDH2030のように予算も時間も限られたプロジェクトにおいては大変重宝するといえる。ちなみに画像のキャラクターはGDH2030に登場するオリジナルキャラクターである。今回はアドベントカレンダーということで初めてUnityに関する記事を書いたが、今後はこのキャラクターの紹介も兼ねてこのような記事を書いていくかもしれない。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

次のHTML タグと属性が使えます: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>