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

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

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

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

タグ

特殊な記法により文書に埋め込む形で記述される付加情報をタグと呼びます。文書構造や書式、文字飾りなどを指示したり、画像や他の文書へのリンクを埋め込むことができる。

Q&A

解決済

2回答

2281閲覧

地面をキャラクターが貫通してしまう

youngdoonatsu

総合スコア5

C#

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

タグ

特殊な記法により文書に埋め込む形で記述される付加情報をタグと呼びます。文書構造や書式、文字飾りなどを指示したり、画像や他の文書へのリンクを埋め込むことができる。

0グッド

0クリップ

投稿2021/08/12 09:20

編集2021/08/12 09:24

unityで2Dのゲームを作っています。
下から上がってくる地面に乗っかって何秒耐えられるかのゲームなのですが、
肝心の地面に触れても、キャラが落ちていってしまいます。
スクリプトに間違いがあったらぜひ教えてください。
キャラクターのスクリプトです↓

C#

1using System; 2using System.Collections; 3using System.Collections.Generic; 4using UnityEngine; 5 6public class PlayerIdou : MonoBehaviour 7{ 8 public float SpeedX; 9   public static int SpeedY=-65; 10 public float Muki; 11 float screenLeft = -2;//左端の座標x 12 float screenRight = 2;//右端の座標x 13 14 void Start() 15 { 16 17 } 18 19 // Update is called once per frame 20 void Update() 21 { 22     SpeedX = SpeedX*0.7f; 23 Muki = Muki*0.7f; 24 SpeedY += 5; 25 if (Input.mousePosition.x >= Screen.width / 2) 26 { 27 if (Input.GetMouseButton(0)) {// 右側をタップしたら 28 SpeedX += 0.1f; 29 Muki -= 1; 30 } 31 } 32 else 33 { 34 if (Input.GetMouseButton(0)) {// 左側をタップしたら 35 SpeedX -= 0.1f; 36 Muki += 1; 37 } 38 } 39 40 if(SpeedY > 0){ 41 void OnTriggerEnter(Collider other) 42 { 43 //接触したオブジェクトのタグが"Ground"のとき 44 if(other.CompareTag("Ground")) 45 { 46 47 SpeedY = -65; 48 } 49 } 50 51 } 52 53 transform.position += new Vector3 (SpeedX*0.5f, 0, 0); 54 transform.rotation = Quaternion.Euler(0, 0, Muki*2); 55 Vector3 pos = transform.position; 56 pos.x = Mathf.Clamp(pos.x, screenLeft, screenRight); 57 transform.position = pos; 58 59 } 60 61 internal static float getSpeedY() 62 { 63 throw new NotImplementedException(); 64 } 65 66 public static int GetSpeedY(){ 67 return SpeedY; 68 } 69 70}

地面のスクリプトです↓

C#

1using System.Collections; 2using System.Collections.Generic; 3using UnityEngine; 4 5public class GameGround : MonoBehaviour 6{ 7 8 public PlayerIdou playerIdou; 9 10 // Start is called before the first frame update 11 void Start() 12 { 13 14 } 15 16 // Update is called once per frame 17 void Update() 18 { 19 float Jump; 20 Jump = PlayerIdou.SpeedY; 21 transform.position += new Vector3 (0, Jump*0.01f, 0); 22 } 23} 24

キャラクターにはPlayerのタグ、Rigidbody2D、Box Collider2Dをつけています。
地面にはGroundのタグと、Box Collider2Dをつけてあります。
このゲームは、キャラクターのy座標を変えたくないので、地面の位置を動かしています。

ネットで調べたことはほぼやったつもりですが、解決できなかったので質問させていただきました。
unityのバージョンは2020.3.14f1です。

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

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

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

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

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

guest

回答2

0

ベストアンサー

まずOnTriggerEnter()がUpdate()の中に定義されている時点で間違っております。
関数の中に関数を定義した場合、その関数(今回の場合Update())でしか呼び出すことはできません。
したがって、Unity本体からOnTriggerEnter()が呼び出せず、動作しません。

また、OnTriggerEnter()は3D用のものなので、2D用のもの(Rigidbody2Dなど)を使用する場合はOnTriggerEnter2D()でなければなりません。

また、OnTriggerEnter()を使っているということはIs Triggerがオンにしているとは思いますが、その場合ぶつかってもすり抜けてしまいます。
(スクリプトで制御しているのかもしれませんが、念のため)


追記:

変更箇所が多かったので、修正したコードを記載します。

C#

1using System; 2using System.Collections; 3using System.Collections.Generic; 4using UnityEngine; 5 6public class PlayerIdou : MonoBehaviour 7{ 8 public float SpeedX; 9 public static int SpeedY = -65; 10 public float Muki; 11 float screenLeft = -2;//左端の座標x 12 float screenRight = 2;//右端の座標x 13 14 Rigidbody2D rigidbody2DComponent; 15 bool tapLeft = false; 16 bool tapRight = false; 17 18 void Start() 19 { 20 rigidbody2DComponent = GetComponent<Rigidbody2D>(); 21 } 22 23 // Update is called once per frame 24 void Update() 25 { 26 if (Input.mousePosition.x >= Screen.width / 2) 27 { 28 if (Input.GetMouseButton(0)) 29 {// 右側をタップしたら 30 tapRight = true; 31 } 32 } 33 else 34 { 35 if (Input.GetMouseButton(0)) 36 {// 左側をタップしたら 37 tapLeft = true; 38 } 39 } 40 } 41 42 void FixedUpdate() 43 { 44 SpeedX = SpeedX * 0.7f; 45 Muki = Muki * 0.7f; 46 SpeedY += 5; 47 48 if (tapRight) 49 {// 右側をタップしたら 50 SpeedX += 0.1f; 51 Muki -= 1; 52 } 53 tapRight = false; 54 55 if (tapLeft) 56 {// 左側をタップしたら 57 SpeedX -= 0.1f; 58 Muki += 1; 59 } 60 tapLeft = false; 61 62 Vector3 pos = transform.position + new Vector3(SpeedX * 0.5f, 0, 0); 63 rigidbody2DComponent.MoveRotation(Quaternion.Euler(0, 0, Muki * 2)); 64 pos.x = Mathf.Clamp(pos.x, screenLeft, screenRight); 65 rigidbody2DComponent.MovePosition(pos); 66 } 67 68 internal static float getSpeedY() 69 { 70 throw new NotImplementedException(); 71 } 72 73 public static int GetSpeedY() 74 { 75 return SpeedY; 76 } 77 78 void OnCollisionEnter2D(Collision2D other) 79 { 80 //接触したオブジェクトのタグが"Ground"のとき 81 if (other.gameObject.CompareTag("Ground")) 82 { 83 SpeedY = -65; 84 } 85 } 86}

C#

1using System.Collections; 2using System.Collections.Generic; 3using UnityEngine; 4 5public class GameGround : MonoBehaviour 6{ 7 8 public PlayerIdou playerIdou; 9 Rigidbody2D rigidbody2DComponent; 10 11 // Start is called before the first frame update 12 void Start() 13 { 14 rigidbody2DComponent = GetComponent<Rigidbody2D>(); 15 } 16 17 void FixedUpdate() 18 { 19 float Jump; 20 Jump = PlayerIdou.SpeedY; 21 rigidbody2DComponent.MovePosition(transform.position + new Vector3(0, Jump * 0.01f, 0)); 22 } 23}

また、Box Collider2DとRigidbody2Dを両方に付けて、Rigidbody2Dを以下のように設定しました。

  • Body Type: Kinematic
  • Use Full Kinematic Contacts: ON
  • Collision Detection: Continuous(上記2つで上手くいかない場合)

以下、変更した箇所についての説明です。

  • OnTriggerEnter()からOnCollisionEnter2D()に変更しております。
    Is Triggerを解除した場合は、OnTriggerEnter2D()では取得できないため、OnCollisionEnter2D()にしています。
  • 物理判定や移動を行うものについては、Update()ではなくFixedUpdate()を使います。
    ただし、操作入力の取得は逆にUpdate()でないといけないので、tapLeftやtapRightのように変数を仲介させるようにしましょう。
  • 移動させる処理もtransformだと貫通することがあるので、Rigidbody2Dを使って移動させます。
    移動方法は色々ありますが、今回はMovePosition()やMoveRotation()を使っています。
    ただし、これらはRigidbody2DがKinematicでないと正しく動作しないため、そのように設定しております。
    また、オブジェクトの大きさや速度次第では、これでも貫通する可能性があるので、必要に応じてContinuousを設定する必要があります。

あと、変更はしていませんが、気になった点として以下があります。

  • SpeedYがstaticですが、そうした意味が理解できませんでした。
    むしろ、staticだと「Playerを2つ以上用意できない」「Playerを破棄した後もSpeedYの値が残ってしまう」という問題があります。
    GameGroundにplayerIdouを用意してあるのだから、それにPlayerIdouをインスペクターで指定させればいい話だと思いますが、どうでしょう。

投稿2021/08/12 09:37

編集2021/08/13 01:35
fiveHundred

総合スコア10152

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

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

youngdoonatsu

2021/08/12 13:11

ご回答ありがとうございます。OnTriggerEnter2D()を使用すると、"Script error: OnTriggerEnter2D This message parameter has to be of type: Collider2D The message will be ignored."というエラーが出てしまいます。
youngdoonatsu

2021/08/12 13:43

本当にごめんなさい!上のは嘘ですすみません。しっかりプログラムを設定してなくて起きてしまいました。 エラーは無くなりましたが、まだ地面を貫通してしまいます…Box ColliderのIs triggerはどちらも解除済みなのですが…
fiveHundred

2021/08/13 01:46

少し前に追記しました。
guest

0

僕も同じことが昔あったのですが…
コードの問題ではなく
キャラクターと地面の方に
Colliderがついているかかくにんしてみてください。

投稿2021/08/13 07:11

Imitubori

総合スコア7

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

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

guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問