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

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

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

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

Unity

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

Q&A

解決済

1回答

2264閲覧

【Unity】接地判定・移動方向の切り替えが上手くいきません

futon-fukafuka

総合スコア9

C#

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

Unity

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

0グッド

0クリップ

投稿2020/07/11 08:27

編集2020/07/11 09:06

前提・実現したいこと

横スクロール型アクションゲーム(3D)で、
敵が足場から落ちるときにゆっくり斜めに下がっていくのではなく、
ストンと下に落ちるようにしたいと思っています。

そこで、接地判定のトリガーを敵キャラの足元に配置し、
接地中は横方向、接地していないとき(落下中)は下方向に動くようにVelocityを切り替えようと考えました
(落下中は Vector3 (0, -5, 0)などにする)。

トリガーのスクリプトで接地(下記"OnGround")のtrue/falseを切り替え、
それを敵スクリプトが取得し、if構文でVelocityを切り替える仕組みを作ったのですが、
実行してみると、接地していない間も動きが変わりません。
さらに、以前は実行できていた左右の向き(enemyEulerAngles.y)による左右移動の切り替えも無効になってしまいました。
if構文を変えるなど、様々試してみたのですが解決できません。
もし改善点がお分かりでしたら、教えて頂けると嬉しいです。

該当のソースコード

【敵本体のスクリプト】

