Unityにおける各コンポーネントはスクリプトも含めて、enabled変数(bool)でその有効無効(アクティブ状態)を設定できます。
機能を止めたい時はenabled = false;とやれば止まりますし、そのゲームオブジェクト全体を停止させたい時はSetActiveを使います。
ただ今回、ある疑問が浮上しまして、それはスクリプトを無効にしても、OnTriggerEnterによる処理がなされるんじゃないか、というものです。
SetActiveとEnabled
単純にゲームオブジェクトを消したい時、Destroyを使うと負担が大きく、特にWebGLだとIncremental GCが使えないので、パフォーマンスに露骨に影響が出ます。なので、DestroyよりはSetActiveが推奨されます。
しかし、そのSetActiveでも動作に影響が出てるようなので、コンポーネントごとに無効にしてみようと思い、スクリプトの無効化を試していたら、今回のようになぜかOnTriggerEnter内の処理が実行される、という現象に出くわしました。
というわけで、スクリプト無効化とOnEnterTriggerの関係性について調べてみました。トリガーにプレイヤーを突っ込ませて、OnTriggerEnterでそのスクリプトを無効にするというテストです。
スクリプト無効化を貫通!
結論から書くと、本当にびっくりしたんですが、スクリプト無効化しても、OnTriggerEnterは影響を受けないということが判明しました!(実はパブリック関数なども外部から呼ばれると実行されるようです)
スクリプトを停止しても影響あるのはUpdateやFixedUpdateなどであり、OnTriggerEnter, Stay, Exitは無効とはならず、トリガーからのイベントが来れば実行されます。
なので、トリガーのコンポーネントである、Colliderコンポーネントを無効化しなければいけないのですが、じゃあSetActive(false)で良いじゃんという話ではあります。(しかし、パフォーマンスに負荷が生じます)
今回のテストはUpdate関数で、経過時間を加算していき、トリガー内に入るとこのスクリプトを無効にする(this).enabled = false;というものです。
スクリプトが無効化される、ということはその時点で経過時間はストップするということ。つまり、スクリプトが止まってもOnTriggerEnterの処理が起動するということは、停止した時間が何度もコンソールに出力されることになります。
実際にそうなりました。今回のシーンには三つのトリガーを用意しましたが、入った時点で時間の加算が止まり、出入りするごとにその時間が出力されるので、それぞれ五回分ログ出力されています。
調べていく中でSetActive重いよ!という記事も見つけました。OnTriggerEnterへの言及はありませんでしたが、いろいろと参考になりました。
今回は本当にビックリしました。スクリプト無効化してるのに動いちゃうのか・・・という感じです。