読者です 読者をやめる 読者になる 読者になる

稲枝の押入れ

いなえが適当なことを書いては、しまっておく場所

Rigidbodyをスリープモードにしない方法

Unity C# プログラミング

導入

Rigidbodyとは

UnityにはRigidbodyと言われる物理演算等をしてくれるコンポーネントが有ります。

Unityの物理演算を利用しなくとも、Unityの当たり判定機能を使う為にもこのRigidbodyコンポーネントを少なくとも片方のオブジェクトが持っている必要があるので、Unityを使ったことがある人はおよそほとんどが使ったことがあるであろうコンポーネントです。

Sleepという機能

普通に使っている分には非常に便利なのですが、ちょっとした落とし穴があります。それはスリープ(Sleep)という機能です。

リジッドボディが決められた最低直線、または、回転スピードよりも動きが遅いとき、物理エンジンはそれが休止していると仮定します。これが発生すると、ゲームオブジェクトは衝突されるか力が与えられない限り再び動きません。そのため、それは「スリープ」モードに設定されます。この最適化により、次にリジッドボディが「起きる」 (これは、再動作のこと) までプロセッサーの時間が更新に使われることがありません。 公式より引用

つまり、Rigidbodyは決められた速度(速度、というのは厳密ではない)よりも遅く移動している等の場合、処理軽減のためスリープモードとなり、力を与えられない限り物理演算を行わず動かなくなります

一見それほど問題はなさそうですが、力を与えられない変更、例えばそのスリープとなっているオブジェクトの下の床が消えたといった場合に、オブジェクトは物理演算を行わないのでそのまま宙に浮いたままになったりします。

問題

さて、今回は「OnCollisionStayでプレイヤーの接地判定を取り、その判定がある時だけジャンプが可能になる」という実装をしようとしていたのですが、プレイヤーが止まるとスリープになってしまいOnCollisionStayが呼ばれなくてうまくいきませんでした。じゃあスリープしないようにしよう!となったわけです。

スリープをしないようにしよう!

SleepingModeがない!!

さてここまではよくある話なのですが、僕はここで徐にインスペクタでSleepingMode(スリープする条件を指定する項目)をNever Sleep(スリープを無効にする)にしようとしました。処理が重くなるので本来推奨されないのですが、面倒なのでそもそもスリープしなくしてしまいたかったのです。

しかし、インスペクタを見てもSleepingModeがありません。

以前に使った事があったので(白目)おかしいなと思いながら調べてみるとどうやらRigidbodyにそんなものはないらしい。

え?うそ?前使ったよ?バージョンアップでなくなったの?と思って「Rigidbody never sleep」とかで検索。

結論から言うとRigidbodyにはSleepingModeはなく、Rigidbody2Dのみにあるということらしいです。

なんじゃそりゃ、という感じなのですが、3Dの処理はやはり大変なので簡単にNever Sleepにはされたくないんでしょうかね。

それでもNever Sleepにしたい!!

でも僕はSleepしないようにしたい…

調べるとWakeup関数(強制的にスリープモードを解除する関数)を毎フレーム呼んだり、IsSleeping関数(スリープモードかどうかを返す関数)で判定して、スリープモードの時はWakeUp関数を呼んだりしてるのを見つけたんですが、毎フレーム呼んだりするのはなんとなく抵抗が…

もう少しスマートに出来ないかなと思って公式マニュアルをみていた所、RigidbodysleepThresholdというメンバ変数を発見。

スリープをするのは決められた速度(上述の通り厳密ではない)よりも遅く移動している時と言いましたが、大雑把に言うとこの変数はそのスリープをする決められた速度を規定する変数です。

よって例えば、sleepThresholdを-1とかにすると、「速度が-1より小さくなった時にスリープする」=「速度は0以上なのでスリープしない」となって、Start()内で一回rigid_body.sleepThreshold=-1;みたいな感じで書いてやればずっとスリープしなくなるわけです。

取り敢えずこんな方法でスリープを回避できるようにはなったんですが、急に思いついた方法(かつ正確に理解できているかわからない)なのでどういう副作用があるかわからないというのと、スリープを切るともちろん処理は重くなるので、使用する場合は自己責任かつあまり使わないようにした方がいいかな、と思います。

面倒なのでプレイヤーだけなら大丈夫かな?とか思って僕は使っちゃいますが。