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

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

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

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

Q&A

解決済

1回答

1720閲覧

(unity) charactercontrollerオブジェクトのtransform.SetParentで親子移動について

kumao23

総合スコア10

Unity

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

0グッド

0クリップ

投稿2021/07/14 12:51

編集2021/07/16 21:19

前提・実現したいこと

charactercontrollerのついたオブジェクトが左右に動く床に乗ったとき、transform.SetParentで同方向に移動させる。

発生している問題・エラーメッセージ

charactercontrollerがついてないオブジェクトはtransform.SetParentで親子移動できたのですが、charactercontrollerがついてしまうと親子移動せずに落ちてしまいます。
下記**[プレイヤーが床に乗ったときに子にするコード]**で床の子要素になっているところまでは確認できています。

■追記です。
最小構成で新規にプロジェクトを作り直してみました。使っていたパーツはそのままです。
以下のページにそのプロジェクトファイルをzipにしておいてあります。もし、見て頂ける方がおられましたらお願いします。

https://firestorage.jp/download/483c6e64f7fc36f536d971df2f2ca914e4b77e59

該当のソースコード

[動く床側のコード]

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MoveFloor : MonoBehaviour
{
public float moveState;
public float speed;
Vector3 vector;

// Start is called before the first frame update void Start() { vector = transform.localPosition; } // Update is called once per frame void Update() { float x = moveState * Mathf.Sin(Time.time * speed); transform.localPosition = vector + new Vector3(x, 0, 0); }

}

[プレイヤーが床に乗ったときに子にするコード]

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MoveFloorPlayer : MonoBehaviour
{
private CharacterController controller;

// Start is called before the first frame update void Start() { controller = GetComponent<CharacterController>(); } // Update is called once per frame void Update() { } //void OnCollisionEnter(Collision col) void OnControllerColliderHit(ControllerColliderHit hit) { if (hit.gameObject.tag == "MoveFloor") { transform.SetParent(hit.transform); } }

}

[プレイヤーを操作するコード]

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CameraController : MonoBehaviour
{
public float rotate;
public float speedup;
private CharacterController characterController; //CharacterControllerの機能を使うためにcharacterControllerという変数を作成
private Vector3 Velocity; //CharacterControllerを動かすためのVector3型の変数を作成

[SerializeField] private float jumpPower; //ジャンプ力を入れるための変数 [SerializeField] private float moveSpeed; //移動スピードを入れるための変数 // Start is called before the first frame update void Start() { characterController = GetComponent<CharacterController>(); //characterControllerにCharacterControllerを代入する } // Update is called once per frame void Update() { characterController.Move(Velocity); //characterControllerをVelocity動かす if (Input.GetKey(KeyCode.W)) { characterController.Move(this.gameObject.transform.forward * moveSpeed * Time.deltaTime); } if (Input.GetKey(KeyCode.S)) { characterController.Move(this.gameObject.transform.forward * -1f * moveSpeed * Time.deltaTime); } if (Input.GetKey(KeyCode.A)) { characterController.Move(this.gameObject.transform.right * -1 * moveSpeed * Time.deltaTime); } if (Input.GetKey(KeyCode.D)) { characterController.Move(this.gameObject.transform.right * moveSpeed * Time.deltaTime); } characterController.Move(Velocity * Time.deltaTime); //characterControllerをVelocity * 時間の経過分動かす Velocity.y += Physics.gravity.y * Time.deltaTime/20; if (characterController.isGrounded) //もしcharacterControllerが地面に着いていたら { if (Input.GetKey(KeyCode.Space)) //もしSpaceキーがおされたら { Velocity.y = jumpPower; } } }

}

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

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

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

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

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

guest

回答1

0

ベストアンサー

どうやらCharacterControllerに親子関係形成による移動は通用しなさそうですね。Moveを使って動かしてはいかがでしょうか?

まず、MoveFloorPlayerを下記のように変更してみました。

lang

