【Unity】【C#】SmoothFollow に回転アングルと高さと距離の遠近機能を付けてみる 
2015/02/06 Fri [edit]
前回、Standard Assets の「SmoothFollow.js」の C# 版を作ったが、せっかくなのでカメラアングルを左右回転する機能と、高さと距離のプロパティ(フィールド)を変更して自由に遠近できる機能を付けてみた。
●SmoothFollow.js の C#版 に左右回転アングルと高さと距離の遠近機能を追加したもの
using UnityEngine;
using System.Collections;
[AddComponentMenu("Camera-Control/SmoothFollow2")]
public class SmoothFollow2 : MonoBehaviour {
/** 追従するオブジェクト */
public Transform target;
/** Z方向の距離 */
public float distance = 2.0f;
/** Y方向の高さ */
public float height = 0f;
/** カメラアングル初期値 */
public float preAngle = 0f;
/** 上下高さのスムーズ移動速度 */
public float heightDamping = 2.0f;
/** 左右回転のスムーズ移動速度 */
public float rotationDamping = 3.0f;
/** 距離のスムーズ移動速度 */
public float distanceDamping = 1.0f;
/** 回転のキー操作の ON/OFF */
public bool angleKeyOperation = true;
/** 左右回転速度 */
public float angleKeySpeed = 45f;
/** 左旋回キー */
public KeyCode angleKeyLeft = KeyCode.Z;
/** 右旋回キー */
public KeyCode angleKeyRight = KeyCode.X;
/** カメラアングル相対値 */
private float angle;
/** 回転のドラッグ操作の ON/OFF */
public bool angleDragOperation = true;
/** ドラッグ操作での回転速度 */
public float angleDragSpeed = 10f;
/** マウス移動始点 */
private Vector3 startPos;
/** 高さのキー操作の ON/OFF */
public bool heightKeyOperation = true;
/** キー操作での移動速度 */
public float heightKeySpeed = 1.5f;
/** 高さ上へキー */
public KeyCode heightKeyUp = KeyCode.C;
/** 高さ下へキー */
public KeyCode heightKeyDown = KeyCode.V;
/** 高さのドラッグ操作での ON/OFF */
public bool heightDragOperation = true;
/** ドラッグ操作での高さ移動速度 */
public float heightDragSpeed = 0.5f;
/** 距離のキー操作の ON/OFF */
public bool distanceKeyOperation = true;
/** Z方向の最小距離 */
public float distanceMin = 1.0f;
/** 距離の移動速度 */
public float distanceKeySpeed = 0.5f;
/** 近くへキー */
public KeyCode distanceKeyNear = KeyCode.B;
/** 遠くへキー */
public KeyCode distanceKeyFar = KeyCode.N;
/** 距離のホイール操作の ON/OFF */
public bool distanceWheelOperation = true;
/** ホイール1目盛りの速度 */
public float distanceWheelSpeed = 7f;
/** 変化先距離 */
private float wantedDistance;
// Use this for initialization
void Start () {
angle = preAngle;
wantedDistance = distance;
}
// Update is called once per frame
void Update () {
//回転のキー操作
if (angleKeyOperation) {
if (Input.GetKey(angleKeyLeft)) {
angle += angleKeySpeed * Time.deltaTime;
if (angle >= 360f) {
angle -= 360f;
}
}
if (Input.GetKey(angleKeyRight)) {
angle -= angleKeySpeed * Time.deltaTime;
if (angle < 0f) {
angle += 360f;
}
}
}
//高さのキー操作
if (heightKeyOperation) {
if (Input.GetKey(heightKeyUp)) {
height += heightKeySpeed * Time.deltaTime;
}
if (Input.GetKey(heightKeyDown)) {
height -= heightKeySpeed * Time.deltaTime;
}
}
//ドラッグ操作
if (angleDragOperation || heightDragOperation) {
Vector3 movePos = Vector3.zero;
if (Input.GetMouseButtonDown(0)) {
startPos = Input.mousePosition;
}
else if (Input.GetMouseButton(0)) {
movePos = Input.mousePosition - startPos;
startPos = Input.mousePosition;
}
else if (Input.GetMouseButtonUp(0)) {
startPos = Vector3.zero;
}
if (movePos != Vector3.zero) {
//回転のドラッグ操作
if (angleDragOperation) {
angle += movePos.x * angleDragSpeed * Time.deltaTime;
if (angle < 0f) {
angle += 360f;
} else if (angle >= 360f) {
angle -= 360f;
}
}
//高さのドラッグ操作
if (heightDragOperation) {
height -= movePos.y * heightDragSpeed * Time.deltaTime;
}
}
}
//距離のキー操作
if (distanceKeyOperation) {
if (Input.GetKey(distanceKeyNear)) {
wantedDistance = distance - distanceKeySpeed;
if (wantedDistance <= distanceMin) {
wantedDistance = distanceMin;
}
}
if (Input.GetKey(distanceKeyFar)) {
wantedDistance = distance + distanceKeySpeed;
}
}
//距離のホイール遠近
if (distanceWheelOperation) {
float mw = Input.GetAxis("Mouse ScrollWheel");
if (mw != 0) {
wantedDistance = distance - mw * distanceWheelSpeed; //0.1 x N倍
if (wantedDistance <= distanceMin) {
wantedDistance = distanceMin;
}
}
}
}
void LateUpdate () {
if (target == null) {
return;
}
//追従先位置
float wantedRotationAngle = target.eulerAngles.y + angle;
float wantedHeight = target.position.y + height;
//現在位置
float currentRotationAngle = transform.eulerAngles.y;
float currentHeight = transform.position.y;
//追従先へのスムーズ移動距離(方向)
currentRotationAngle = Mathf.LerpAngle(currentRotationAngle, wantedRotationAngle,
rotationDamping * Time.deltaTime);
currentHeight = Mathf.Lerp(currentHeight, wantedHeight, heightDamping * Time.deltaTime);
distance = Mathf.Lerp(distance, wantedDistance, distanceDamping * Time.deltaTime);
//カメラの移動
var currentRotation = Quaternion.Euler(0, currentRotationAngle, 0);
Vector3 pos = target.position - currentRotation * Vector3.forward * distance;
pos.y = currentHeight;
transform.position = pos;
transform.LookAt(target);
}
}
プロパティはやたらと増えてしまったが、基本的な仕様はそのまま引き継いでいるつもり。インスペクターで細かく調整できるようにしたが、~Operation のチェックをすべて外せば、実質、SmoothFollow と同じになる。製作中のチェック用に使うのも良いかもしれない。
LateUpdate() の部分はあまり変えてないが、カメラのアングル位置を相対変化させる計算と、距離(distance)をスムーズに移動するように Mathf.Lerp() を追加している。Update() は主に操作用のコードとなっているが、単純な計算しかしてないので、改造するのは簡単だろう。Start() は手抜きして初期化が必須なものしか書いてないが、本来はプロパティ値が負の値だと動作が変になるので、値のチェックを追加しても良いかもしれない。distance だけは distanceMin で制限はしてある(distanceMin 自体は0より上)。
●プロパティ図解


