質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

Q&A

解決済

1回答

7379閲覧

unityで球体の地面に埋まる

Sobasenbei

総合スコア132

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

0グッド

0クリップ

投稿2021/06/12 12:34

編集2021/06/12 12:36

#解決したいこと
unityでマリオギャラクシーのように球体を地面にしたいのですが、sphere colliderを使うと体が少し埋まってしまいます。
貫通することはないのですがその分コライダーを大きくしてもなぜか全く同じところまで埋まります。
埋まるときは沼に沈んでいくようにゆっくり埋まっていきます
コライダーを大きくすると当たり判定があやふやになってしまうのでしょうか

#試したこと
コライダーを大きくした
球体モデルのメッシュを細かくした

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Bongo

2021/06/12 13:17

球体の地面となると、何か特殊な重力処理をなさっているんでしょうかね? 私も以前練習目的で球体の地面を試してみたことがあるのですが、そのような現象は特に見当たりませんでした(https://teratail-v2.storage.googleapis.com/uploads/contributed_images/23a541b001669916cfb00e784c5ef485.gif )。地面やキャラクターの作り、キャラクターをコントロールするスクリプトなどもご提示いただければ何かしらアドバイスできることがあるかもしれません。
Sobasenbei

2021/06/12 15:46

恥ずかしながら、方法としてはキャラクターにはジャンプ機能だけつけて移動は星の方を動かしているというだけなので、引力の向きを変えるなどの特殊な機能は一切書いていません。 unityの球体ではメッシュが粗かったのでblenderの球体を持ってきましたが、コライダーはキャラクターも地面も普通のコライダーを入れてます
guest

回答1

0

ベストアンサー

コメントいただきました方法をイメージして実験用シーンを作ってみました。まだめり込み現象を再現させることができていませんが、追記依頼欄だと見にくいかと思い、すみませんが回答欄を使わせていただきました。
私の場合は下記のようにしてみたのですが、ご質問者さんの場合と比較して相違点・疑わしい点はありますでしょうか?
お気付きの点がありましたらぜひコメントください。もしかするとそこから原因を特定できるかもしれません。

まず、地面はサイズ10のSphereとしました。ご質問者さんの場合は独自のメッシュを使用されているようですが、物理的な形はコライダーに依存しており、画面上に表示するためのメッシュが何であろうが影響はないだろうと思います。
Sphereには元々付いていたSphereColliderに加えてRigidbodyをアタッチし、Is Kinematicをオンにしました。

図1

キャラクターには下図のようにCapsuleColliderRigidbodyを付け、回転はY軸周りのみ許可、移動はY軸方向のみ許可しています。

図2

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}

動かしてみたところどうやら正常に動作しているようで、キャラクターが地面にめり込んでしまうような様子はありませんでした。

図3

##キャラクターのアニメーションについて

キャラクターオブジェクトのベースにしたのは、Prefabsフォルダ内のSD_unitychan_humanoidプレハブです。これにはすでに体の各部位にSpringBoneSpringColliderが仕込まれており、オブジェクトの動きに応じて部位が揺れるようになっています。
これの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}

図4

ユニティちゃんのアニメーションクリップの中には表情変化のためにOnCallChangeFaceイベントを発生させるものがあります。今回のアニメーションには表情変化は組み込んでおらず、処置なしだとOnCallChangeFaceイベントの受信者が存在しないのですが、それだとイベント発生時にエラーメッセージが出てうっとうしいためこのような処置を加えました。

次にアニメーションクリップを用意します。Animationsフォルダ内のSD_unitychan_motion_humanoidにさまざまな動きが収録されており、地上の姿勢についてはStanding@loop、Walking@loop、Running@loopの3つでまかなえるのですが、空中の姿勢についてはちょっとカスタマイズしたかったため少々手を加えました。

まず空を飛んでいる姿勢については「【Unity】FBXに格納されたAnimationClipを取り出し編集可能にする - テラシュールブログ」で紹介されている方法と同様の手順で「TopOfJump」を複製し、「UnitychanTop」と名前を変更し、下図のように設定を変更しました。

図5

着地姿勢については、すみませんが具体的なフレーム番号範囲は忘れてしまったのですが「アニメーションクリップの抽出 - Unity マニュアル」の手順に従って「TopToGround」のモーションのうち爪先が地面に触れてから姿勢を正すまでのモーションを切り出し、同じく複製して「UnitychanTopToGround」という名前にした上で下図のように設定しました。

図6

そしてアニメーターコントローラーを作成します。名前は前述のように「UnitychanGalaxyMotion」とし、ベースレイヤーのみで表情用レイヤーは持っていません。下図のようにパラメーターとしてFloat型のSpeed、Bool型のOnGroundを持っています。

図7

Groundedステートは地上にいる時の状態であり、ブレンドツリーになっています。

図8

下図のようにSpeedに応じてStanding@loop、Walking@loop、Running@loopを混合するようになっています。

図9

Groundedステートにいる時にOnGroundがfalseになるとTopステートに遷移します。

図10

Topステートは空中の姿勢で...

図11

Topステートにいる時にOnGroundがtrueになるとTopToGroundステートに遷移します。

図12

TopToGroundステートが着地時に脚を屈曲させる動きで...

図13

再生後にGroundedステートに遷移します。

図14

以上のようにセットアップされたアニメーターコントローラーを、シーン上のキャラクターのAnimatorのControllerにセットしました。

投稿2021/06/12 21:59

編集2021/06/13 13:28
Bongo

総合スコア10811

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Sobasenbei

2021/06/13 04:32

差し支えなければ教えて欲しいのですが、そのunityちゃんのモデルとモーションはどこで入手できるのでしょうか? あなたのスクリプトで試してみたいのですが、初心者すぎてアニメの付け方もよくわからないので
Bongo

2021/06/13 13:29

回答中で申し上げましたようにアニメーションは見た目だけのものですので、PlayerControllerから private Animator animator; と this.animator = this.GetComponent<Animator>(); と this.animator.SetBool(ParamOnGround, grounded); this.animator.SetFloat(ParamSpeed, Vector3.Dot(this.horizontalVelocity, this.inputHorizontalVelocity)); の3ヶ所を削除して、アニメーション抜きにしてしまっても物理的挙動に変化はないはずです。 ですが、やはり直立したまま滑って動くだけではつまらないかもしれませんね。今回の実験に使ったのは「UNITY-CHAN! OFFICIAL WEBSITE」(https://unity-chan.com/ )から入手した「SDユニティちゃん 3Dモデルデータ」に収録されていたものです。私の場合のアニメーションの作りについて追記しました。
Sobasenbei

2021/06/13 17:09

とても丁寧に書いていただいてありがとうございました! バージョンを2019から2021に変えて新しくプロジェクトを作りあなたのスクリプトを使わせていただいたらうまくいきました。 結局バグだったのでしょうかね?
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問