🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
C#

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

Unity3D

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

Unity

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

Q&A

解決済

2回答

2024閲覧

UnityC# TPSカメラの角度が上手に求められず反転してしまう

Karakuri_Polta

総合スコア50

C#

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

Unity3D

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

Unity

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

0グッド

0クリップ

投稿2019/01/21 13:37

tpsのゲームのカメラ制御を作っている際に、このようなプログラムを書いていたら

C#

1using System.Collections; 2using System.Collections.Generic; 3using UnityEngine; 4 5public class PlayerCam : MonoBehaviour 6{ 7 public GameObject targetObj; 8 public float camRotateHorizontalSpeed; 9 public float camRotateVerticalSpeed; 10 public float camJoyStickRotateHorizontalSpeed; 11 public float camJoyStickRotateVerticntalSpeed; 12 13 public float minVerticalLimit; 14 public float maxVerticalLimit; 15 16 public Vector3 defaulltCamPos; 17 bool afterSetFirstFrame; 18 Vector3 prevTargetPos; 19 20 public bool cursorLocking; 21 22 [SerializeField] GameObject pauseUI; 23 24 // Start is called before the first frame update 25 void Start() 26 { 27 targetObj = null; 28 afterSetFirstFrame = true; 29 //カーソルをロック 30 cursorLocking = true; 31 Cursor.lockState = CursorLockMode.Locked; 32 Cursor.visible = false; 33 pauseUI.SetActive(false); 34 } 35 36 // Update is called once per frame 37 void Update() 38 { 39 if (Input.GetKeyDown(KeyCode.Escape)) 40 { 41 //カーソルロック解除 42 Cursor.lockState = CursorLockMode.None; 43 Cursor.visible = true; 44 cursorLocking = false; 45 pauseUI.SetActive(true); 46 } 47 48 if (targetObj != null) 49 { 50 if (afterSetFirstFrame) 51 { 52 afterSetFirstFrame = false; 53 prevTargetPos = targetObj.transform.position; 54 transform.position = prevTargetPos + defaulltCamPos; 55 } 56 else 57 { 58 //↓ProgressOfCam↓ 59 //move 60 transform.position += targetObj.transform.position - prevTargetPos; 61 prevTargetPos = targetObj.transform.position; 62 63 float mouseMoveX = Input.GetAxis("Mouse X"); 64 float mouseMoveY = Input.GetAxis("Mouse Y"); 65 float rightStickX = Input.GetAxis("RightStickHorizontal"); 66 float rightStickY = Input.GetAxis("RightStickVertical"); 67 68 if (cursorLocking) 69 { 70 //カメラの回転 71 transform.RotateAround(prevTargetPos, Vector3.up, (mouseMoveX + Input.GetAxis("RightStickHorizontal") * camJoyStickRotateHorizontalSpeed) * Time.deltaTime * camRotateHorizontalSpeed); 72 transform.RotateAround(prevTargetPos, transform.right, (mouseMoveY + Input.GetAxis("RightStickVertical") * camJoyStickRotateVerticntalSpeed) * Time.deltaTime * camRotateVerticalSpeed); 73 float fLEAX = fixedLocalEulerAngleX(); 74 75 Debug.Log("MouseX:" + mouseMoveX.ToString() + "MouseY:" + mouseMoveY.ToString() + "StickX:" + rightStickX.ToString() + "StickY:" + rightStickY.ToString() + "RotateX:" + transform.eulerAngles.x.ToString() + "FixedRotateX:" + fLEAX); 76 //!!!!問題点!!!!上限・下限を超えた場合にもとに戻す処理がうまくいかない 77 if (fLEAX < minVerticalLimit || fLEAX > maxVerticalLimit) 78 transform.RotateAround(prevTargetPos, transform.right, 0 - (mouseMoveY + Input.GetAxis("RightStickVertical") * camJoyStickRotateVerticntalSpeed) * Time.deltaTime * camRotateVerticalSpeed); 79 } 80 } 81 } 82 83 84 } 85 86 //localEulerAngle.xを-90<x<=270に修正 87 float fixedLocalEulerAngleX() 88 { 89 float lEAX = transform.localEulerAngles.x; 90 91 if (lEAX <= 270) return lEAX; else return lEAX - 360; 92 } 93} 94

マウスを縦に動かす大きさが大きすぎるとx軸の回転が大きくなりすぎて上下逆になってしまいます。
上限・下限を超した場合の計算がうまくいかないようです。
360°でx軸の角度を求められないのでしょうか?
または反転しないように他の工夫が出来るのでしょうか?

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

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

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

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

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

guest

回答2

0

あまり正攻法ではありませんが、コードが少なくなる以下の方法はどうでしょう。

cs:

1using UnityEngine; 2 3public class CameraScript : MonoBehaviour 4{ 5 6 public Transform Center; 7 // Update is called once per frame 8 void Update() 9 { 10 transform.LookAt(Center); 11 } 12}

cs:

1using UnityEngine; 2 3public class RotateCamera : MonoBehaviour 4{ 5 6 public float Speed=1; 7 // Update is called once per frame 8 void Update() 9 { 10 var mouseMoveX = Input.GetAxis("Mouse X"); 11 var mouseMoveY = Input.GetAxis("Mouse Y"); 12 13 transform.Rotate(new Vector3(mouseMoveY, mouseMoveX) * Speed); 14 } 15} 16

この2つのスクリプトを作成し、シーン上に以下のように貼り付けます。
イメージ説明
Positionのxが少しずれているのは、その方がゆっくりとした天地反転になってくれるからです。

イメージ説明

これで恐らく上下反転せずに回転するはずです。
キャラクターの位置を動かしたい場合は、PlayerCenterの方を動かしてください

投稿2019/01/24 07:58

編集2019/01/24 08:14
yuto_onizakura

総合スコア52

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

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

Karakuri_Polta

2019/01/24 08:22

なるほど…そんな方法もあったんですね… 今回はシステムそのままで行きたかったのでベストアンサーにはしませんでしたがとても勉強になりました! ありがとうございました!
guest

0

ベストアンサー

Unity の回転と向き - Unity マニュアルの中に...

ただし、スクリプトでオイラー角を使用したほうがよい場合があります。そのような場合は、角度を変数に代入し、オイラー角として回転に適用するためにだけ使用することが重要です。オイラー角をクォータニオンから取得することは可能ですが、取得、変更、再適用すると、問題が発生します。

という記述があります。ご質問者さんのコードは一見するとオイラー角の取得のみ行っており再適用していないため、マニュアルの警告にあるケースには当てはまらないように思われるかもしれませんが、似たような問題が発生しうるでしょう。
角度の範囲制限をなくした状態でカメラを垂直に回転させていきコンソールのRotateXを観察すると、おそらく-90°や90°を越えたところで角度の増減方向が逆になるかと思います。この意図しない角度をもとに範囲制限が行われてしまうと、制限結果も意図しないものになってしまうはずです。

マニュアルに例示されている...

以下は、スクリプトでオイラー角を使う時の正しい使用法です。

// 正しくオイラー角を用いた回転スクリプト。 // ここでは、オイラー角をクラス変数として格納します。 //それをオイラー角として使用しますが、決してオイラー角として読み込みには使いません。 float x; void Update () { x += Time.deltaTime * 10; transform.rotation = Quaternion.Euler(x,0,0); }

に似せた形に変えて、下記のように制限を加えてみるのはいかがでしょうか?

C#

1using System.Collections; 2using System.Collections.Generic; 3using UnityEngine; 4 5public class PlayerCam : MonoBehaviour 6{ 7 public GameObject targetObj; 8 public float camRotateHorizontalSpeed; 9 public float camRotateVerticalSpeed; 10 public float camJoyStickRotateHorizontalSpeed; 11 public float camJoyStickRotateVerticntalSpeed; 12 13 public float minVerticalLimit; 14 public float maxVerticalLimit; 15 16 public Vector3 defaulltCamPos; 17 bool afterSetFirstFrame; 18 Vector3 prevTargetPos; 19 20 public bool cursorLocking; 21 22 [SerializeField] GameObject pauseUI; 23 24 // X軸回転角を積算するためのフィールドを追加 25 float verticalAngle; 26 27 // Start is called before the first frame update 28 void Start() 29 { 30 targetObj = null; 31 afterSetFirstFrame = true; 32 //カーソルをロック 33 cursorLocking = true; 34 Cursor.lockState = CursorLockMode.Locked; 35 Cursor.visible = false; 36 pauseUI.SetActive(false); 37 } 38 39 // Update is called once per frame 40 void Update() 41 { 42 if (Input.GetKeyDown(KeyCode.Escape)) 43 { 44 //カーソルロック解除 45 Cursor.lockState = CursorLockMode.None; 46 Cursor.visible = true; 47 cursorLocking = false; 48 pauseUI.SetActive(true); 49 } 50 51 if (targetObj != null) 52 { 53 if (afterSetFirstFrame) 54 { 55 afterSetFirstFrame = false; 56 prevTargetPos = targetObj.transform.position; 57 transform.position = prevTargetPos + defaulltCamPos; 58 59 // 初期X軸周り角度としてカメラのオイラー角Xを代入し 60 // これ以降はtransform.localEulerAngles.xは見ないことにする 61 verticalAngle = transform.localEulerAngles.x; 62 } 63 else 64 { 65 //↓ProgressOfCam↓ 66 //move 67 transform.position += targetObj.transform.position - prevTargetPos; 68 prevTargetPos = targetObj.transform.position; 69 70 float mouseMoveX = Input.GetAxis("Mouse X"); 71 float mouseMoveY = Input.GetAxis("Mouse Y"); 72 float rightStickX = Input.GetAxis("RightStickHorizontal"); 73 float rightStickY = Input.GetAxis("RightStickVertical"); 74 75 if (cursorLocking) 76 { 77 //カメラの回転 78 // 水平操作はそのままでいいとして... 79 transform.RotateAround(prevTargetPos, Vector3.up, (mouseMoveX + Input.GetAxis("RightStickHorizontal") * camJoyStickRotateHorizontalSpeed) * Time.deltaTime * camRotateHorizontalSpeed); 80 81 // 垂直操作を少し修正 82 // 入力された垂直回転角を... 83 float verticalAngleDelta = (mouseMoveY + Input.GetAxis("RightStickVertical") * camJoyStickRotateVerticntalSpeed) * Time.deltaTime * camRotateVerticalSpeed; 84 85 // verticalAngleと足し合わせ、nextVerticalAngleとし... 86 float nextVerticalAngle = verticalAngle + verticalAngleDelta; 87 88 // nextVerticalAngleを制限範囲内にクランプし... 89 nextVerticalAngle = Mathf.Clamp(nextVerticalAngle, minVerticalLimit, maxVerticalLimit); 90 91 // クランプ後の角度からverticalAngleDeltaを逆算し... 92 verticalAngleDelta = nextVerticalAngle - verticalAngle; 93 94 // カメラを垂直回転する 95 transform.RotateAround(prevTargetPos, transform.right, verticalAngleDelta); 96 97 // verticalAngleを新しい角度に更新する 98 verticalAngle = nextVerticalAngle; 99 100 Debug.Log("MouseX:" + mouseMoveX.ToString() + "MouseY:" + mouseMoveY.ToString() + "StickX:" + rightStickX.ToString() + "StickY:" + rightStickY.ToString() + "RotateX:" + transform.localEulerAngles.x.ToString()); 101 } 102 } 103 } 104 } 105 106 // fixedLocalEulerAngleXは廃止 107 /* 108 //localEulerAngle.xを-90<x<=270に修正 109 float fixedLocalEulerAngleX() 110 { 111 float lEAX = transform.localEulerAngles.x; 112 113 if (lEAX <= 270) return lEAX; else return lEAX - 360; 114 } 115 */ 116}

投稿2019/01/21 22:41

Bongo

総合スコア10811

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

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

Karakuri_Polta

2019/01/24 08:24

確かに、自分で計算して用意すれば正確ですね… 適用してみると確かに反転しなくなりました! 詳しい解説ありがとうございました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問