Skip to content

Instantly share code, notes, and snippets.

@baba-s
Created August 24, 2017 02:37
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save baba-s/04134481224440d63022a20409b1b9f7 to your computer and use it in GitHub Desktop.
Save baba-s/04134481224440d63022a20409b1b9f7 to your computer and use it in GitHub Desktop.
using HedgehogTeam.EasyTouch;
using System;
using System.Collections;
using UnityEngine;
/// <summary>
/// カメラのタッチ制御を管理するクラス
/// </summary>
public sealed class TouchManager : MonoBehaviour
{
//==============================================================================
// 列挙型
//==============================================================================
[Flags]
private enum State
{
NONE = 1 << 0, // 待機
MOVE = 1 << 1, // 移動
ROTATE = 1 << 2, // 回転
ZOOM_IN = 1 << 3, // 拡大
ZOOM_OUT = 1 << 4, // 拡大
}
//==============================================================================
// 変数(SerializeField)
//==============================================================================
[SerializeField] private Transform m_cameraAxis = null ; // カメラの軸
[SerializeField] private Camera m_camera = null ; // カメラ本体
[SerializeField] private float m_moveSpeed = 0.5f ; // 移動速度
[SerializeField] private float m_rotateSpeed = 10 ; // 回転速度
[SerializeField] private float m_zoomSpeed = 2.5f ; // 拡大速度
[SerializeField] private float m_minPosX = -1 ; // X 座標の最小値
[SerializeField] private float m_maxPosX = 1 ; // X 座標の最大値
[SerializeField] private float m_minPosY = -1 ; // Y 座標の最小値
[SerializeField] private float m_maxPosY = 1 ; // Y 座標の最大値
[SerializeField] private float m_minFieldOfView = 6 ; // 視野角の最小値
[SerializeField] private float m_maxFieldOfView = 60 ; // 視野角の最大値
[SerializeField] private float m_minRotateX = -85 ; // X 軸方向の回転角の最小値
[SerializeField] private float m_maxRotateX = 15 ; // X 軸方向の回転角の最大値
#if UNITY_EDITOR
[SerializeField] private float m_mouseSpeed = 10 ; // マウスの速さ
[SerializeField] private float m_wheelSpeed = -500 ; // マウスホイールの速さ
#endif
//==============================================================================
// 変数
//==============================================================================
private State m_state ; // ステート
private bool m_isPortrait; // 縦持ちの場合 true
private Vector3 m_defaultCameraAxisPos ;
private Vector3 m_defaultCameraAxisRotate ;
private Vector3 m_defaultCameraPos ;
private Vector3 m_defaultCameraRotate ;
private float m_defaultFieldOfView ;
//==============================================================================
// プロパティ
//==============================================================================
public bool IsReverseHorizontal { private get; set; } // カメラの左右操作をリバースする場合 true を設定します
public bool IsReverseVertical { private get; set; } // カメラの上下操作をリバースする場合 true を設定します
private float deltaTime { get { return Time.deltaTime * ( 1 / Time.timeScale ); } }
//==============================================================================
// 関数
//==============================================================================
/// <summary>
/// 初期化する時に呼び出されます
/// </summary>
private void Awake()
{
m_defaultCameraAxisPos = m_cameraAxis.transform.localPosition ;
m_defaultCameraAxisRotate = m_cameraAxis.transform.localEulerAngles ;
m_defaultCameraPos = m_camera.transform.localPosition ;
m_defaultCameraRotate = m_camera.transform.localEulerAngles ;
m_defaultFieldOfView = m_camera.fieldOfView ;
}
/// <summary>
/// 有効になる時に呼び出されます
/// </summary>
private void OnEnable()
{
EasyTouch.On_TouchUp2Fingers += On_TouchUp2Fingers ;
EasyTouch.On_SwipeStart2Fingers += On_SwipeStart2Fingers ;
EasyTouch.On_Swipe2Fingers += On_Swipe2Fingers ;
EasyTouch.On_SwipeEnd2Fingers += On_SwipeEnd2Fingers ;
EasyTouch.On_SwipeStart += On_SwipeStart ;
EasyTouch.On_Swipe += On_Swipe ;
EasyTouch.On_SwipeEnd += On_SwipeEnd ;
EasyTouch.On_PinchIn += On_PinchIn ;
EasyTouch.On_PinchOut += On_PinchOut ;
}
/// <summary>
/// 無効になる時に呼び出されます
/// </summary>
private void OnDisable()
{
EasyTouch.On_TouchUp2Fingers -= On_TouchUp2Fingers ;
EasyTouch.On_SwipeStart2Fingers -= On_SwipeStart2Fingers ;
EasyTouch.On_Swipe2Fingers -= On_Swipe2Fingers ;
EasyTouch.On_SwipeEnd2Fingers -= On_SwipeEnd2Fingers ;
EasyTouch.On_SwipeStart -= On_SwipeStart ;
EasyTouch.On_Swipe -= On_Swipe ;
EasyTouch.On_SwipeEnd -= On_SwipeEnd ;
EasyTouch.On_PinchIn -= On_PinchIn ;
EasyTouch.On_PinchOut -= On_PinchOut ;
}
/// <summary>
/// 2 本指の両方もしくは片方が離れた時に呼び出されます
/// </summary>
private void On_TouchUp2Fingers( Gesture gesture )
{
RemoveState( State.MOVE );
}
/// <summary>
/// 2 本指のスワイプを開始した時に呼び出されます
/// </summary>
private void On_SwipeStart2Fingers( Gesture gesture )
{
AddState( State.MOVE );
}
/// <summary>
/// 2 本指のスワイプ中に呼び出されます
/// </summary>
private void On_Swipe2Fingers( Gesture gesture )
{
Move( gesture.deltaPosition );
}
/// <summary>
/// 移動します
/// </summary>
private void Move( Vector2 deltaPosition )
{
var posZ = m_camera.fieldOfView;
var zoomRate = Mathf.InverseLerp( m_maxFieldOfView, m_minFieldOfView, posZ );
var speedDelta = Mathf.Lerp( 1, 0.05f, zoomRate );
var delta = deltaTime * deltaPosition * m_moveSpeed * speedDelta;
var moveX = m_isPortrait ? -delta.y : -delta.x;
var moveY = m_isPortrait ? -delta.x : delta.y;
var posX = m_camera.transform.localPosition.x + moveX;
var posY = m_camera.transform.localPosition.y + moveY;
posX = Mathf.Clamp( posX, m_minPosX, m_maxPosX );
posY = Mathf.Clamp( posY, m_minPosY, m_maxPosY );
var pos = m_camera.transform.localPosition;
pos.x = posX;
pos.y = posY;
m_camera.transform.localPosition = pos;
}
/// <summary>
/// 2 本指のスワイプが終了した時に呼び出されます
/// </summary>
private void On_SwipeEnd2Fingers( Gesture gesture )
{
RemoveState( State.MOVE );
}
/// <summary>
/// スワイプを開始した時に呼び出されます
/// </summary>
private void On_SwipeStart( Gesture gesture )
{
if ( HasFlag( m_state, State.MOVE ) ) return;
if ( HasFlag( m_state, State.ZOOM_IN ) ) return;
if ( HasFlag( m_state, State.ZOOM_OUT ) ) return;
AddState( State.ROTATE );
}
/// <summary>
/// スワイプ中に呼び出されます
/// </summary>
private void On_Swipe( Gesture gesture )
{
if ( HasFlag( m_state, State.MOVE ) ) return;
if ( HasFlag( m_state, State.ZOOM_IN ) ) return;
if ( HasFlag( m_state, State.ZOOM_OUT ) ) return;
if ( !HasFlag( m_state, State.ROTATE ) )
{
AddState( State.ROTATE );
}
// 縦持ち:portrait
// 横持ち:landscape
var delta = deltaTime * gesture.deltaPosition * m_rotateSpeed;
var rotate = m_cameraAxis.transform.localEulerAngles;
var rateX = m_isPortrait ? -delta.x : delta.y;
var rateY = m_isPortrait ? -delta.y : -delta.x;
rotate.x += IsReverseVertical ? -rateX : rateX; // 縦方向
rotate.y += IsReverseHorizontal ? rateY : -rateY; // 横方向
rotate.z = 0;
// カメラの X 軸方向の回転角が
// -1 ではなく 359 で管理されることがあるため調整しています
if ( 180 <= rotate.x ) rotate.x -= 360;
rotate.x = Mathf.Clamp( rotate.x, m_minRotateX, m_maxRotateX );
m_cameraAxis.transform.localRotation = Quaternion.Euler( rotate );
}
/// <summary>
/// スワイプを終了した時に呼び出されます
/// </summary>
private void On_SwipeEnd( Gesture gesture )
{
RemoveState( State.ROTATE );
}
/// <summary>
/// ピンチイン中に呼び出されます
/// </summary>
private void On_PinchIn( Gesture gesture )
{
AddState( State.ZOOM_IN );
CallWaitForEndOfFrame( () => RemoveState( State.ZOOM_IN ) );
Zoom( gesture.deltaPinch );
}
/// <summary>
/// ピンチアウト中に呼び出されます
/// </summary>
private void On_PinchOut( Gesture gesture )
{
AddState( State.ZOOM_OUT );
CallWaitForEndOfFrame( () => RemoveState( State.ZOOM_OUT ) );
Zoom( -gesture.deltaPinch );
}
/// <summary>
/// ズームします
/// </summary>
private void Zoom( float deltaPinch )
{
var delta = deltaTime * deltaPinch * m_zoomSpeed;
var fieldOfView = m_camera.fieldOfView + delta;
m_camera.fieldOfView = Mathf.Clamp( fieldOfView, m_minFieldOfView, m_maxFieldOfView );
}
/// <summary>
/// ステートを追加します
/// </summary>
private void AddState( State state )
{
m_state |= state;
}
/// <summary>
/// ステートを削除します
/// </summary>
private void RemoveState( State state )
{
m_state &= ~state;
}
#if UNITY_EDITOR
/// <summary>
/// 更新する時に呼び出されます
/// </summary>
private void Update()
{
Zoom( Input.GetAxis( "Mouse ScrollWheel" ) * m_wheelSpeed );
if ( !Input.GetMouseButton( 2 ) ) return;
var deltaPosition = new Vector2
(
Input.GetAxis( "Mouse X" ),
Input.GetAxis( "Mouse Y" )
);
Move( deltaPosition * m_mouseSpeed );
}
#endif
/// <summary>
/// 縦持ちの場合 true を設定します
/// </summary>
public void SetIsPortrait( bool isPortrait )
{
m_isPortrait = isPortrait;
var angle = m_camera.transform.localEulerAngles;
angle.z = m_isPortrait ? -90 : 0;
m_camera.transform.localEulerAngles = angle;
}
/// <summary>
/// カメラのトランスフォームをリセットします
/// </summary>
public void ResetTranmsform()
{
m_cameraAxis.transform.localPosition = m_defaultCameraAxisPos ;
m_cameraAxis.transform.localEulerAngles = m_defaultCameraAxisRotate ;
var cameraTrans = m_camera.transform;
var pos = cameraTrans.localPosition;
pos.x = m_defaultCameraPos.x;
pos.y = m_defaultCameraPos.y;
cameraTrans.localPosition = pos;
// カメラの Z 軸方向の回転角は
// 縦持ち、横持ちの制御で使用する想定なのでリセットしません
var angle = cameraTrans.localEulerAngles;
angle.x = m_defaultCameraRotate.x;
angle.y = m_defaultCameraRotate.y;
cameraTrans.localEulerAngles = angle;
m_camera.fieldOfView = m_defaultFieldOfView;
}
/// <summary>
/// 指定されたコールバック関数を 1 フレーム後に呼び出します
/// </summary>
private void CallWaitForEndOfFrame( Action callback )
{
StartCoroutine( DoCallWaitForEndOfFrame( callback ) );
}
/// <summary>
/// 指定されたコールバック関数を 1 フレーム後に呼び出すコルーチン
/// </summary>
private IEnumerator DoCallWaitForEndOfFrame( Action callback )
{
yield return 0;
callback();
}
/// <summary>
/// 指定された列挙型が指定されたフラグを保持している場合 true を返します
/// </summary>
private static bool HasFlag( Enum self, Enum flag )
{
if ( self.GetType() != flag.GetType() ) return false;
var selfValue = Convert.ToUInt64( self );
var flagValue = Convert.ToUInt64( flag );
return ( selfValue & flagValue ) == flagValue;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment