質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.12%

パーティクルを一瞬だけ表示させたい。

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 7,144

tkmnusr

score 259

前提・実現したいこと

キー入力とUpdateとLateUpdateを利用して、パーティクルを一瞬だけ表示したいと考えています。

仕様:
Fキーを押した瞬間だけ、指定した再生位置でパーティクルを表示する。それ以外の時はパーティクルは非表示。

試したこと

以下のようなコードを組んでゲームを実行してみましたが、意図通りの結果になりません。

void Start(){
        pObject = GameObject.Find ("Particle System");
        particle = pObject.GetComponent<ParticleSystem> ();

        particle.Simulate(0.0f,true,true);
        particle.Stop ();
    }

    void Update(){
        if (Input.GetKeyDown (KeyCode.F)) {
            if (particle.isStopped || particle.isPaused) {
                particle.Simulate(3.0f,true,true);
                particle.Play ();
                Debug.Log ("A");
            }
        }
    }

    void LateUpdate(){
        if (particle.isPlaying) {
            particle.Stop ();
            Debug.Log ("B");
        }
    }

発生している問題・エラーメッセージ

最初にFキーを押すとパーティクルは表示されて消えるが、その後、何度かFキーを押してみると、
パーティクルが表示される時と表示されない時がある。
また、パーティクルが表示されても、一瞬だけ表示しているようには見えず、表示されている時間が少し長い気がする。

また、コードでログを取ってみると、パーティクルが表示されていないときでも、「B」の出力が出続けます。
それならば、同じif文内の「particle.Stop();」が効いて、次のLateUpdateでは「if(particle.isPlaying)」の
if文に引っ掛からないはずなのに、何故か、そのif文に引っ掛かって「B」が連続して出力されます。
この辺りの挙動がわからないです。

キー入力でパーティクルを一瞬だけ表示する方法ならば、他にも方法があるのかもしれないですが、現状から、次の2点に関して教えていただきたいです。

・今回のソースコードでうまくいかない原因。
 特に、「if(particle.isPlaying)」のif文に引っかかり続けているにも関わらず
 「particle.Stop();」が効かない理由。

・UpdateとLateUpdateを利用して、キー入力でパーティクルを一瞬表示させる方法。
 (今回のコードの修正方法。)

しかし、UpdateとLateUpdateを使う仕様自体がbad codeであるのならば、代替の方法を教えて頂きたいです。

ご教授のほどよろしくお願いします。

追記①

ご回答ありがとうございます。追記しました。

//ここでパーティクルが停止される時間を指定
    float particleDelayTime = .2f;

    void Awake()
    {
        pObject = GameObject.Find ("Particle System");
        particle = pObject.GetComponent<ParticleSystem> ();
        particle.gameObject.SetActive(false);
    }

    void Update()
    {
        if (Input.GetKeyDown ("f") && particle.isStopped) {
            particle.gameObject.SetActive (true);
            particle.Simulate (4.0f, true, true);  //追記。
            particle.Play ();  //追記。
            StartCoroutine (delay (particleDelayTime, () => {
                particle.gameObject.SetActive (false);
            }));
            //for Debug
            Debug.Log ("A");
        }
    }

    IEnumerator delay(float waitTime, UnityAction action)
    {
        yield return new WaitForSeconds(waitTime);
        action();
    }
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+1

[追記]ご指摘いただきました「指定した再生位置でパーティクルを表示する」という内容を踏まえてソースを少し修正しました。

Fキーを押した瞬間だけ、パーティクルを表示する。それ以外の時はパーティクルは非表示。

それだけでよければ以下コードでいけます。適当なオブジェクトに以下コードをアタッチしてインスペクタ上から該当パーティクルを指定してください。

※パーティクルが設定されたオブジェクトに以下スクリプトをアタッチしても動かないと思うので、パーティクルが指定されたオブジェクト以外にアタッチしてください。

実装のポイント

パーティクルシステムをplay / stopしなくても、オブジェクトを非表示にすると勝手に止まります。その状態で再表示すると勝手に始まります。それを利用した実装になります。

using UnityEngine;
using System.Collections;
using UnityEngine.Events;

public class particleForFkey : MonoBehaviour {

    //他で使うかもしれないのでParticleSystemを指定してますが以下コードで問題なければGameObjectに書き直してもいいです。
    [SerializeField]
    ParticleSystem pObject;

    //ここでパーティクルが停止される時間を指定
    float particleDelayTime = .2f;

    void Awake()
    {
        pObject.gameObject.SetActive(false);
    }

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.F) && pObject.isStopped){
            pObject.gameObject.SetActive(true);
            pObject.Simulate(4.0f, true, false); //追記
            pObject.Play(); //追記
            StartCoroutine(delay(particleDelayTime,()=>{
                pObject.gameObject.SetActive(false);
            }));
            //for Debug
            Debug.Log ("A");
        }
    }

    IEnumerator delay(float waitTime,UnityAction action)
    {
        yield return new WaitForSeconds(waitTime);
        action();
    }
}

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/09/30 00:24 編集

    ご回答ありがとうございます。ご指摘ありがとうございます。
    早速、FindGameObjectWithTagを使ってみました。
    さらに質問で恐縮ですが、これの応用として、パーティクルの連射表示みたいなことをしたいと思っています。
    Fキーを押した瞬間だけの表示をやめて、Fキーを押しっぱなしにしている間、パーティクルの一瞬表示が、連続的に起こるものです(particleDelayTimeを短めにして、パーティクルを高速点滅させるイメージです)。
    これは、コードを「Input.GetKeyDown」から「Input.GetKey」に変えるだけの修正で大丈夫ですか?
    追記②に詳細を書きました。
    今は安定していますが、最初に何回かテストしたところ、パソコンの性能のせいなのか、
    particleDelayTimeが.01fなど短めだと、Fキー押しっぱなしの間、周期的に点滅が止まる挙動がありました。(しかし、今テストしてる限り、同じコードなのにそれが解消されてきました。)
    それとも、他にもコードで修正すべき点がありますか?
    また、パーティクルはいつも同じ再生位置から表示したいと思っているので、その場合は
    Simulateの第3引数をtrueにすれば大丈夫ですか?

    キャンセル

  • 2016/09/30 22:44

    お手数ですが、内容が変わってきているので一度こちらを閉じて再質問していただいても良いですか?あと、しばらく触れなそうなので返答遅れます。

    キャンセル

  • 2016/09/30 22:47

    ご回答ありがとうございます。いろいろ質問してしまってすみません。
    ご教授くださりありがとうございました。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.12%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる