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

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

詳細はこちら
C#

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

Unity3D

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

Q&A

解決済

1回答

2407閲覧

カメラをマウスで移動しすぎると反転する

退会済みユーザー

退会済みユーザー

総合スコア0

C#

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

Unity3D

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

0グッド

0クリップ

投稿2019/12/23 16:02

カメラを主人公のまわりをマウスで移動させるスクリプトを作ったのですがY軸に激しく動かすと反転します。
反転させないようにしたいです!
このスクリプトは画像に乗っているCameraControllerに張り付けたスクリプトです。
public class CameraController : MonoBehaviour {

public GameObject player; public GameObject mainCamera; public float rotate_speed;

  private const int ROTATE_BUTTON = 1;
private const float ANGLE_LIMIT_UP = 60f;
private const float ANGLE_LIMIT_DOWN = -60f;

void Start() { mainCamera = Camera.main.gameObject; player = GameObject.FindGameObjectWithTag("Player"); } void Update() { transform.position = player.transform.position; if (Input.GetMouseButton(ROTATE_BUTTON)) { rotateCmaeraAngle(); } float angle_x = 180f <= transform.eulerAngles.x ? transform.eulerAngles.x - 360 :   transform.eulerAngles.x; transform.eulerAngles = new Vector3( Mathf.Clamp(angle_x, ANGLE_LIMIT_DOWN, ANGLE_LIMIT_UP), transform.eulerAngles.y, transform.eulerAngles.z ); }

  private void rotateCmaeraAngle() {
Vector3 angle = new Vector3(
Input.GetAxis("Mouse X") * rotate_speed,
Input.GetAxis("Mouse Y") * rotate_speed,
0
);

transform.eulerAngles += new Vector3(angle.y, angle.x);

}
}
イメージ説明
イメージ説明
回答くださると幸いです。

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

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

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

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

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

guest

回答1

0

ベストアンサー

transform.eulerAnglesからオイラー角を取得するというのはちょっと注意が必要ですね。内部的にはQuaternion型からの変換が起こっていますので、予期した角度とは違う角度(具体的に言うと、YやZが180°反転してXの増減方向が逆転した角度)が返ってくることがあるかと思います。縦にすばやくマウスを動かしてX角度が±90°を超えてしまうとこの現象が発生し、異常動作の原因となるでしょう。
以前見かけました他の方のご質問に「UnityC# TPSカメラの角度が上手に求められず反転してしまう」や「[Unity] オブジェクトのRotationの値を変化させたときの挙動について質問」といったものがあり、ご参考になるかもしれません。

現在のコードをなるべく維持したまま上記の問題を回避する一案として、下記のような形はどうでしょうか。

C#

1using UnityEngine; 2 3public class CameraController : MonoBehaviour { 4 5 public GameObject player; 6 public GameObject mainCamera; 7 public float rotate_speed; 8 private const int ROTATE_BUTTON = 1; 9 private const float ANGLE_LIMIT_UP = 60f; 10 private const float ANGLE_LIMIT_DOWN = -60f; 11 12 // クォータニオンとオイラー角の相互変換をせずにすむように、 13 // まずオイラー角保存用のフィールドを作り... 14 private Vector3 eulerAngles; 15 16 void Start() { 17 mainCamera = Camera.main.gameObject; 18 player = GameObject.FindGameObjectWithTag("Player"); 19 20 // Start時点のtransform.eulerAnglesを保存し、これ以降は 21 // transform.eulerAnglesからの値の取得は行わないようにする 22 eulerAngles = transform.eulerAngles; 23 } 24 25 void Update() { 26 transform.position = player.transform.position; 27 28 if (Input.GetMouseButton(ROTATE_BUTTON)) { 29 rotateCmaeraAngle(); 30 } 31 32 float angle_x = 180f <= eulerAngles.x ? eulerAngles.x - 360 : eulerAngles.x; 33 eulerAngles = new Vector3( 34 Mathf.Clamp(angle_x, ANGLE_LIMIT_DOWN, ANGLE_LIMIT_UP), 35 eulerAngles.y, 36 eulerAngles.z 37 ); 38 39 // ここまでの回転制御でtransform.eulerAnglesを使っていた部分は 40 // 代わりにeulerAnglesを使うよう変更し、最後にeulerAnglesを 41 // transform.eulerAnglesにセットする 42 transform.eulerAngles = eulerAngles; 43 } 44 45 private void rotateCmaeraAngle() { 46 Vector3 angle = new Vector3( 47 Input.GetAxis("Mouse X") * rotate_speed, 48 Input.GetAxis("Mouse Y") * rotate_speed, 49 0 50 ); 51 52 eulerAngles += new Vector3(angle.y, angle.x); 53 } 54}

投稿2019/12/23 22:42

Bongo

総合スコア10811

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

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

退会済みユーザー

退会済みユーザー

2019/12/24 09:53

なるほど(よくわかってない) ただ少しづつ理解できるように頑張りたいと思います! 丁寧に教えていただきありがとうございます!
退会済みユーザー

退会済みユーザー

2020/03/27 14:46 編集

なんども質問してすみません! 元々カメラでターゲット機能をつけていたので上記のようにスクリプトをつけたらそれらが機能しなくなりました。 どうすればよいでしょうか? private LockOnTargetDetector lockOnTargetDetector; [SerializeField] public GameObject lockOnTarget; void Start() { mainCamera = Camera.main.gameObject; player = GameObject.FindGameObjectWithTag("Player"); lockOnTargetDetector = player.GetComponentInChildren<LockOnTargetDetector>(); } void Update() { transform.position = player.transform.position; if (Input.GetKeyDown(KeyCode.R)) { GameObject target = lockOnTargetDetector.getTarget(); if (target != null) { lockOnTarget = target; } else { lockOnTarget = null; } } if (lockOnTarget) { lockOnTargetObject(lockOnTarget); } else { if (Input.GetMouseButton(ROTATE_BUTTON)) { rotateCmaeraAngle(); } } float angle_x = 180f <= transform.eulerAngles.x ? transform.eulerAngles.x - 360 : transform.eulerAngles.x; transform.eulerAngles = new Vector3( Mathf.Clamp(angle_x, ANGLE_LIMIT_DOWN, ANGLE_LIMIT_UP), transform.eulerAngles.y, transform.eulerAngles.z ); }
Bongo

2019/12/24 21:01

なるほど、ロックオン機能もあったのですね。 当初投稿したコードでは、Start内のコメントに「これ以降はtransform.eulerAnglesからの値の取得は行わないようにする」などと書いておきましたが、それを曲げてロックオン直後(transform.LookAt使用直後)にも... private void lockOnTargetObject(GameObject target) { transform.LookAt(target.transform, Vector3.up); eulerAngles = transform.eulerAngles; } といった具合にtransform.eulerAnglesから角度を再取得してeulerAnglesを更新してみるとどうでしょうか。 実際のところスクリプト全域でtransform.eulerAnglesの再取得を禁止しなくても、カメラのフリー回転処理の過程で「transform.eulerAnglesに大きく飛んだ角度が設定される」→「transform.eulerAnglesから意図しない角度が取得され、それを使って角度制限される」という現象が起こらないようにすれば十分なように思います。 もしたくさんの場所でtransform.LookAtのようなtransformの回転に影響を与える操作をしている場合、フリー回転処理だけを単独のメソッドにまとめてしまい(現状だと「rotateCmaeraAngle」と「X回転制限部分」の2カ所に分散していますよね)、そのメソッドの先頭部分でtransform.eulerAnglesの再取得をしてもいいでしょう。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問