カメラが初期位置から移動しなかったのは、オフセットがUpdate中のoffset = transform.position - player.position;
のために毎回「その時点のカメラの位置 - その時点のプレイヤーの位置」に更新されてしまっていたためかと思います。
ご参考として修正案を考えてみましたが、いかがでしょうか?
なるべく元のコードを残そうとしたつもりでしたが、ご質問者さんの意図する動きを想像しながらいじっているうちに、結構変わってしまいました。すみません...
左右上下キー押下時のプレイヤー移動方向の切り替え案として、基準とするべき右方向・前方向をカメラに持たせておいて、プレイヤーはそれを見て進む方向を決めるようにしてみました。
スクリプト名はご質問者さんのものに合わせて読み替えてください。変数などをいくらか追加しましたが、名前がちょっと冗長な気がするので、お好きな名前を付けていただくといいかと思います。
カメラのスクリプト(LookRotation版)
C#
1using UnityEngine;
2
3public class CameraController : MonoBehaviour
4{
5 private const float CameraDeltaOffsetSqrMagnitudeThreshold = 0.0001f;
6
7 // キャラクターのTransform
8 public Transform player;
9 // カメラの移動スピード
10 public float cameraMoveSpeed;
11 // カメラの回転スピード
12 public float cameraRotateSpeed;
13 // カメラのキャラクターからの相対値を指定
14 private Vector3 offset;
15 // Start時のキャラクターに対するカメラの相対位置をプレイヤーのローカル座標系で保存
16 private Vector3 initialPlayerLocalOffset;
17
18 public Vector3 CameraRight { get; private set; } // 変更...バッキングフィールドとしてcameraRightを用意するより、CameraRightをCameraControllerだけから設定可能なプロパティとした方がコードがシンプルになるかと思いました
19 public Vector3 CameraForward { get; private set; } // 変更...CameraRightと同じく、CameraControllerだけから設定可能なプロパティとしました
20
21 bool flag = false;
22
23 void Start ()
24 {
25 //プレイヤーとカメラの距離を計算する
26 offset = transform.position - player.position;
27 transform.rotation = Quaternion.LookRotation(-offset); // offsetが更新されたので、カメラ回転も更新
28
29 initialPlayerLocalOffset = player.InverseTransformDirection(offset); // offsetをプレイヤーローカル座標系に直すパターンを採用
30
31 CameraRight = transform.right; // カメラの右方向を設定
32
33 var newForward = transform.forward; // 追加
34
35 newForward.y = 0.0f; // 追加...カメラの前方向をXZ平面上に投影
36 newForward.Normalize(); // 追加...正規化し長さを1に
37 CameraForward = newForward; // 変更...新しい前方向ベクトルを設定
38 }
39
40 void Update ()
41 {
42 //ALtキーを押すとカメラの位置をプレイヤーの真後ろへリセットする
43 if (Input.GetKeyDown (KeyCode.LeftAlt) || Input.GetKeyDown (KeyCode.RightAlt))
44 {
45 flag = true;
46 }
47 if (flag == true)
48 {
49 //プレイヤーの背後へ移動
50 Vector3 destinationOffset = player.TransformDirection(initialPlayerLocalOffset); // Start時にプレイヤーの座標系で見たカメラの位置を保存しておいたので、そこからカメラの目標オフセットを求める
51
52 // offset = Vector3.Slerp (offset, destinationOffset, cameraMoveSpeed * Time.deltaTime); // 変更...LerpをSlerpにして、カメラの動きが球面上の軌道を取るようにしてみました(Lerpの方がお好みでしたら、そちらでも問題ありません)
53 offset = InterpolateOffset(offset, destinationOffset, cameraMoveSpeed * Time.deltaTime); // 追加...Slerpの代わりにカスタム補間メソッドを使った場合
54 transform.rotation = Quaternion.LookRotation(-offset); // offsetが更新されたので、カメラ回転も更新
55 //回転が終わったら通常の追従状態に戻る?
56 if ((offset - destinationOffset).sqrMagnitude < CameraDeltaOffsetSqrMagnitudeThreshold)
57 {
58 offset = destinationOffset; // 目標オフセットに完全に移動する
59 transform.rotation = Quaternion.LookRotation(-offset); // offsetが更新されたので、カメラ回転も更新
60 CameraRight = transform.right; // カメラの右方向を更新、以後プレイヤーは新しい右方向を基準に移動するようになる
61
62 var newForward = transform.forward; // 追加
63
64 newForward.y = 0.0f; // 追加...カメラの前方向をXZ平面上に投影
65 newForward.Normalize(); // 追加...正規化し長さを1に
66 CameraForward = newForward; // 変更...新しい前方向ベクトルを設定、以後プレイヤーは新しい前方向を基準に移動するようになる
67 flag = false;
68 }
69 }
70 transform.position = player.position + offset;
71 }
72
73 // 追加...offsetの補間用メソッド
74 static Vector3 InterpolateOffset(Vector3 a, Vector3 b, float t)
75 {
76 var aXZ = new Vector2(a.x, a.z); // 真上から見たa
77 var aR = aXZ.magnitude; // aのY軸からの距離
78 var aRIsNotZero = aR > 1E-05; // aRが(ほぼ)0より大きいか?
79 var aD = aRIsNotZero ? aXZ / aR : Vector2.zero; // 真上から見たaの方角、aRがほぼ0ならVector2.zeroとして無回転にする
80 var bXZ = new Vector2(b.x, b.z); // 真上から見たb
81 var bR = bXZ.magnitude; // bのY軸からの距離
82 var bD = (bR > 1E-05) ? bXZ / bR : Vector2.zero; // 真上から見たbの方角、bRがほぼ0ならVector2.zeroとして無回転にする
83 var theta = Mathf.Sign(aD.x * bD.y - bD.x * aD.y) * Mathf.Acos(Mathf.Clamp(Vector2.Dot(aD, bD), -1.0f, 1.0f)); // aDとbDがなす弧度法による符号付き角度
84 var alpha = aRIsNotZero ? Mathf.Atan2(aD.y, aD.x) : Mathf.Atan2(bD.y, bD.x); // 基準の角度...aDとX軸のなす角(aRがほぼ0ならbDとX軸のなす角)
85 var newTheta = Mathf.Lerp(0.0f, theta, t); // aDとbDがなす角度を線形補間
86 var newPhi = alpha + newTheta; // 基準の角度に先ほど線形補間した角度を足して、これを真上から見たときの新たな方角とする
87 var newR = Mathf.Lerp(aR, bR, t); // Y軸からの距離を線形補間
88 var newX = Mathf.Cos(newPhi) * newR; // 新しいX座標
89 var newY = Mathf.Lerp(a.y, b.y, t); // 新しいY座標(aとbのY座標を線形補間)
90 var newZ = Mathf.Sin(newPhi) * newR; // 新しいZ座標
91
92 return new Vector3(newX, newY, newZ);
93 }
94}
プレイヤーのスクリプト
C#
1using UnityEngine;
2
3public class PlayerController : MonoBehaviour
4{
5 public CameraController cameraController; // 追加...カメラの右・前方向を知りたいので、カメラのスクリプトを保持するようにしました(インスペクタでカメラをセットしておいてください)
6
7 // Use this for initialization
8 private void Start()
9 {
10
11 }
12
13 // Update is called once per frame
14 private void Update()
15 {
16 float dirH, dirV;
17 float dirSpeed = 0.1f; // これは使用していないようですが、一応残しています
18 dirH = Input.GetAxis ("Horizontal");
19 dirV = Input.GetAxis ("Vertical");
20
21 // 削除...移動はvecを求めてから行う
22 /*
23 transform.position = new Vector3 (transform.position.x - dirH * 0.1f, //横移動
24 transform.position.y,
25 transform.position.z - dirV * 0.1f); //奥移動
26 */
27
28 var vec = cameraController.CameraRight * (dirH * 0.1f) + cameraController.CameraForward * (dirV * 0.1f); // 変更...入力された移動量について、水平はCameraRight、垂直はCameraForwardの向きへの移動と考え、これをvecとする
29
30 transform.Translate(vec, Space.World); // 追加...位置をvecだけ移動
31
32 // 追加...立ち止まったときに初期の向きに戻ってしまうのを防ぐため、入力がゼロ以外の時しか向きを回転しない
33 // カメラのスクリプトでやったのと同じく、vec.sqrMagnitudeが一定値未満かどうかで判定すれば、入力の有無の判定にあそびを設けることもできると思います
34 if (vec != Vector3.zero)
35 {
36 // ここから...
37 vec.Normalize ();
38 //方向を求める
39 var dirRot = Mathf.Atan2 (vec.x, vec.z) / 3.14159265f * 180.0f;
40 transform.eulerAngles = new Vector3 (0.0f, dirRot, 0.0f);
41 // ここまでの代わりに、下記のような回転方法もアリかと思います
42 // transform.rotation = Quaternion.FromToRotation(Vector3.forward, vec);
43 }
44 }
45}
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/11/23 14:16
2017/11/23 15:42
2017/11/24 06:10
2017/11/24 13:35
2017/11/24 15:04
2017/11/24 21:25
2017/11/25 12:22