週刊SleepNel新聞

SleepNel所属のぽうひろが日々の個人開発で気になったことを綴ります。

Stop the World! Unity 一部の物体だけ時を止めるScript

こんにちは、ぽうひろです。

オリンピック、盛り上がってますね。
個人的には卓球の福原愛ちゃんの表情が、ゾーンに入ってるなと思いまして、こりゃ覚醒したか・・・・と準決勝以降楽しみです。

さて今日はUnity C#で 一部の物体だけ時を止めるScriptについてご紹介したいと思います。

こちらを参考(というかほぼそのまま)にしております。
[Unity] ポーズ動作をTime.timeScale=0を使わずに実現する | ftvlog

ゲーム全体をポーズしたいとき、Time.timeScale=0としてゲームの進行時間を停止すれば簡単に実現できます。
しかし、アーバンナックルの必殺技を発動した時など、キャラクターの動きは一時停止させ、エフェクトなどはそのまま動かしたい、というような一部の物体を一時停止させたい場合には使えません。

このScriptを一時停止させたいオブジェクトにアタッチすることで、簡単に一時停止を実現することができます。
掲載元のブログScriptに少しだけnullチェックを追加してあります。

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;

public class Pauser : MonoBehaviour {

  static List<Pauser> targets = new List<Pauser>();	// ポーズ対象のスクリプト
  Behaviour[] pauseBehavs = null;	// ポーズ対象のコンポーネント

  // 初期化
  void Start() {
    // ポーズ対象に追加する
    targets.Add(this);
  }

  // 破棄されるとき
  void OnDestory() {
    // ポーズ対象から除外する
    targets.Remove(this);
  }

  // ポーズされたとき
  void OnPause() {
    if ( pauseBehavs != null ) {
      return;
    }

    // 有効なBehaviourを取得
    pauseBehavs = Array.FindAll(GetComponentsInChildren<Behaviour>(), (obj) => { 
    if(obj == null){
      return false;
    }
    return obj.enabled; });

    foreach ( var com in pauseBehavs ) {
      com.enabled = false;
    }
  }

  // ポーズ解除されたとき
  void OnResume() {
    if ( pauseBehavs == null ) {
      return;
    }

    // ポーズ前の状態にBehaviourの有効状態を復元
    foreach ( var com in pauseBehavs ) {
      com.enabled = true;
    }
    pauseBehavs = null;
  }

  // ポーズ
  public static void Pause() {
    foreach ( Pauser obj in GameObject.FindObjectsOfType<Pauser>() ) {
      Debug.Log (obj.gameObject.name);
      if (obj != null) {
        obj.OnPause ();
      }
    }
  }

  // ポーズ解除
  public static void Resume() {
    foreach ( var obj in targets ) {
      obj.OnResume();
    }
  }
}

このScriptを一時停止したいオブジェクトにアタッチします。
今回はプレイヤーにアタッチしてみました。
f:id:pouhiroshi:20160810062743p:plain:w300

Pauser.csがアタッチされている物体を一時停止させる場合はPauser.Pause();
再開させる場合はPauser.Resume();を呼び出せばOKです。

以下、実装例です。
必殺技を発動した時に、一時停止。
必殺技の名前をカットインさせ、一秒後に再開させます。

Pauser.Pause ();
//技タイトルカットイン
ShowSpTitle(sp.spNo);
//1秒後に再開させる
Timer timer = new Timer ();
timer.Start (1f, 1f);
timer.Finished += delegate() {
	Pauser.Resume ();
}

実行結果はこちらです!
f:id:pouhiroshi:20160810063646g:plain
必殺技を発動した後、キャラクターの動きがピタアっと止まってますね!いい感じです!

キャラの動きを止めた状態で、カメラをキャラクターの周りを一周させる!
なんていう映画のようなエフェクトも作れそうですね!

なお、こちらのスクリプトはRigidBodyの停止には対応していないとのことで、
完全対応版はこちらをご覧になると良いと思います。
[Unity] ポーズ動作をTime.timeScale=0を使わずに実現する(その2) | ftvlog


それではまた!!