public class enemyMovement : MonoBehaviour { private int layermask = 1 << 0 | 1 << 16; public Vector3 leftVelocity;//inspectorで(-4, 0, 0)に設定 public Vector3 rightVelocity;//inspectorで(4, 0, 0)に設定 public Vector3 leftFallVelocity;//inspectorで(-0.1, -5, 0)に設定 public Vector3 rightFallVelocity;//inspectorで(0.1, -5, 0)に設定 public GameObject GroundCheckTrigger;//inspectorでトリガーのオブジェクトを設定 RaycastHit hit; void Start() { layermask = 1 << 0 | 1 << 16; } void Update() { Vector3 enemyEulerAngles = this.transform.localEulerAngles; Rigidbody enemyRB = this.transform.GetComponent<Rigidbody>(); GroundChecker GroundCheck = GroundCheckTrigger.gameObject.GetComponent<GroundChecker>(); if (Physics.Raycast(transform.position, transform.TransformDirection(Vector3.left), out hit, 1.3f, layermask))//レイキャストで、壁(layer 0)と敵(layer 16)へのヒットを判定 { if (enemyEulerAngles.y == 0)//敵が左向きの場合 { transform.eulerAngles = new Vector3(0, -180, 0);//敵を右向きにする } else//左向きでなければ { transform.eulerAngles = new Vector3(0, 0, 0);//右向きにする } } if (enemyEulerAngles.y == 0)//敵が左向きのとき { if (GroundCheck.OnGround = true) { enemyRB.velocity = leftVelocity; } else if (GroundCheck.OnGround = false) { enemyRB.velocity = leftFallVelocity; } } else if (enemyEulerAngles.y == -180)//敵が右向きのとき { if (GroundCheck.OnGround = true) { enemyRB.velocity = rightVelocity; } else if (GroundCheck.OnGround = false) { enemyRB.velocity = rightFallVelocity; } } } }

【接地判定トリガーのスクリプト】

public class GroundChecker : MonoBehaviour { public bool OnGround; void Start() { OnGround = false; } void OnTriggerEnter(Collider collision) { OnGround = true; } void OnTriggerExit(Collider collision) { OnGround = false; } }

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

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

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

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

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

guest

回答1

0

ベストアンサー

回答ではありません。貼り付けられたコードがとてもじゃないが読める代物ではないため整形しています。

敵本体のスクリプト

csharp

1public class enemyMovement : MonoBehaviour 2{ 3 private int layermask = 1 << 0 | 1 << 16; 4 public Vector3 leftVelocity; 5 public Vector3 rightVelocity; 6 public Vector3 fallVelocity; 7 public GameObject GroundCheckTrigger; 8 RaycastHit hit; 9 10 void Start() 11 { 12 layermask = 1 << 0 | 1 << 16; 13 } 14 15 void Update() 16 { 17 Vector3 enemyEulerAngles = this.transform.localEulerAngles; 18 Rigidbody enemyRB = this.transform.GetComponent<Rigidbody>(); 19 GroundChecker GroundCheck = GroundCheckTrigger.gameObject.GetComponent<GroundChecker>(); 20 21 if (Physics.Raycast(transform.position, transform.TransformDirection(Vector3.left), out hit, 1.3f, layermask)) 22 { 23 if (enemyEulerAngles.y == 0) 24 { 25 transform.eulerAngles = new Vector3(0, -180, 0); 26 } 27 28 else 29 { 30 transform.eulerAngles = new Vector3(0, 0, 0); 31 } 32 } 33 34 if (enemyEulerAngles.y == 0) 35 { 36 if (GroundCheck.OnGround = true) 37 { 38 enemyRB.velocity = leftVelocity; 39 } 40 41 else if (GroundCheck.OnGround = false) 42 { 43 enemyRB.velocity = leftFallVelocity; 44 } 45 } 46 47 else if (enemyEulerAngles.y == -180) 48 { 49 if (GroundCheck.OnGround = true) 50 { 51 enemyRB.velocity = rightVelocity; 52 } 53 54 else if (GroundCheck.OnGround = false) 55 { 56 enemyRB.velocity = rightFallVelocity; 57 } 58 } 59 } 60}

接地判定トリガーのスクリプト

charp

1public class GroundChecker : MonoBehaviour 2{ 3 public bool OnGround; 4 5 void Start() 6 { 7 OnGround = false; 8 } 9 10 void OnTriggerEnter(Collider collision) 11 { 12 OnGround = true; 13 } 14 15 void OnTriggerExit(Collider collision) 16 { 17 OnGround = false; 18 } 19}

投稿2020/07/11 08:35

bboydaisuke

総合スコア5308

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

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

futon-fukafuka

2020/07/11 08:38

すみません、コード用の書式を設定する方法を知りませんでした。修正しました。
bboydaisuke

2020/07/11 08:43

整形したものを見て思ったこと 1. > 接地していない間も動きが変わりません。 「接地していない」ことはどうやって確認したのか。Inspector から GroundCheck.OnGround が true であることを確認したのか。それでは不十分ではないか? 2. leftFallVelocity, rightFallVelocity という未定義の変数が出てくるが、これで実行できるのか?またその値は何なのか 3. enemyEulerAngles.y が 0 か 180 の時のみ(どうやら)落下できるようだが、それでよいのか
futon-fukafuka

2020/07/11 08:49

ご指摘ありがとうございます。 1.Inspectorで接地判定トリガーのオブジェクトを指定し、そのコンポーネントを取得するようにしています。 2.leftFallVelocity、rightFallVelocityについては、間違って定義していない状態のコードをここに載せてしまったため、その部分を修正しました。申し訳ありません。public変数で、inspecterにて値を設定しています。 3.横向きのゲームなので、基本的にキャラの方向は0か-180のみのため、このように記述しています。右向きのとき、左向きのとき、という意味合いです。
bboydaisuke

2020/07/11 08:53

> 1.Inspectorで接地判定トリガーのオブジェクトを指定し、そのコンポーネントを取得するようにしています。 そういうことではなくて、自分で接地判定ができるつもりで処理などを作ったとしても、実行中にそれが自分の思った通りに判定できているかをどのように確認したのか、ということです。実際は見た目では接地していないように見えても作り方が間違っていて設置していると判定されているかもしれませんよね。どうやって「自分が思った通りに接地判定できている」と確認したのか、ということですよ。
bboydaisuke

2020/07/11 08:54

> 3.横向きのゲームなので、基本的にキャラの方向は0か-180のみのため、このように記述しています。右向きのとき、左向きのとき、という意味合いです。 計算誤差などなんらかの要因でオブジェクトの Rotation が少しでもズレてしまったらもう正しく動かなくなると思います。
bboydaisuke

2020/07/11 08:57 編集

> public変数で、inspecterにて値を設定しています。 そうなると、そこの値が Inspector で何の値にしているかを書かないと、この質問を見た人はそこの値に何が設定されているか知らないので、それが間違ってるんじゃないの?という確認をしないといけないですね。
bboydaisuke

2020/07/11 09:13 編集

とりあえず、自分なら Update の先頭に if (!GroundCheck.OnGround) { ....Debug.Log("接地してない。 " + enemyEulerAngles.ToString()); } というコードを加えて、接地判定ができているのか、またその時の EulerAngles はいくつなのかを調べると思います。
bboydaisuke

2020/07/11 09:18 編集

> 敵が足場から落ちるときにゆっくり斜めに下がっていくのではなく、 > public Vector3 leftFallVelocity;//inspectorで(-0.1, -5, 0)に設定 > enemyRB.velocity = leftFallVelocity; 「斜め下に移動する」ようにコードが書かれていますし、もしこのコンポーネントがアタッチされたオブジェクトに Rigidbody がアタッチされていて "Use Gravity" にチェックが入っているなら、斜め移動と重力による落下が両方行われますね。
bboydaisuke

2020/07/11 09:20

> 接地中は横方向、接地していないとき(落下中)は下方向に動くようにVelocityを切り替えようと考えました >(落下中は Vector3 (0, -5, 0)などにする)。 こういった処理は見当たらないように思いますが、どこの処理がこれに該当しますか?
bboydaisuke

2020/07/11 09:26

> 敵が足場から落ちるときにゆっくり斜めに下がっていくのではなく、 > ストンと下に落ちるようにしたいと思っています。 velocity を直接編集して移動処理をしているので、左右に移動する時に Y 軸方向だけは現在の velocity の値を残すようにすればいいんじゃないかと思います。 そして落下している、つまり Y 軸方向の velocity が負の時は左右に移動する処理をしなければ、あとは重力で落下するでしょう。必要であれば左右移動をストップしたりなど細かい制御をすればいいと思います。
bboydaisuke

2020/07/11 09:27 編集

↑この辺のことは velocity 直接編集ではなく AddForce でやっていれば非常に簡単なので、AddForce でやるように全面的に書き直す、というのもいいでしょう。
futon-fukafuka

2020/07/11 10:03 編集

アドバイスありがとうございます。 Debug.Logで確かめたところ、プレイ開始時(敵がまだ宙に浮いているとき)から「接地している」と判定されており、地面に触れた瞬間(1フレーム分)のみ「接地していない」と判定されているようでした。意図とは逆のことが起こっており、まだ何がどうなっているのか確認中です。 Vector3(0, -5, 0)の部分については、コードの説明文にある(-0.1, -5, 0)(0.1, -5, 0)がそれに当たります。ややこしくしてしまい、すみません。 AddForceも試してみたのですが、どんどん加速してしまうため、一定速度を保つためにVelocityで移動を制御しています。
futon-fukafuka

2020/07/11 10:04

enemyEulerAnglesについては、(0.0, 0.0, 0.0)だったので、角度は問題なかったようです。
bboydaisuke

2020/07/11 10:07

> AddForceも試してみたのですが、どんどん加速してしまうため、一定速度を保つためにVelocityで移動を制御しています。 速度が上がり過ぎたら AddForce しないように制御すればよいでしょう。現状の力学的に不自然な制御よりは簡単だと思います。
futon-fukafuka

2020/07/11 13:47

色々な助言、ありがとうございます。とても勉強になりました。 接地判定に関してどこがおかしいのか最終的に分からなかったので、 逃げの手法ではありますが、onCollisionStay/onCollisionExitで接地中/非接地中の挙動を分けました。 別オブジェクトをトリガーにする手法はもう少し知識が必要のようなので、改めて勉強します。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問