teratail header banner
teratail header banner
質問するログイン新規登録

回答編集履歴

1

実験結果を追記

2017/07/06 14:36

投稿

Bongo
Bongo

スコア10816

answer CHANGED
@@ -1,2 +1,240 @@
1
1
  凹凸に触れると転がる...という点を考慮しますと、[Rigidbody](https://docs.unity3d.com/ja/540/Manual/class-Rigidbody.html)の設定がどうなっているか気になります。
2
- もし、「Freeze Rotation」に何もチェックがないようでしたら、「X」と「Z」にチェックを入れてY軸周り以外の回転を禁止してみるとどうでしょうか。
2
+ もし、「Freeze Rotation」に何もチェックがないようでしたら、「X」と「Z」にチェックを入れてY軸周り以外の回転を禁止してみるとどうでしょうか。
3
+
4
+ [コメントを受けて追記]
5
+ どちらも自機にアタッチ...ですか?まだ全体の構造を把握しきれておりませんが、ちょっと私なりの方法で実験してみましたので追記します。おそらく質問者さんのオブジェクトの階層構造と違っている点があるかと思いますが、ここをこうしたいなどありましたらご指摘ください。
6
+
7
+ 以下のようにオブジェクトを用意しました。
8
+ - シーンの直下に空のオブジェクトを置く。名前は「PlayerAndCamera」とする。
9
+ - PlayerAndCameraの下に「Player」を置く。原点はPlayerAndCameraと合わせる(ローカル座標がゼロ)。
10
+ - PlayerAndCameraの下に「Camera」を置く。Playerの背中を映す位置にする(ローカル座標Zは-3)。
11
+ - PlayerにSphere Colliderをアタッチする。オブジェクトの見た目と合うよう位置・サイズを調整する(Colliderは適宜質問者さんのプレイヤーオブジェクトに合わせて選定してください)。
12
+ - PlayerAndCameraにRigidbodyをアタッチする。Freeze RotationはX・Y・Zすべてチェックする(物理シミュレーションによる回転の影響が及ぶといまいちな気がしたので、Yも回転禁止しました)。
13
+ - スクリプトその1をPlayerAndCameraに、その2をCameraにアタッチする(ここは質問者さんの構成と違っていると思います)。
14
+ - スクリプトその1のSpeedをとりあえず5とする。
15
+
16
+ ```C#
17
+ // PlayerAndCameraにアタッチ、スクリプトその1と同等。
18
+ // コードを自動整形した結果、ifにカッコが付いたりthisが増えたりしていますが、内容は同じです
19
+ using UnityEngine;
20
+
21
+ public class PlayerAndCameraController : MonoBehaviour
22
+ {
23
+ public float Speed;
24
+
25
+ private void Start()
26
+ {
27
+ }
28
+
29
+ private void Update()
30
+ {
31
+ var vec = Vector3.zero;
32
+ if (Input.GetKey(KeyCode.W))
33
+ {
34
+ vec.z += 1.0f;
35
+ }
36
+ if (Input.GetKey(KeyCode.S))
37
+ {
38
+ vec.z -= 1.0f;
39
+ }
40
+ if (Input.GetKey(KeyCode.A))
41
+ {
42
+ vec.x -= 1.0f;
43
+ }
44
+ if (Input.GetKey(KeyCode.D))
45
+ {
46
+ vec.x += 1.0f;
47
+ }
48
+ vec = vec.normalized;
49
+ this.transform.position += vec * Time.deltaTime * this.Speed;
50
+ if (vec.magnitude > 0.0f)
51
+ {
52
+ this.transform.rotation = Quaternion.LookRotation(vec);
53
+ }
54
+ }
55
+ }
56
+ ```
57
+
58
+ ```C#
59
+ // Cameraにアタッチ、、スクリプトその2と同等。
60
+ // コードを自動整形した結果、ifにカッコが付いたりthisが増えたりしていますが、内容は同じです
61
+ using UnityEngine;
62
+
63
+ public class CameraController : MonoBehaviour
64
+ {
65
+ private void Start()
66
+ {
67
+ }
68
+
69
+ private void Update()
70
+ {
71
+ if (Input.GetKey(KeyCode.UpArrow))
72
+ {
73
+ this.transform.Rotate(1.0f, 0, 0);
74
+ }
75
+ if (Input.GetKey(KeyCode.DownArrow))
76
+ {
77
+ this.transform.Rotate(-1.0f, 0, 0);
78
+ }
79
+ if (Input.GetKey(KeyCode.LeftArrow))
80
+ {
81
+ this.transform.Rotate(0, -1.0f, 0);
82
+ }
83
+ if (Input.GetKey(KeyCode.RightArrow))
84
+ {
85
+ this.transform.Rotate(0, 1.0f, 0);
86
+ }
87
+ }
88
+ }
89
+ ```
90
+
91
+ これで実行すると、下図のようになりました。
92
+
93
+ ![実行図1](1fbcda5487da9f68f6917b913932490f.gif)
94
+
95
+ 確かにカメラはプレイヤーに追従しますが、常にプレイヤーの背後へ視点が飛んでめまぐるしい点と、矢印キーでカメラを動かすとカメラを振るような動きになり、プレイヤーをカメラ中心に捉えられない点がいまいちに感じましたので、両スクリプトを下記のように変更しました。
96
+
97
+ ```C#
98
+ // 最後の向き設定の部分を、PlayerAndCamera全体ではなくPlayerだけを回転させるように変更
99
+ using UnityEngine;
100
+
101
+ public class PlayerAndCameraController : MonoBehaviour
102
+ {
103
+ public float Speed;
104
+ private Transform playerTransform;
105
+
106
+ private void Start()
107
+ {
108
+ // Start内でPlayerのtransformを探しておく
109
+ this.playerTransform = this.transform.Find("Player");
110
+ }
111
+
112
+ private void Update()
113
+ {
114
+ var vec = Vector3.zero;
115
+ if (Input.GetKey(KeyCode.W))
116
+ {
117
+ vec.z += 1.0f;
118
+ }
119
+ if (Input.GetKey(KeyCode.S))
120
+ {
121
+ vec.z -= 1.0f;
122
+ }
123
+ if (Input.GetKey(KeyCode.A))
124
+ {
125
+ vec.x -= 1.0f;
126
+ }
127
+ if (Input.GetKey(KeyCode.D))
128
+ {
129
+ vec.x += 1.0f;
130
+ }
131
+ vec = vec.normalized;
132
+ this.transform.position += vec * Time.deltaTime * this.Speed; // もしこのスクリプトをPlayerAndCameraではなくPlayerにアタッチする場合、回転部分には修正を加えず、ここの移動部分を親(つまりPlayerAndCamera)を対象にするよう修正すればいけると思います
133
+ if (vec.magnitude > 0.0f)
134
+ {
135
+ // 自身のtransformに代わり、playerTransformを回転させる
136
+ this.playerTransform.rotation = Quaternion.LookRotation(vec);
137
+ }
138
+ }
139
+ }
140
+ ```
141
+
142
+ ```C#
143
+ // RotateをRotateAroundに変更
144
+ using UnityEngine;
145
+
146
+ public class CameraController : MonoBehaviour
147
+ {
148
+ private Transform playerTransform;
149
+
150
+ private void Start()
151
+ {
152
+ // Start内でPlayerのtransformを探しておき、そこを中心にRotateAroundで回転する
153
+ this.playerTransform = transform.parent.Find("Player");
154
+ }
155
+
156
+ private void Update()
157
+ {
158
+ // RotateAroundの回転軸は水平回転はワールドY軸、垂直回転はローカルX軸としました
159
+ // 一般的な地上を舞台にしたゲームならこれが妥当かと思いますが、たとえば宇宙空間を飛び回るような場合は両方ローカル軸にしても面白いかもしれません
160
+ // いろいろ軸をいじってみて、質問者さんのゲームに合った設定にしてみてください
161
+ if (Input.GetKey(KeyCode.UpArrow))
162
+ {
163
+ this.transform.RotateAround(this.playerTransform.position, transform.right, 1.0f);
164
+ }
165
+ if (Input.GetKey(KeyCode.DownArrow))
166
+ {
167
+ this.transform.RotateAround(this.playerTransform.position, transform.right, -1.0f);
168
+ }
169
+ if (Input.GetKey(KeyCode.LeftArrow))
170
+ {
171
+ this.transform.RotateAround(this.playerTransform.position, Vector3.up, 1.0f);
172
+ }
173
+ if (Input.GetKey(KeyCode.RightArrow))
174
+ {
175
+ this.transform.RotateAround(this.playerTransform.position, Vector3.up, -1.0f);
176
+ }
177
+ }
178
+ }
179
+ ```
180
+
181
+ これで実行すると、下図のようになります。
182
+
183
+ ![実行図2](11875a60b6f8585e9a7c041c31d8febc.gif)
184
+
185
+ さらに、移動部分をカメラローカル軸を基準に移動するように改造すれば、カメラの向きに対する前後左右に移動することも可能かと思います。
186
+
187
+ ```C#
188
+ // 移動方向をCameraのtransformのright(ローカルX+)とforward(ローカルZ+)を基準にするよう変更
189
+ using UnityEngine;
190
+
191
+ public class PlayerAndCameraController : MonoBehaviour
192
+ {
193
+ public float Speed;
194
+ private Transform cameraTransform;
195
+ private Transform playerTransform;
196
+
197
+ private void Start()
198
+ {
199
+ // Start内でPlayerに加えCameraのtransformを探しておく
200
+ this.playerTransform = this.transform.Find("Player");
201
+ this.cameraTransform = this.transform.Find("Camera");
202
+ }
203
+
204
+ private void Update()
205
+ {
206
+ var u = 0.0f;
207
+ var v = 0.0f;
208
+ if (Input.GetKey(KeyCode.W))
209
+ {
210
+ v += 1.0f;
211
+ }
212
+ if (Input.GetKey(KeyCode.S))
213
+ {
214
+ v -= 1.0f;
215
+ }
216
+ if (Input.GetKey(KeyCode.A))
217
+ {
218
+ u -= 1.0f;
219
+ }
220
+ if (Input.GetKey(KeyCode.D))
221
+ {
222
+ u += 1.0f;
223
+ }
224
+ // カメラローカル軸を基準に方向を決め、Y軸を潰して正規化しXZ平面上の方角にして、これをvecとする
225
+ var dir = (this.cameraTransform.right * u) + (this.cameraTransform.forward * v);
226
+ var vec = new Vector3(dir.x, 0.0f, dir.z).normalized;
227
+ this.transform.position += vec * Time.deltaTime * this.Speed;
228
+ if (vec.magnitude > 0.0f)
229
+ {
230
+ this.playerTransform.rotation = Quaternion.LookRotation(vec);
231
+ }
232
+ }
233
+ }
234
+ ```
235
+
236
+ これで実行したらこうなりました。実際にプレイしないと違いが分かりにくいかもしれません...
237
+
238
+ ![実行図3](cd3843a4394be59e948225cb36307f83.gif)
239
+
240
+ いかがでしょうか?ご参考になりましたらさいわいです。