主なコンテンツ

〜主なコンテンツ〜

1. Unityで製作したゲームと製作Tips
  1. 三月精チャレンジ(東方Project二次創作)
    1. 作り方
  2. 英語学習2D(オリジナルスマホアプリ)
2. UE4
3. ゲームアプリ見学
4. Bitbucket & SourceTreeでの一連の流れ
  1. 前半
  2. 後半
5. Tips
  1. UnityのTips
  5. SQL文のTips
  6. Final IK
  7. GearVR+Unity

2016年3月7日月曜日

カメラワーク③【三月精チャレンジ】

■キャラクターに追従させる

座標間の距離はVector3.Distanceで取得することができる。このとき距離が開きすぎていたらカメラをキャラクターに近づける。transform.Translateを使えば、指定した方向に動かすことができる。このとき安易にtransform.forwardとすると、カメラがキャラクターの方向を向いていない場合、全く関係ない方向に進み出してしまう。

カメラから見たキャラクターへの方向ベクトルは、単純に座標の引き算で求めることができる(参考)。ただし、前述の通り仰角俯角には影響を与えたくないので、y成分は除外する必要がある。これにより、この引き算によって求めた方向ベクトルとtransform.Translateを使えばカメラを対象に近づけることができる。



ただし、カメラを対象の方向に向けることはできていない。そこで次に、カメラを対象に向かせる必要がある。

■キャラクターの方を向く

特定の座標を向かせるのにはTransform.LookAtという便利な関数がある。ただし、Transform.LookAtを使うとtransform.rotationの全成分を上書きすることになるため、マウスの上下操作でカメラを回転させられるようにした意味がなくなる。また、例えばLookAt(target.tarnsform.possition)とした場合、この座標とはキャラクターの足元の座標のことである

現在のX軸周りの回転を別な変数に保存しておき、キャラクターの中心に子オブジェクトを作って、LookAtでその座標を向かせ、transform.eulerAnglesとQuaterion.Eulerを用いてX軸周りの回転だけ元に戻すという手もある。

ただ、ここでは素直にtransform.Rotateを用いてY軸周りに必要なだけ回転させることを目指す。この角度を求めるにはカメラのローカル空間で計算した方が都合が良い。

カメラのローカル空間とは、下図のカメラに表示されている座標系のことである。対して右上に示されている座標系がワールド空間である。青い軸はZ軸を表しており、特にローカル空間ではオブジェクトが向いている向き(forward)を意味している。またローカル空間における原点=そのオブジェクトの座標である。


Transform.InverseTransformPoint(Vector3)を使えば、キャラクターのワールド座標(transform.possition)をカメラのローカル座標に変換することができる。

これにより、カメラのローカル空間でのX軸とキャラクター座標の成す角度を三角関数の逆関数から求めることができる。Z軸は90°なので求めた角度から90°を引けば、カメラのforwardを原点周りに何度回転させればキャラの方を向くかが分かる。


■プログラム全体(Main Cameraにアタッチ)

  • 90°から求めた角度を引いて、初めから時計回りを正にしたほうが良い。
using UnityEngine;
using System.Collections;
public class CameraFollowing : MonoBehaviour {
public Transform target;
public float distance = 1f;
private Vector3 tarPosXZ;//<! ワールド空間
private Vector3 camPosXZ;//<! ワールド空間
private Vector3 direction;//<! ワールド空間
void Start(){
//初期位置の設定
float x = target.transform.position.x;
float y = transform.position.y;//<! yはカメラの高さのままにしておく
float z = target.transform.position.y - distance;//<! 距離分引く
transform.position.Set (x, y, z);
//targetのxz平面座標の用意
tarPosXZ = target.transform.position;
tarPosXZ.y = 0;
//カメラのxz平面座標の用意
camPosXZ = transform.position;
camPosXZ.y = 0;
//カメラからターゲットに向かう方向ベクトル
direction = tarPosXZ - camPosXZ;
}
void Update() {
//ベクトルの更新
UpdateVector ();
//ターゲットの方を向く
LookTargetXZ ();
//ターゲットに追従
Follow ();
}
void UpdateVector(){
//tarPosXZの更新
tarPosXZ.x = target.transform.position.x;
tarPosXZ.z = target.transform.position.z;
//camPosXZの更新
camPosXZ.x = transform.position.x;
camPosXZ.z = transform.position.z;
//方向ベクトルの更新と正規化
direction = tarPosXZ - camPosXZ;
direction.Normalize();
}
void LookTargetXZ(){
//ローカルXZ空間におけるtargetの座標を取得
Vector3 localTarPosXZ = transform.InverseTransformPoint(tarPosXZ);
//ローカル座標の原点(=カメラ)とtargetの座標の角度を取得
float angle = Mathf.Atan2(localTarPosXZ.z, localTarPosXZ.x);
//Z軸(0,0,1)との成す角度が知りたいので90°減算
angle -= Mathf.PI / 2;
//Quaternionは時計回りが正なので、得られた向きを逆転させる
angle *= -1;
//Rotateメドッドを使用するのでオイラーに変換
angle *= Mathf.Rad2Deg;
//ワールド座標でカメラを回転
transform.Rotate(Vector3.up, angle, Space.World);
//transform.rotation *= Quaternion.AngleAxis(angle, upVector);//<! transform.rotationの空間に置き換えたとき、ちょうど真上を向くベクトルが必要
//transform.rotation = Quaternion.LookRotation (direction);//<! 部分的なパラメータではなく全て帰るので、カメラの傾きも上書きしてしまう
}
void Follow(){
//現在の距離と指定距離との差を調べる
float difference = Vector3.Distance (camPosXZ, tarPosXZ) - distance;
//ターゲット方向に距離を詰める
transform.Translate (direction * difference, Space.World);//<! forwardを使うと、カメラがキャラを向いていない場合移動するほどキャラから離れる
}
}

0 件のコメント:

コメントを投稿