Cooooding!!

Unity(C#)を使ったゲーム開発関連Tipsなど

FreezeをOnにしたRigidbodyを積み上げると勝手に動くことがある問題を解決する【Unity】

概要

Rigidbodyの動きを制限して2Dゲームのような動きをさせようと検証していたらRigidbodyが不自然な動きをすることがあったので調査してみました。

問題の再現方法

  1. 新規3Dプロジェクトを作る
  2. Terrainを作る
    1. カメラとの位置関係を調整するために座標を(-250,0,-250)にする
    2. 白いままだとわかりにくいので適当なTextureで色を付ける
  3. 落下させるprefabを作る
    1. Cubeを新規作成
    2. Rigidbodyを付ける
    3. ConstraintsをいくつかOnにする
      1. Freeze PositionのZをOn
      2. Freeze RotationのX, YをOn
    4. prefabとして保存
  4. 作ったprefabを、落下したら縦に積み重なるようにいくつか配置
    • 位置や個数によって再現するかどうかが変わる
    • 今回は5つ置いて、それぞれ高さを1, 4, 7, 10, 14にした

Rigidbodyを付けてFreezeをいくつかOnにしたものを、落下したら積みあがるように配置

プレビューするとCubeが勝手に動くのが見えます。

Freezeを全てOffにするとこの問題は発生しなくなります。


対策

1. Default Solver Iterationsを大きくする

Default Solver Iterationsは計算回数を増やすことで精度を高くするもののようです。最大値は255です。この値を大きくするほど不自然な動きをすることが無くなっていきました。

f:id:nyama41:20190616153740p:plain

この値を変更して解決するのでこの問題はバグではなく計算誤差によるものなのかもしれません。

ちなみに、マニュアルを読む限りこの値を大きくすると処理コストが増えそうな気がするのですが、Profilerで見た限り明らかな処理の増加は見られませんでした。わからなかっただけで微妙に増えているのかもしれません。
→ Rigidbodyの数を300まで増やしてRigidbody同士が接触しやすい状態にして計測したらDefault Solver Iterationsが大きい方が明らかに処理が増えていました。(2019/06/17 21:00修正)

2. Sleep Thresholdを大きくする

Sleep Thresholdを増やしても問題が発生しなくなりました。Rigidbodyは運動エネルギーが小さくなったときに動きを止めSleep状態になります。この値を増やすことで勝手に動き出す前にSleep状態に入ったのだと思います。

f:id:nyama41:20190616153757p:plain

ただ、この値を増やしすぎると不自然な状態で動きが止まってしまうこともありました。処理負荷の面では良いですが調整に苦労するかもしれません。

試したけどダメだったこと

ちなみに、以下の変更も試してみましたが問題は解決しませんでした。

  • PhysicsMaterialを付けてFrictionの値を大きくしてもダメ
  • Enable Adaptive ForceをOnにしてもダメ
  • RigidbodyのIterpolateを変更してもダメ
  • RigidbodyのCollision Detectionを変更してもダメ
  • Unity 2019.1.2f1にしてもダメ
  • 2Dでプロジェクトを作ってもダメ

環境

  • Unity 2018.4.0f1