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

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

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

Unity3Dは、ゲームや対話式の3Dアプリケーション、トレーニングシュミレーション、そして医学的・建築学的な技術を可視化する、商業用の開発プラットフォームです。

Q&A

解決済

1回答

15177閲覧

3Dモデルが壁に引っかかって落ちてこない現象

nishi835

総合スコア15

Unity3D

Unity3Dは、ゲームや対話式の3Dアプリケーション、トレーニングシュミレーション、そして医学的・建築学的な技術を可視化する、商業用の開発プラットフォームです。

0グッド

1クリップ

投稿2018/12/10 11:13

編集2018/12/10 12:05

困っていること

お世話になります。
ちょっと質問なのですが、3Dモデルをジャンプさせて壁にぶつけると、引っかかったようになって落ちてこない現象で困っています。
モデルのColliderをtriggerにすると落ちていくので、当たり判定が引っかかっているのでしょうか。歩いてぶつかっても問題ないのですが。

モデルのColliderの形状はシンプルなBox状で、壁にも当たり判定の凹凸はありません。
壁はProBuilderで作成したものです。

原因に心当たりのある方、ご回答宜しくお願い致します。

Unityのバージョンは2018.2.9f1 Personalです。

イメージ説明

少し長いですが、3Dモデルを動かしているスクリプトの関係のありそうな部分を添付いたします。

C#

