#はじめに
*注意*この記事はプログラミングの基礎知識がある前提で進みます。
レベルとしてはC++でちょっと書いたことあるよとか、Javaならいじったことあるぜ、って人ならば十分に理解できるでしょう。
あと高校数学の知識を必要とします。
それと、その1を見ないと多分意味わからないから見てね。
#視点操作とカメラ移動の同期編
やっとタイトルが出てきましたね。
前回はこんなコードで終了しましたね。
void update(){
float dx = Input.GetAxis("Horizontal");
float dz = Input.GetAxis("Vertical");
transform.Translate(dx, 0, dz, 0.0F);
}
さあ、何故ダメなのかを答え合わせしよう。
実際にやってみた人ならばわかるだろうが、カメラの視点とカメラの移動が同期されていないのです。
さてここからは最も重要な範囲であり、最も退屈な理論の時間です。
###同期の理論
カメラの移動はカメラの視点に同期する必要があると思いました。
じゃあどうして同期してやればいいでしょう。
私が思いついた方法を説明します。
実はその1で sight_x の範囲を 0 ~ 360にしましたね。
その理由が今回、その値を利用して方角を決めるからなのです。
sight_x は z軸方向を正方向つまり 0度と定めた角度なのです。
####上下入力があった場合
ではまず左スティックの上下入力があった場合を考えてみましょう。
カメラが向いている方向が sight_x度方向であるとして、ベクトルの移動量が1であるとすると
1^2 = x方向の移動量^2 + y方向の移動量^2
つまり
1 = sin(sight\_x)^2 + cos(sight\_x)^2
入力量は常に1または-1であるとは限らないので、入力量を両辺にかける
z^2 = (zsin(sight\_x))^2 + (zcos(sight\_x))^2
したがって各成分を分解してみると、z軸方法の移動量をdz1とすると
dz1 = zcos(sight\_x)
x軸方法の移動量をdx1とすると
dx1 = zsin(sight\_x)
となることがわかりました。
####左右入力があった場合
これはカメラが向いている方向から右に90度方向に進めばいいということになります。
ということは気づいた方もいると思いますが、sight_xに90を足せばいいということです。
1 = sin(sight\_x+90)^2 + cos(sight\_x+90)^2
先ほどの理論より、x軸方向の移動量を掛けると
x^2 = (xsin(sight\_x+90))^2 + (xcos(sight\_x+90))^2
したがって各成分を分解してみると、z軸方法の移動量をdz2とすると
dz2 = xcos(sight\_x+90)
x軸方法の移動量をdx1とすると
dx2 = xsin(sight\_x+90)
となることがわかりました。
#結果
上下左右の入力から求めた移動量をあわせるとz軸方向の移動量をdz、x軸方向の移動量をdxとすると、
dz = dz1 + dz2 = zcos(sight\_x) + xcos(sight\_x+90)
dx = dx1 + dx2 = zsin(sight\_x) + xsin(sight\_x+90)
となります。お疲れさまでした、理論は終わりです。
#実行
さあ、長い理論にお付き合いいただきましたので、さっそく使っていただきましょう。
先ほどの移動量の式をコードに変換すると
float dx = Mathf.Sin(sight_x * Mathf.Deg2Rad) * z + Mathf.Sin((sight_x + 90f) * Mathf.Deg2Rad) * x;
float dz = Mathf.Cos(sight_x * Mathf.Deg2Rad) * z + Mathf.Cos((sight_x + 90f) * Mathf.Deg2Rad) * x;
このコードを追加して、コードを完成させると
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class クラス名 : MonoBehaviour
{
void Start()
{
}
float sight_x = 0;
float sight_y = 0;
void controller()
{
float x = Input.GetAxis("Horizontal");
float z = Input.GetAxis("Vertical");
float angleH = Input.GetAxis("Horizontal2") * 5.0f;
float angleV = Input.GetAxis("Vertical2") * 5.0f;
if (sight_x >= 360)
{
sight_x = sight_x - 360;
}
else if (sight_x < 0){
sight_x = 360 - sight_x;
}
sight_x = sight_x + angleH;
if (sight_y > 80)
{
if (angleV < 0)
{
sight_y = sight_y + angleV;
}
}
else if (sight_y < -90)
{
if (angleV > 0)
{
sight_y = sight_y + angleV;
}
}
else
{
sight_y = sight_y + angleV;
}
float dx = Mathf.Sin(sight_x * Mathf.Deg2Rad) * z + Mathf.Sin((sight_x + 90f) * Mathf.Deg2Rad) * x;
float dz = Mathf.Cos(sight_x * Mathf.Deg2Rad) * z + Mathf.Cos((sight_x + 90f) * Mathf.Deg2Rad) * x;
transform.Translate(dx, 0, dz, 0.0F);
transform.localRotation = Quaternion.Euler(sight_y, sight_x, 0);
//Debug.Log("sight_x:sight_y \n" + sight_x + " : " + sight_y);
Debug.Log("dx:dz \n" + dx + " : " + dz);
}
void Update()
{
controller();
}
}
よく頑張りました、これで視点操作とカメラ移動の同期を終了します。
何かわからないことがあればコメントで遠慮せずに尋ねてください。
私はすべてのプログラマーの味方でありたいと思っていますので。 それではさようならっ!!
#あとがき(自己紹介です、読まなくてもいいです)
私はVonletと申します。
プログラミング、電子工作、作曲などを生きがいにしています。
一番わかりやすいものでしたら、
マクドナルド(シオンタウン店)
https://www.nicovideo.jp/watch/sm34895662
FutureHouse神社(bootleg).dondiablo
https://www.nicovideo.jp/watch/sm34666016
などを作って恥を晒しています。よろしければ見に行ってやってください。
最後に自分のSNSを載せておきます
YouTube : https://www.youtube.com/channel/UCvL2cxUWsnBDT95jSq1G9QQ
Twitter : https://twitter.com/Vonlet
ニコニコ動画 : https://www.nicovideo.jp/user/87637963
Sound Cloud : https://soundcloud.com/8yve6bc8icio