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

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

新規登録して質問してみよう
ただいま回答率
85.34%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Unity

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

Q&A

1回答

277閲覧

Unityでキャラクターを動かしたときに前に壁があった場合停止する処理が実行されません

takopanda

総合スコア0

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Unity

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

0グッド

0クリップ

投稿2024/12/25 08:49

実現したいこと

キャラクターを前に動かしたいときに前に障害物があった場合停止する処理をしたいです。コードに不具合があるなど、どのような不備があるのか教えてください。

発生している問題・分からないこと

うまく作動せず延々と壁にぶつかり続け、操作不能になります。コライダーなどはしっかり設定しているため、何が不備なのかわかりません。

エラーメッセージ

error

1延々とぶつかり続ける(エラーメッセージはなし)

該当のソースコード

C#

1using System.Collections; 2using UnityEngine; 3using UnityEngine.EventSystems; 4 5public class chara_move : MonoBehaviour 6{ 7 [SerializeField] LayerMask solidObjectsLayer; 8 9 Animator animator; 10 bool isMoving; 11 12 private void Awake() 13 { 14 animator = GetComponent<Animator>(); 15 } 16 17 void Update() 18 { 19 if (isMoving == false) 20 { 21 float x = Input.GetAxisRaw("Horizontal"); 22 float y = Input.GetAxisRaw("Vertical"); 23 24 if (x != 0) 25 { 26 y = 0; 27 } 28 29 if (x != 0 || y != 0) 30 { 31 animator.SetFloat("InputX", x); 32 animator.SetFloat("InputY", y); 33 StartCoroutine(Move(new Vector2(x, y))); 34 } 35 } 36 animator.SetBool("IsMoving", isMoving); 37 38 } 39 40 IEnumerator Move(Vector3 direction) 41 { 42 isMoving = true; 43 Vector3 targetPos = transform.position + direction; 44 if (IsWalkable(targetPos) == false) 45 { 46 isMoving = false; 47 yield break; 48 } 49 while ((targetPos - transform.position).sqrMagnitude > Mathf.Epsilon) 50 { 51 transform.position = Vector3.MoveTowards(transform.position, targetPos, 5f * Time.deltaTime); 52 yield return null; 53 } 54 55 transform.position = targetPos; 56 isMoving = false; 57 } 58 59 bool IsWalkable(Vector3 targetPos) 60 { 61 return Physics2D.OverlapCircle(targetPos, 0.2f, solidObjectsLayer) == false; 62 } 63}

試したこと・調べたこと

  • teratailやGoogle等で検索した
  • ソースコードを自分なりに変更した
  • 知人に聞いた
  • その他
上記の詳細・結果

特に変わりはなかった

補足

特になし

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

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

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

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

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

Eclipse216

2024/12/29 14:24

Ridibody2Dを使って、当たり判定を実装してはどうでしょうか?
takopanda

2024/12/30 15:14

Rigidbody 2D は使っているんですけど、ぶつかっても止まらず延々とぶつかり続けるんですよね…
fiveHundred

2024/12/31 02:09

Rigidbody2Dはどんな設定で、どのように使っていますか? もしかしたら「Rigidbody2Dが邪魔になって移動できない」ということかもしれません。
takopanda

2025/01/01 17:01

Rigidbody2Dの設定はボディタイプはダイナミックで、質量だけ1にしてます。後は衝突判定は連続的で、Z軸の回転は固定してます。
fiveHundred

2025/01/02 03:37

この場合「Physics2D.OverlapCircle」で移動するか判定しているので、物理判定は不要だと思います。 むしろ、その物理判定によって「指定された位置まで移動できない」となってしまって現状の問題になっている可能性もあります。
fiveHundred

2025/01/02 03:58

試しにRigidbody2Dなし(Collider2Dのみ)にしましたが、動作しました。 そのため「Rigidbody2Dによる物理的な挙動」は不要です。 そもそも、このスクリプトはRPGのようなマス目単位で移動するものですが、その点は理解していますか?
takopanda

2025/01/03 16:18

マス移動のRPGを作っているので、大丈夫です。 Rigidbody2Dを試しに抜いたところ、タイルマップの建物にぶつからずに通過してしまいました。 TilemapCollider2Dは入れています。
guest

回答1

0

動作の原因かどうかはわかりませんが、コードの不具合を指摘しておきます。

まず、 Update メソッドの中で入力があれば Move コルーチンを走らせています。
そして、 Move コルーチンの中では入力された方向に5unit/秒の速度で移動しようとしています。
入力値は-1から1の範囲ですから、最大1unit移動することになりますから、その場合には0.2秒かかることになります。

Update メソッドの呼ばれるサイクルはそれぞれですが、0.2秒の間に何回かは呼ばれます。
よって、同じ方向に入力された場合、 Move コルーチンが同時に多数走ることになります。

更に、同じ方向ではなく、急に逆方向に入力があった場合、多重にコルーチンが走っていれば前の方向に向かう移動力の方が勝っていますが、そのうちに逆方向へ向かうコルーチンが多くなるので、逆方向へ向かいます。
それ自体は見た目にはいい感じになるでしょうが、前に向かっていたコルーチンが残っていれば、目的地とは逆の方向に向かってしまうので、再度目的地に近づかない限りこのコルーチンが走り続けてしまうことになります。

次に当たり判定のとり方です。
移動先に半径0.2unitの範囲でコライダが無ければ、という判定になっていますが、先程も言ったとおり、最大1unit移動先との距離があることになりますが、となると最大0.8unitの間があることになります。
当然、その間にコライダがあっても、当たっていると判断されません。
(ただし、そんな小さなコライダはない、というのであれば、あまり問題にはならないかもしれません)
もしこの問題を回避したいのであれば、 Physics2D.OverlapCapsule を使って、現在位置と移動先とのカプセルで判定する方がいいでしょう。

次に Rigidbody2D に関してです。
Rigidbody2D を使っている場合には、基本的に移動に Transform.position などに位置を代入して移動してはいけません。 Rigidbody2D.AddForcevelocity などを使います。
この辺りの話は、「Unity Rigidbody2D 移動」で検索すればたくさん出てくると思うので、調べてください。

Rigidbody2D を使えば、壁に当たった際の処理もしてくれるので便利ですが、物理演算というのはリアリティに沿った動きをするので、想定外の動きをする場合もあります。
簡単な動きであれば Rigidbody2D に頼らず自分で処理する、という考えもありますが、そうであれば Rigidbody2D は基本有効にすべきではありません。(キネマティックにして使う、という考えもありますが、話がややっこしくなるので、とりあえず置いといて)


操作不能になる不具合の原因ですが、正直パッとはわかりませんが、上記のことを踏まえてあえて考えるのであれば、「障害物が小さかった場合」「 Rigidbody2D が有効であれば」、障害物を無視して移動しようとする力と、 Rigidbody2D による障害物の衝突による押し戻す力が同時に働いて、動けなくなっている、という可能性があります。
もしそうであれば、先に話したとおりカプセルで当たり判定を行い、 Rigidbody2D を無効にすれば解決しますが、コルーチンの多重起動の問題もありますので、一旦移動処理を見直すことをおすすめします。

投稿2025/01/04 01:23

katsuko

総合スコア3554

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.34%

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

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

質問する

関連した質問