Skip to content

Instantly share code, notes, and snippets.

@naojitaniguchi
Created March 25, 2016 06:26
Show Gist options
  • Save naojitaniguchi/689b928b401f2c924491 to your computer and use it in GitHub Desktop.
Save naojitaniguchi/689b928b401f2c924491 to your computer and use it in GitHub Desktop.
using UnityEngine;
using System.Collections;
// マウスのボタンをあらわす番号がわかりにくかったので名前を付けた
enum MouseButtonDown {
MBD_LEFT = 0,
MBD_RIGHT,
MBD_MIDDLE,
};
[ RequireComponent( typeof( Camera ) ) ]
public class CameraControllerMayaLike : MonoBehaviour {
[SerializeField]
private GameObject focusObj = null; // 注視点となるオブジェクト
private Vector3 oldPos; // マウスの位置を保存する変数
private Vector3 initFocusPosition; // focusObjの初期位置
private Quaternion initFocusRotation;
private Vector3 initCamPosition;
private Quaternion initCamRotation;
// 注視点オブジェクトが未設定の場合、新規に生成する
void setupFocusObject( string name ) {
GameObject obj = this.focusObj = new GameObject(name);
obj.transform.position = Vector3.zero;
return;
}
void Start() {
// 注視点オブジェクトの有無を確認
if( this.focusObj == null )
this.setupFocusObject( "CameraFocusObject" );
// 注視点オブジェクトをカメラの親にする
Transform trans = this.transform;
transform.parent = this.focusObj.transform;
// カメラの方向ベクトル(ローカルのZ方向)を注視点オブジェクトに向ける
trans.LookAt( this.focusObj.transform.position );
// store init param
storeInitCamera();
return;
}
void Update() {
// マウス関係のイベントを関数にまとめる
this.mouseEvent();
if( Input.GetKeyDown( KeyCode.Space ) ) {
this.restoreInitCamera();
}
return;
}
void storeInitCamera() {
initFocusPosition = this.focusObj.transform.position;
initFocusRotation = this.focusObj.transform.rotation;
initCamPosition = transform.position;
initCamRotation = transform.rotation;
}
void restoreInitCamera() {
this.focusObj.transform.position = initFocusPosition;
this.focusObj.transform.rotation = initFocusRotation;
transform.position = initCamPosition;
transform.rotation = initCamRotation;
}
// マウス関係のイベント
void mouseEvent() {
// マウスホイールの回転量を取得
float delta = Input.GetAxis("Mouse ScrollWheel");
// 回転量が0でなければホイールイベントを処理
if( delta != 0.0f )
this.mouseWheelEvent( delta );
// マウスボタンが押されたタイミングで、マウスの位置を保存する
if( Input.GetMouseButtonDown( ( int )MouseButtonDown.MBD_LEFT ) ||
Input.GetMouseButtonDown( ( int )MouseButtonDown.MBD_MIDDLE ) ||
Input.GetMouseButtonDown( ( int )MouseButtonDown.MBD_RIGHT ) )
this.oldPos = Input.mousePosition;
// マウスドラッグイベント
this.mouseDragEvent( Input.mousePosition );
return;
}
// マウスホイールイベント
void mouseWheelEvent( float delta ) {
// 注視点からカメラまでのベクトルを計算
Vector3 focusToPosition = this.transform.position - this.focusObj.transform.position;
// ホイールの回転量を元に上で求めたベクトルの長さを変える
Vector3 post = focusToPosition * (1.0f + delta * -1.0f );
// 長さを変えたベクトルの長さが一定以上あれば、カメラの位置を変更する
if( post.magnitude > 0.01f )
this.transform.position = this.focusObj.transform.position + post;
return;
}
// マウスドラッグイベント関数
void mouseDragEvent( Vector3 mousePos ) {
// マウスの現在の位置と過去の位置から差分を求める
Vector3 diff = mousePos - oldPos;
// 差分の長さが極小数より小さかったら、ドラッグしていないと判断する
if( diff.magnitude < Vector3.kEpsilon )
return;
if( Input.GetMouseButton( ( int )MouseButtonDown.MBD_LEFT ) ) {
// マウス左ボタンをドラッグした場合(カメラの回転)
this.cameraRotate( new Vector3( diff.y, diff.x, 0.0f ) );
} else if( Input.GetMouseButton( ( int )MouseButtonDown.MBD_MIDDLE ) ) {
// マウス中ボタンをドラッグした場合(注視点の移動)
this.cameraTranslate( -diff / 65.0f );
} else if( Input.GetMouseButton( ( int )MouseButtonDown.MBD_RIGHT ) ) {
// マウス右ボタンをドラッグした場合(なにもしない)
// 注視点からカメラまでのベクトルを計算
Vector3 focusToPosition = this.transform.position - this.focusObj.transform.position;
// ホイールの回転量を元に上で求めたベクトルの長さを変える
Vector3 post = focusToPosition * ( 1.0f + diff.magnitude / 100 * ( ( diff.x >= 0 ) ? -1.0f : 1.0f ) );
// 長さを変えたベクトルの長さが一定以上あれば、カメラの位置を変更する
if( post.magnitude > 0.01f )
this.transform.position = this.focusObj.transform.position + post;
}
// 現在のマウス位置を、次回のために保存する
this.oldPos = mousePos;
return;
}
// カメラを移動する関数
void cameraTranslate( Vector3 vec ) {
Transform focusTrans = this.focusObj.transform;
Transform trans = this.transform;
// カメラのローカル座標軸を元に注視点オブジェクトを移動する
focusTrans.Translate( ( trans.right * vec.x ) + ( trans.up * vec.y ) );
return;
}
// カメラを回転する関数
public void cameraRotate( Vector3 eulerAngle ) {
Vector3 focusPos = this.focusObj.transform.position;
Transform trans = this.transform;
// 回転前のカメラの情報を保存する
Vector3 preUpV, preAngle, prePos;
preUpV = trans.up;
preAngle = trans.localEulerAngles;
prePos = trans.position;
// カメラの回転
// 横方向の回転はグローバル座標系のY軸で回転する
trans.RotateAround( focusPos, Vector3.up, eulerAngle.y );
// 縦方向の回転はカメラのローカル座標系のX軸で回転する
trans.RotateAround( focusPos, trans.right, -eulerAngle.x );
// カメラを注視点に向ける
trans.LookAt( focusPos );
// ジンバルロック対策
// カメラが真上や真下を向くとジンバルロックがおきる
// ジンバルロックがおきるとカメラがぐるぐる回ってしまうので、一度に90度以上回るような計算結果になった場合は回転しないようにする(計算を元に戻す)
Vector3 up = trans.up;
if( Vector3.Angle( preUpV, up ) > 90.0f ) {
trans.localEulerAngles = preAngle;
trans.position = prePos;
}
return;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment