#解決したいこと
unityでマリオギャラクシーのように球体を地面にしたいのですが、sphere colliderを使うと体が少し埋まってしまいます。
貫通することはないのですがその分コライダーを大きくしてもなぜか全く同じところまで埋まります。
埋まるときは沼に沈んでいくようにゆっくり埋まっていきます
コライダーを大きくすると当たり判定があやふやになってしまうのでしょうか
#試したこと
コライダーを大きくした
球体モデルのメッシュを細かくした
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2021/06/12 15:46
回答1件
0
ベストアンサー
コメントいただきました方法をイメージして実験用シーンを作ってみました。まだめり込み現象を再現させることができていませんが、追記依頼欄だと見にくいかと思い、すみませんが回答欄を使わせていただきました。
私の場合は下記のようにしてみたのですが、ご質問者さんの場合と比較して相違点・疑わしい点はありますでしょうか?
お気付きの点がありましたらぜひコメントください。もしかするとそこから原因を特定できるかもしれません。
まず、地面はサイズ10のSphereとしました。ご質問者さんの場合は独自のメッシュを使用されているようですが、物理的な形はコライダーに依存しており、画面上に表示するためのメッシュが何であろうが影響はないだろうと思います。
Sphereには元々付いていたSphereCollider
に加えてRigidbody
をアタッチし、Is Kinematicをオンにしました。
キャラクターには下図のようにCapsuleCollider
とRigidbody
を付け、回転はY軸周りのみ許可、移動はY軸方向のみ許可しています。
PlayerController
がキャラクターをコントロールするためのスクリプトです。なおSpringManager
は髪の毛やらリボンやらを揺らすためのもので、FaceDisabler
は表情アニメーションを無効化するためのものであり、いずれも物理的挙動には関与していません。
また図では表示を閉じていますが、Animator
のApply Root Motionはオフにしています。純粋に見た目だけをコントロールするようにしており、Transform
に操作は加わらないようになっています。ですのでこれも物理的挙動に影響はないはずです。
PlayerController
の内容は下記のようになっています。
lang
1using UnityEngine; 2 3public class PlayerController : MonoBehaviour 4{ 5 private static readonly int ParamOnGround = Animator.StringToHash("OnGround"); 6 private static readonly int ParamSpeed = Animator.StringToHash("Speed"); 7 8 [SerializeField] private Rigidbody groundRigidbody; 9 [SerializeField] private Transform cameraTransform; 10 [SerializeField] private float horizontalSpeed = 3.0f; 11 [SerializeField] private float verticalSpeed = 10.0f; 12 [SerializeField] private float velocityBlendingFactor = 0.5f; 13 [SerializeField] private LayerMask groundLayers; 14 15 private Animator animator; 16 private Vector3 horizontalVelocity; 17 private Vector3 inputHorizontalVelocity; 18 private new Rigidbody rigidbody; 19 20 private bool IsGrounded => Physics.CheckSphere(this.rigidbody.position, 0.25f, this.groundLayers); 21 22 private void Awake() 23 { 24 this.animator = this.GetComponent<Animator>(); 25 this.rigidbody = this.GetComponent<Rigidbody>(); 26 this.rigidbody.centerOfMass = Vector3.zero; 27 } 28 29 private void Update() 30 { 31 // 接地状態、コントローラー入力を取得する 32 var grounded = this.IsGrounded; 33 var inputX = Input.GetAxis("Horizontal"); 34 var inputZ = Input.GetAxis("Vertical"); 35 var inputJump = Input.GetButtonDown("Jump"); 36 var forward = Vector3.ProjectOnPlane(this.cameraTransform.forward, Vector3.up).normalized; 37 var right = Vector3.ProjectOnPlane(this.cameraTransform.right, Vector3.up).normalized; 38 this.inputHorizontalVelocity = ((forward * inputZ) + (right * inputX)) * this.horizontalSpeed; 39 40 // 地上にいる状態でジャンプボタンが押されたら 41 // 真上に速度を加えることでジャンプさせる 42 if (grounded && inputJump) 43 { 44 this.rigidbody.AddForce(Vector3.up * this.verticalSpeed, ForceMode.VelocityChange); 45 } 46 47 // キャラクター自体は水平移動を禁止しており、水平速度はhorizontalVelocityで表現する 48 // 現在の水平速度を視覚的に確認する目的で、シーンビューに水平速度を表す線を描く 49 Debug.DrawLine(this.rigidbody.position, this.rigidbody.position + this.horizontalVelocity, Color.cyan); 50 51 // 状態に応じてアニメーションをコントロールする 52 this.animator.SetBool(ParamOnGround, grounded); 53 this.animator.SetFloat(ParamSpeed, Vector3.Dot(this.horizontalVelocity, this.inputHorizontalVelocity)); 54 } 55 56 private void FixedUpdate() 57 { 58 // 入力方向に応じて角速度を設定することで 59 // キャラクターを入力方向に向かって回転させる 60 var faceDirection = this.transform.forward; 61 var inputDirection = this.inputHorizontalVelocity.normalized; 62 this.rigidbody.angularVelocity = Vector3.Cross(faceDirection, inputDirection) / Time.deltaTime; 63 64 // 入力された水平速度に向かって現在の水平速度をゆったり変化させる 65 this.horizontalVelocity = Vector3.Lerp(this.horizontalVelocity, this.inputHorizontalVelocity, this.velocityBlendingFactor); 66 67 // 現在の水平速度に応じて地面を回転させる 68 var relativePosition = this.rigidbody.position - this.groundRigidbody.position; 69 var deltaAngle = (this.horizontalVelocity.magnitude * Time.deltaTime * Mathf.Rad2Deg) / relativePosition.magnitude; 70 var axis = Vector3.Cross(this.horizontalVelocity, relativePosition).normalized; 71 this.groundRigidbody.MoveRotation(Quaternion.AngleAxis(deltaAngle, axis) * this.groundRigidbody.rotation); 72 } 73}
動かしてみたところどうやら正常に動作しているようで、キャラクターが地面にめり込んでしまうような様子はありませんでした。
##キャラクターのアニメーションについて
キャラクターオブジェクトのベースにしたのは、Prefabsフォルダ内のSD_unitychan_humanoidプレハブです。これにはすでに体の各部位にSpringBone
やSpringCollider
が仕込まれており、オブジェクトの動きに応じて部位が揺れるようになっています。
これのAnimator
については前述のようにApply Root Motionをオフにし、Controllerを後述の「UnitychanGalaxyMotion」に差し替えました。
また、アタッチされているスクリプト類のうちSpringManager
以外は削除して、代わりにFaceDisabler
をアタッチしました。
これは下記のように「OnCallChangeFace
メッセージを受信しても何もしない」というだけのものです。
lang
1using UnityEngine; 2 3public class FaceDisabler : MonoBehaviour 4{ 5 public void OnCallChangeFace(string _) 6 { 7 } 8}
ユニティちゃんのアニメーションクリップの中には表情変化のためにOnCallChangeFace
イベントを発生させるものがあります。今回のアニメーションには表情変化は組み込んでおらず、処置なしだとOnCallChangeFace
イベントの受信者が存在しないのですが、それだとイベント発生時にエラーメッセージが出てうっとうしいためこのような処置を加えました。
次にアニメーションクリップを用意します。Animationsフォルダ内のSD_unitychan_motion_humanoidにさまざまな動きが収録されており、地上の姿勢についてはStanding@loop、Walking@loop、Running@loopの3つでまかなえるのですが、空中の姿勢についてはちょっとカスタマイズしたかったため少々手を加えました。
まず空を飛んでいる姿勢については「【Unity】FBXに格納されたAnimationClipを取り出し編集可能にする - テラシュールブログ」で紹介されている方法と同様の手順で「TopOfJump」を複製し、「UnitychanTop」と名前を変更し、下図のように設定を変更しました。
着地姿勢については、すみませんが具体的なフレーム番号範囲は忘れてしまったのですが「アニメーションクリップの抽出 - Unity マニュアル」の手順に従って「TopToGround」のモーションのうち爪先が地面に触れてから姿勢を正すまでのモーションを切り出し、同じく複製して「UnitychanTopToGround」という名前にした上で下図のように設定しました。
そしてアニメーターコントローラーを作成します。名前は前述のように「UnitychanGalaxyMotion」とし、ベースレイヤーのみで表情用レイヤーは持っていません。下図のようにパラメーターとしてFloat型のSpeed、Bool型のOnGroundを持っています。
Groundedステートは地上にいる時の状態であり、ブレンドツリーになっています。
下図のようにSpeedに応じてStanding@loop、Walking@loop、Running@loopを混合するようになっています。
Groundedステートにいる時にOnGroundがfalse
になるとTopステートに遷移します。
Topステートは空中の姿勢で...
Topステートにいる時にOnGroundがtrue
になるとTopToGroundステートに遷移します。
TopToGroundステートが着地時に脚を屈曲させる動きで...
再生後にGroundedステートに遷移します。
以上のようにセットアップされたアニメーターコントローラーを、シーン上のキャラクターのAnimator
のControllerにセットしました。
投稿2021/06/12 21:59
編集2021/06/13 13:28総合スコア10811
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2021/06/13 04:32
2021/06/13 13:29
2021/06/13 17:09
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。