1 void Update() 2 { 3 var cameraForward = Vector3.Scale(Camera.main.transform.forward, new Vector3(1, 0, 1)).normalized; // カメラが追従するための動作 4 Vector3 direction = Vector3.zero; 5 6 // 地面に接地している時 7 if (CheckGrounded()) 8 { 9 if (Input.GetAxis("Vertical01") == 0 && Input.GetAxis("Horizontal01") == 0) // テンキーや3Dスティックの入力(GetAxis)がゼロの時の動作 10 { 11 animCon.SetBool("Walk", false); 12 animCon.SetBool("Run", false); 13 } 14 else if (!(Input.GetButton("SideRight") || Input.GetButton("SideLeft")) && !(animCon.GetBool("FrontFlip") || animCon.GetBool("BackFlip"))) 15 { 16 if (Input.GetButton("Dash")) 17 { 18 animCon.SetBool("Run", true); 19 dashTime += Time.deltaTime; 20 21 endurance -= consRate * Time.deltaTime; 22 23 if (Input.GetButtonDown("Slide")) 24 { 25 animCon.SetBool("Slide", true); 26 } 27 } 28 else 29 { 30 animCon.SetBool("Run", false); 31 animCon.SetBool("Walk", true); 32 dashTime = 0.0f; 33 } 34 35 // フリップ 36 if (Input.GetAxis("Flip") > 0) 37 { 38 animCon.SetBool("FrontFlip", true); 39 } 40 else if (Input.GetAxis("Flip") < 0) 41 { 42 animCon.SetBool("BackFlip", true); 43 } 44 45 direction = cameraForward * Input.GetAxis("Vertical01") + Camera.main.transform.right * Input.GetAxis("Horizontal01"); // テンキーや3Dスティックの入力(GetAxis)があるとdirectionに値を返す 46 Turn(direction); // 向きを変える動作の処理を実行する(後述) 47 } 48 49 moveDirection = direction * moveSpeed; //移動スピードを向いている方向に与える 50 moveDirection.y = 0f; //Y方向への速度をゼロにする 51 52 if (isWallJump) 53 { 54 animCon.SetBool("Idle", true); 55 isWallJump = false; 56 } 57 58 // 着地したらアニメーションパラメータのFallをfalseにする 59 animCon.SetBool("Fall", false); 60 animCon.SetBool("Jump", false); 61 animCon.SetBool("WallJump", false); 62 63 var input = new Vector3(Input.GetAxis("Horizontal01"), 0f, Input.GetAxis("Vertical01")); 64 65 if (input.magnitude > 0f) 66 { 67 // 着地後移動キーを押したら着地アニメーション終了 68 animCon.SetBool("Landing", false); 69 } 70 71 var stateInfo = animCon.GetCurrentAnimatorStateInfo(0); 72 73 // ジャンプ 74 if (Input.GetButtonDown("Jump") && !(Input.GetButton("SideRight") || Input.GetButton("SideLeft")) && !(animCon.GetBool("FrontFlip") || animCon.GetBool("BackFlip") || stateInfo.IsName("Roll"))) 75 { 76 rb.AddForce(0, jumpPower, 0, ForceMode.Impulse); 77 isJump = true; 78 } 79 80 // ジャンプ力リセット 81 jumpPower = defaultJumpPower; 82 } 83 else // 空中なら 84 { 85 // ジャンプアクション後、空中に移動したらジャンプアニメーションを始める 86 if (isJump) 87 { 88 animCon.SetBool("Jump", true); 89 isJump = false; 90 } 91 92 //animCon.SetBool("isGrounded", false); 93 animCon.SetBool("Idle", false); 94 95 if (!animCon.GetBool("Fall")) // アニメーションパラメータFallがfalseの時で地面との距離が遠かったらFallをtrueにする 96 { 97 if (!Physics.SphereCast(new Ray(spine.position, Vector3.down), 0.5f, distanceToTheGround, LayerMask.GetMask("Field"))) 98 { 99 animCon.SetBool("Fall", true); 100 } 101 } 102 else if (animCon.GetBool("Fall")) // 落下アニメーションの時はレイを飛ばし着地アニメーションにする 103 { 104 if (Physics.Linecast(spine.position, spine.position + Vector3.down * distanceToLanding, LayerMask.GetMask("Field")) && !isRoll) 105 { 106 animCon.SetBool("Landing", true); 107 } 108 } 109 110 if (Input.GetButtonDown("Jump")) 111 { 112 isRoll = true; 113 animCon.SetBool("Landing", false); 114 } 115 116 jumpPower += gravity * Time.deltaTime; // 時間経過とともに壁ジャンプ力を増す 117 } 118 119 if (Input.GetButtonDown("Action")) 120 { 121 if (rader.CanHang()) 122 { 123 //Rayの作成       ↓Rayを飛ばす原点   ↓Rayを飛ばす方向 124 Ray ray = new Ray(transform.position, new Vector3(0, -1, 0)); 125 126 //Rayが当たったオブジェクトの情報を入れる箱 127 RaycastHit hit; 128 129 //Rayの飛ばせる距離 130 int distance = 10; 131 Physics.Raycast(ray, out hit, distance); 132 133 float h_angle = hit.transform.eulerAngles.y; 134 float p_angle = transform.eulerAngles.y; 135 136 for (int i = 0; i < 4; i++) 137 { 138 h_angle -= 90 * i; 139 if (h_angle < 0) { h_angle = 360 + h_angle; } 140 float diff = Mathf.Abs(h_angle - p_angle); 141 if (diff > 180) { diff = 360 - diff; } 142 if (diff <= 45) 143 { 144 transform.rotation = Quaternion.Euler(0.0f, h_angle, 0.0f); 145 break; 146 } 147 } 148 149 animCon.SetBool("HangWall", true); 150 151 StartCoroutine(DelayMethod(0.65f, () => 152 { 153 transform.position = Vector3.Lerp(transform.position, transform.position + new Vector3(0.0f, 0.0f, -0.15f), 1.0f); 154 })); 155 } 156 } 157 158 if (animCon.GetBool("HangWall")) 159 { 160 Physics.gravity = new Vector3(0.0f, 0.0f, 0.0f); 161 } 162 else 163 { 164 Physics.gravity = new Vector3(0.0f, defaultGravity, 0.0f); 165 } 166 167 switch(animClip) 168 { 169 case AnimClip.GetHit: 170 if(animCon.GetCurrentAnimatorStateInfo(0).normalizedTime >= 1f) 171 { 172 animClip = AnimClip.Idle; 173 animCon.CrossFadeInFixedTime(AnimClip.Idle.ToString(), 0.5f); 174 } 175 break; 176 } 177 178 // 移動 179 //charaCon.Move(moveDirection * Time.deltaTime); //CharacterControllerの付いているこのオブジェクトを移動させる処理 180 rb.AddForce(moveDirection.x * moveSpeed, 0, moveDirection.z * moveSpeed); 181 } 182 183 // 汎用コルーチン 184 private IEnumerator DelayMethod(float waitTime, Action action) 185 { 186 yield return new WaitForSeconds(waitTime); 187 action(); 188 } 189 190 // 向きを変える動作の処理 191 void Turn(Vector3 direction) 192 { 193 Quaternion q = Quaternion.LookRotation(direction); // 向きたい方角をQuaternion型に直す 194 transform.rotation = Quaternion.RotateTowards(transform.rotation, q, turnSpeed * Time.deltaTime); // 向きを q に向けてじわ~っと変化させる. 195 } 196 197 // スタミナを返す 198 public int Endurance() 199 { 200 return (int)endurance; 201 } 202 203 // 着地判定 204 public bool CheckGrounded() 205 { 206 //CharacterControlle.IsGroundedがtrueならRaycastを使わずに判定終了 207 //if (charaCon.isGrounded) { return true; } 208 209 //放つ光線の初期位置と姿勢 210 //若干身体にめり込ませた位置から発射しないと正しく判定できない時がある 211 var ray = new Ray(this.transform.position + new Vector3(0.0f, 0.1f, -0.1f), Vector3.down); 212 213 //探索距離 214 var tolerance = 0.3f; 215 216 //Raycastがhitするかどうかで判定 217 //地面にのみ衝突するようにレイヤを指定する 218 return Physics.Raycast(ray, tolerance, LayerMask.GetMask("Field")); 219 } 220 221 // 壁ジャンプ 222 private void OnControllerColliderHit(ControllerColliderHit hit) 223 { 224 if (!CheckGrounded()) 225 //if (!charaCon.isGrounded) 226 { 227 if (hit.normal.y < 0.1f) 228 { 229 if (Input.GetButtonDown("Jump")) 230 { 231 animCon.SetBool("WallJump", true); 232 isWallJump = true; 233 234 float angle = Mathf.Atan2(hit.normal.x, hit.normal.z) * Mathf.Rad2Deg; 235 transform.rotation = Quaternion.Euler(0.0f, angle, 0.0f); 236 moveDirection.x = hit.normal.x * moveSpeed; 237 moveDirection.z = hit.normal.z * moveSpeed; 238 moveDirection.y = jumpPower; 239 } 240 } 241 } 242 } 243 244} 245

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

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

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

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

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

Bongo

2018/12/10 11:25

これは壁方向に入力を続けている状態でしょうか、それともキー入力・コントローラー入力をやめても壁に貼り付いて落ちてこない状態でしょうか?
nishi835

2018/12/10 11:28

キー入力はしていない状態ですね。ちなみに、壁に当たる前にキーを離しても、結果は同じになります。
Bongo

2018/12/10 11:53

キー入力なしでも貼り付いてしまいますか...私の想像とは状況が異なっており、すぐには回答を提示できないかもしれません。キャラクターの移動のためのスクリプトをご提示いただけますでしょうか?また、壁やキャラクターのコライダーのMaterial(Physic Material)はどうなっているでしょうか。
nishi835

2018/12/10 12:08

回答を考えてくださりありがとうございます。少し長くて申し訳ないのですが、スクリプトを追記いたしましたので、よろしくお願いいたします。Physic Materialは、一度壁のほうの摩擦を0にしたり、跳ね返りをつけたりしたのですが、上手くいきませんでした。モデル側はMaterialをつけていません。
Bongo

2018/12/10 12:35

壁に貼り付いている状態だと、地上にいると判定される...つまり、Updateの最初の方にある「if (CheckGrounded()) {」の次の行あたりに「Debug.Log(...」でコンソールにメッセージを出力させると、それが表示される状態でしょうか?
nishi835

2018/12/10 13:02

壁に張り付いている状態のCheckGroundedの戻り値はFalseですね。空中にいる判定です。
Bongo

2018/12/10 13:21

なるほど...たびたびすみませんが、Updateの最後にある「rb.AddForce(moveDirection.x * moveSpeed, 0, moveDirection.z * moveSpeed);」の直前の行に「Debug.Log(moveDirection.ToString("F6"));」とでも入れてみますと、キー入力なしで壁に貼り付いている状態ではどのような値が出力されるでしょうか?XYZすべて0でしょうか?
nishi835

2018/12/10 13:46

(0.841196, 0.000000, 10.000000)となっています。
guest

回答1

0

ベストアンサー

まだ実際に動作検証したわけではないのですが、現在の作りではキャラクターが移動中にジャンプした場合、空中でも移動していた方向に力が加わり続けているように思われます。
そうだとすると、もし壁に向かって走り込んでジャンプし壁に飛びつくと、そのままキャラクターが壁に押しつけられた状態になり、壁とキャラクターの間の摩擦力によって貼り付いている可能性が考えられます。

壁とキャラクターの摩擦をなくせば張り付き防止に効果がありそうですが、そうすると今度は地上を歩いている時もつるつる滑って不都合かもしれません。
キャラクターにコライダーを追加して、メインのコライダーよりも垂直方向を少し小さく、水平方向を少し大きくしてやり、キャラクターの側面だけにコライダーが露出する状態にして、そのコライダーのPhysic Materialを摩擦なしにする...Dynamic FrictionとStatic Frictionを0、Friction CombineをMinimumにするというのはどうでしょうか。

あるいは、コード修正による張り付き対策として思いつくのは、空中で衝突検出した場合に衝突面の法線を調べ(ご質問者さんが壁ジャンプ実装部分で行っているのと同様です)、側面衝突であればmoveDirectionVector3.zeroに書き換える...とかでしょうか。こちらの方がコライダー追加よりも手軽かもしれませんね。

投稿2018/12/10 20:39

Bongo

総合スコア10807

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

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

nishi835

2018/12/11 07:46 編集

後者の、「空中で衝突検出した場合に衝突面の法線を調べ、側面衝突であればmoveDirectionをVector3.zeroに書き換える」を採用したところ、上手くいきました。 壁ジャンプと両立するのに少し苦労しましたが、そちらも一応解決しました。 丁寧なご対応ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.44%

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

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

質問する

関連した質問