1using System.Collections; 2using System.Collections.Generic; 3using UnityEngine; 4 5public class MoveFloorPlayer : MonoBehaviour 6{ 7 private CharacterController controller; 8 9 // Start is called before the first frame update 10 void Start() 11 { 12 controller = GetComponent<CharacterController>(); 13 14 } 15 16 // Update is called once per frame 17 void Update() 18 { 19 20 } 21 22 //void OnCollisionEnter(Collision col) 23 void OnControllerColliderHit(ControllerColliderHit hit) 24 { 25 if (hit.gameObject.tag == "MoveFloor") 26 { 27 // 親子関係を作るのはやめる 28 // transform.SetParent(hit.transform); 29 30 // 代わりに、衝突相手に対してOnControllerStay(名前は適当に決めました)メッセージを送る 31 hit.gameObject.BroadcastMessage("OnControllerStay", hit.controller, SendMessageOptions.DontRequireReceiver); 32 33 // 念のため、コンソールに衝突相手と現在のフレーム番号を表示してみる 34 // コンソールをご確認いただくとおわかりかと思いますが、OnControllerColliderHitは 35 // Moveによる移動で衝突が発生するたびに起動するため、1フレームに複数回発生しうるでしょう 36 // そのため、OnControllerStayもそれを考慮した実装にする必要があるかと思います 37 Debug.Log($"on {hit.gameObject.name}:{Time.frameCount}"); 38 } 39 } 40}

そしてMoveFloorは下記のようにしました。これならどうでしょうか。

lang

1using System.Collections; 2using System.Collections.Generic; 3using UnityEngine; 4 5public class MoveFloor : MonoBehaviour 6{ 7 //float型を変数moveStateで宣言します。 8 public float moveState; 9 //float型を変数speedで宣言します。 10 public float speed; 11 //Vector3型を変数vectorで宣言します。 12 Vector3 vector; 13 14 // 前回の位置を保持しておくフィールドを追加 15 Vector3 previousPosition; 16 17 // フレーム間の位置の変位を保持しておくフィールドを追加 18 Vector3 deltaPosition; 19 20 // 後述のOnControllerStayで、処理済みのCharacterControllerを識別するために使う 21 readonly HashSet<CharacterController> processedControllers = new HashSet<CharacterController>(); 22 23 // Start is called before the first frame update 24 void Start() 25 { 26 //初期位置を保存します。 27 vector = transform.localPosition; 28 previousPosition = vector; 29 } 30 31 // Update is called once per frame 32 void Update() 33 { 34 //x軸に移動する移動範囲とスピードの計算をします。 35 float x = moveState * Mathf.Sin(Time.time * speed); 36 //割当られた数値を元にz軸のポジションを決定します。 37 // このときに、併せてpreviousPositionからどれだけ移動したかを求めて 38 // deltaPositionを更新、そののち次のUpdateに備えてpreviousPositionを更新 39 Vector3 newPosition = vector + new Vector3(x, 0, 0); 40 deltaPosition = newPosition - previousPosition; 41 transform.localPosition = newPosition; 42 previousPosition = newPosition; 43 44 // deltaPositionが更新されたので、processedControllersも空にする 45 processedControllers.Clear(); 46 } 47 48 // OnControllerStayメッセージを受け取ったら... 49 void OnControllerStay(CharacterController controller) 50 { 51 // 相手のCharacterControllerが処理済みなら何もしない 52 if (processedControllers.Contains(controller)) 53 { 54 return; 55 } 56 57 // 相手のCharacterControllerを処理済みとして記録する 58 processedControllers.Add(controller); 59 60 // 相手のCharacterControllerをdeltaPositionだけ動かす 61 controller.Move(deltaPosition); 62 } 63}

図

投稿2021/07/16 21:33

編集2021/07/16 23:07
Bongo

総合スコア10811

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

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

kumao23

2021/07/17 11:44

Bongo様。 今回もとても有難いご回答有難う御座います。 まだ、内容の改変について読み切れていませんが、書き換えたのちの動作は完璧で御座います。 またまた助けて頂き、ひたすら感謝で御座います。 今から改良された内容を少しずつ読み解いて頭の中に入れていきます。 本当に本当にありがとうございました!!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問