使い方としては、元の「SmoothFollow.js」と同じ。カメラにスクリプトを追加して、Target にキャラを設定するだけだ。ただ使ってみると、ユニティちゃんみたいなキャラは足元が基準座標となっているため、距離(distance)を近づけると、足元に寄ってしまう。キャラの中心あたりに視点を設定したければ、空の GameObject をキャラの子要素にして、そのオブジェクトをカメラスクリプトの Target に設定すれば良い。
●空の GameObject(TargetPos)を追加して、子要素にする

●カメラの視点にしたい位置を Position に設定

●スクリプトの Target に視点用オブジェクトを設定

具体的な動作を見てみたい場合は、下記のリンクからサンプルをどうぞ。
(関連記事)
【Unity】【C#】SmoothFollow を C# で書いてみる
【Unity】【C#】ユニティちゃんをサクっと簡単に動かす!
【Unity】【C#】ユニティちゃんを飛行させる!
【Unity】クエリちゃんを動かす!
【Unity】【C#】クエリちゃんを飛行させる!
【Unity】SDクエリちゃんを動かす!
【Unity】【C#】SDクエリちゃんを飛行させる!
【Unity】プロ生ちゃんを動かす!
【Unity】プロ生ちゃんを飛行させる!

- 関連記事
-
-
【Unity】【C#】SmoothFollow に回転アングルと高さと距離の遠近機能を付けてみる
-
【Unity】Androidで数値・半角英数・パスワード入力ダイアログを使う
-
【Unity】ARCore を使って現実世界にプロ生ちゃんを召喚してみる
-
【Unity】Unity2018.3.2 にアップグレードすると見た目がおかしくなることがある
-
【Unity】【C#】クエリちゃんを飛行させる!
-
トラックバック
トラックバックURL
→http://fantom1x.blog130.fc2.com/tb.php/163-3b432ee0
この記事にトラックバックする(FC2ブログユーザー)
| h o m e |