コライダーが重なったり、突き抜けたりしてしまう。そんな時。
はじめに
「動く物体が壁に設定したコライダーに埋まる!」「動く物体が壁を貫通してしまった・・。」という方に向けた記事です。私が2Dメインであるので、2Dでの対処法を書いていきます。もしかすると、3Dでも同様の方法で改善する場合があるかもしれません(。・ω・。)
対処法
その1
こちらは単純に処理回数を増やして改善する方法です。
Edit -> Project Setting -> Time を選択すると TimeManager が開きますので Fixed Timestep の値を変更します。この記事を書いた現在、0.0001~10の値を選択できます。この値はFixed Updateを実行する間隔ですので、値が小さいほど正しい動きをするようになります。しかし、値と物理演算を行う必要のある物体の数によっては負荷がとても大きくなってしまうことがあります。
その2
こちらは Rigidbody 2D の Collision Detection の機能を使用して改善する方法です。
Rigidbody 2D の項目の中に Collision Detection というものがあります。デフォルトでは Discrete となっているので Continuous に変更してください。
Continuous に設定するとぶつかる瞬間を計算で求めて、そこ以上には進まずに重なりやすり抜けを防止してくれます。ですが、こちらも Discrete と比較するとCPUの負荷が大きくなってしまいます。また、厳密には完璧な物理挙動ではないようです。
どちらを選ぶのか
個人的にですが、完璧に近い物理挙動を求める場合には1の方法を、完璧でないが違和感もないような挙動を求める時に2の方法を選択するようにしています。とは言っても、ゲーム内で完璧な物理挙動が必要な場面に出会ったことがないので2の方法だけでやっていますが…。
おわり
このどちらかの方法で埋まったりすり抜けたりする問題は解決できるはずです。3Dにも選択肢は3つありますが同じ機能が実装されているので是非使ってみてください。もしかすると、3Dバージョンも近いうちに書くかもしれません((φ(-ω-)
質問や間違っている箇所、追加情報があれば是非コメントをお願いします!
初心者の方や熟練者の方を問わずTwitterのフォローお待ちしています…(`・ω・´) Let’s Unity !
PhysicsMaterial2D についての豆知識(摩擦編)
はじめに
PhysicsMaterial2D の摩擦(Friction)についての検証を行ったので結果を記事にまとめます。この記事では前提条件として Physics2DSetting の DefaultMaterial は None であるとします。
謎
直方体Aと平たい板Bがどちらも Rigidbody2D と Collider2D をアタッチされている状態で存在しているとします。PhysicsMaterial2D をどのように扱うと、AをB上で運動させる際に生じる摩擦力にどのような影響を及ぼすのか様々なパターンでチェックして見ました。
確認する項目は以下の項目です。
- Rigidbody2D と Collider2D のどちらにアタッチするかで影響するのか?
- Rigidbody2D と Collider2D の両方にアタッチすると影響力が増すのか?
- A,Bの両方にアタッチしなければならないのか?それとも片方のみで良いのか?
- A,Bのそれぞれに異なった値の PhysicsMaterial2D をアタッチした場合、どちらが優先されるのか?
- A,Bのどちらにもアタッチしていない時でも摩擦が生じるがその時どのような値が設定されているのか?
これらを動いているAが止まるまでの移動距離を計測し、確認していきます。
検証結果
以下の表の○と×は PhysicsMaterial2D がそのコンポーネントにアタッチされているかどうかを表しています。また、Friction=1.0を設定しています。
この表から項目1,2,3が確認できます。
- Rigidbody2D と Collider2D のどちらにアタッチしても影響はありませんでした。
- Rigidbody2D と Collider2D の両方にアタッチしても、どちらか一方にアタッチしている時と変わりませんでした。
- 後でも述べますがFriction=1.0の今回であれば、A,Bのどちらにもアタッチした時の摩擦力はどちらか一方のみにアタッチした時の摩擦力を上回っています。
次に項目4についてですが、A,Bに設定したFrictionを掛け合わせたものが等しければ生じる摩擦力も等しいという事実が検証を行う中で確認できました。すなわち、どちらが優先ということはありません。
最後の項目5については、PhysicsMaterial2D がアタッチされていないオブジェクトにはFriction=0.4があらかじめ設定されていることが値を試行錯誤していく中で確認できました。
ここで項目3の説明に戻ります。Frictionを掛け合わせたものが等しければ生じる摩擦力も等しく、Friction=0.4があらかじめ設定されていることから、A,Bの両方にアタッチするかどうかはどの程度の強さの摩擦力が欲しいかによると言えます。
ごちゃごちゃしているのでまとめ直します。
まとめ
- Rigidbody2D と Collider2D のどちらにアタッチしても影響はありません
- Rigidbody2D と Collider2D の両方にアタッチしても、どちらか一方にアタッチしている時と変わりません
- 欲しい摩擦力による
- 優先は存在しません
- Friction=0.4
おわり
ゲーム制作中に「 Rigidbody2D と Collider2D のどっちにアタッチしたらいいんだ?どっちもか?」と悩んだので、ついでに気になっていた関係とともに検証しました( *`ω´)v
Friction=0.4で満足する動きをするのであればアタッチをしなくても良いのかアタッチだけでもすべきなのかをご存知の方は是非コメントをお願いします!
にしても説明が下手ですね…分かりづらい箇所や間違った内容があればコメントをお願いします!こう書けば分かりやすいよというアドバイスも絶賛募集中です(´・ω・`)
初心者の方や熟練者の方を問わずTwitterのフォローお待ちしています…(`・ω・´) Let’s Unity !
this と gameObject と this.gameObject の違いをまとめた
はじめに
this と gameObject と this.gameObject を感覚で使っていたので違いを調べたものをまとめておきます。違いがいまいち分からないって方の参考になれば・・(*・.・)ノ
何が違うのか
this
自分自身のインスタンスを指します。ゲームオブジェクトにアタッチされているスクリプト自身を指していると理解してください。
gameObject
スクリプトがアタッチされているゲームオブジェクトを指します。
this.gameObject
ゲームオブジェクトにアタッチされているスクリプトがアタッチされているゲームオブジェクト(呪文のようですが…)。すなわち、スクリプトがアタッチされているゲームオブジェクトを指します。
結局…
this と gameObject は別物ですが、gameObject とthis.gameObjectは同じものを指していると言うことです。
確認してみた
今回、ゲームオブジェクトobj_a,obj_b,obj_cのそれぞれにA,B,Cという名前のスクリプトをアタッチしてみました。AのスクリプトはDebug.Log(this)
を、BのスクリプトはDebug.Log(gameObject)
、CのスクリプトはDebug.Log(this.gameObject)
といった処理を記述しています。(分かりやすくなるようにA is ~
といったログを出しています)
その結果が以下の画像になります。
画像から、Aはobj_aにアタッチされているスクリプトを指しており、B,Cはそれぞれのゲームオブジェクトを指していることが確認できます。
ちょっと待てよ?
this.GetComponent<hoge> (); ・・・A this.gameObject.GetComponent<hoge> (); ・・・B
「上のコードはA,Bどちらも同じを動きをするから this と this.gameObject は同じなのでは?」と思った方はいませんか?思った方は少し長いですが以下を読むことをおススメします。
A,Bは正確に言うと常に同じものではありません。A,Bが同じ動きをするのは
MonoBehaviour を継承したクラス内のみなのです。なぜなら、GetComponent というメソッドが MonoBehaviour で実装されているからです。
つまり、MonoBehaviour を継承していなければ GetComponent メソッドは自分で実装していない限り存在していません。そのため、MonoBehaviour を継承していないクラス内ではAはエラーとなります。
Bは MonoBehaviour を継承しているかどうかに関わらずエラーは発生しません。なぜなら、this.gameObject の GameObject クラスは MonoBehaviour を継承したクラスになっているためです。
おわり
後半は長々しい説明になってしまいましたが、以上でまとめを終わります。
個人的な疑問なのですが、gameObject と this.gameObject が一緒という結果だったのですが、好きな方を使用してもいいんでしょうかね?(←調査中です)
何か間違っている内容や追加の情報がありましたらコメントをお願いします!
初心者の方や熟練者の方を問わずTwitterのフォローお待ちしています…(`・ω・´) Let’s Unity !
あるGameObjectから他のGameObject内の変数を読もうとしてハマった話
はじめに
タイトルに書いたようにドハマりしました・・・。
気づけばそりゃそうだろと思うようなことなのですが・・(´・ω・`)
ハマった点
オブジェクト(OBJ_A)とオブジェクト(OBJ_B)があるとします。また、OBJ_AとOBJ_Bはどちらもprefab化しています。(便宜上、OBJ_AのprefabをOBJ_A[pre]のように表現します。)
OBJ_AとOBJ_Bにはそれぞれ以下の内容のスクリプト(A.cs、B.cs)がアタッチされています。
A.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; public class A : MonoBehaviour { public GameObject bObj; private B b; // Use this for initialization void Start () { b = bObj.GetComponent<B> (); } // Update is called once per frame void Update () { Debug.Log ("A:" + b.num); } }
B.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; public class B : MonoBehaviour { public int num = 0; // Use this for initialization void Start () { } // Update is called once per frame void Update () { num++; Debug.Log ("B:" + num); } }
見てわかるように、updateされるたびにBスクリプト内のnumがインクリメントされ、numの値をAとBのスクリプト内でコンソールに出力しています。
bObjにOBJ_Bを入れるために、OBJ_AをInspectorに表示させると以下のようになります。
今からここにOBJ_Bを入れるのですが、私は考えなしに(いつものように)OBJ_B[pre]の方をいれて以下のような出力になりました。
この出力を見た私:「!?」
原因
OBJ_B[pre]を入れたということが原因です。
OBJ_B[pre]の内部を見に行ったところでUpdate関数でインクリメントされているnumはそこにはいません。num = 0
が待っているだけです。Update関数が実行されるのはゲーム内で有効なオブジェクトである必要があるからです。
解決法
もう分かるかと思いますが、HierarchyにあるOBJ_Bの方を入れる必要があったわけです。
以下がその時の出力結果です。
おわり
何言ってんだよ当たり前だろ。って言われるような内容ですが、ハマっていた当時は原因不明で「??」って感じでした。
Instantiateに使うオブジェクトとして考えなしにとりあえずprefabを設定していたツケがきたんですね(´・ω・`)
説明や語句の使用で間違っている箇所があればコメントをお願いします!