Created
February 29, 2020 07:43
-
-
Save jackyli-work/0f067dd82c91473ac656c3e6aa65af51 to your computer and use it in GitHub Desktop.
GyroParallax
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
public class GyroParallaxHelper : MonoBehaviour | |
{ | |
[Header("Layer of Group Object")] | |
public RectTransform LayerObject; | |
[Header("Layer of Inner Image Object")] | |
public RectTransform LayerImage; | |
[Header("Layer of Background Object")] | |
public RectTransform LayerBackground; | |
[HideInInspector] | |
public float UpdateSpeed = 10f; | |
[HideInInspector] | |
public float RecoverySpeedRatio = 0.2f; | |
[HideInInspector] | |
public float RotationMax = 20f; | |
[HideInInspector] | |
public bool EnableRotation = true; | |
[HideInInspector] | |
public float MoveRatioOfObject = 0f; | |
[HideInInspector] | |
public float MoveRatioOfImage = 1.2f; | |
[HideInInspector] | |
public float MoveRatioOfBackground = 0.5f; | |
[HideInInspector] | |
public bool UseTouch = true; | |
[HideInInspector] | |
public float ForceOfTouch = 50f; | |
[HideInInspector] | |
public bool SkipWhenTouch = true; | |
[HideInInspector] | |
public bool UseGyro = true; | |
[HideInInspector] | |
public float ForceOfGyro = 3f; | |
[HideInInspector] | |
public float GyroUpdateSpeed = 60f; | |
[HideInInspector] | |
public bool UseAcc; | |
[HideInInspector] | |
public float ForceOfAcc = 100f; | |
[HideInInspector] | |
public float FilterOfAcc = 50f; | |
[HideInInspector] | |
public bool UseArrowKey = true; | |
[HideInInspector] | |
public float ForceOfArrowKey = 5f; | |
private Vector3 initScreenPosOfObject; | |
private Vector3 initAnchoredPosOfObject; | |
private Vector3 initAnchoredPosOfImage; | |
private Vector3 initAnchoredPosOfBackground; | |
private Vector3 tarEulerAngles; | |
private Vector3 prevAccCache; | |
void Start() | |
{ | |
if (LayerObject == null) | |
{ | |
LayerObject = GetComponent<RectTransform>(); | |
} | |
tarEulerAngles = LayerObject.localEulerAngles; | |
initAnchoredPosOfObject = LayerObject.anchoredPosition; | |
if (LayerImage != null) | |
{ | |
initAnchoredPosOfImage = LayerImage.anchoredPosition; | |
} | |
if (LayerBackground != null) | |
{ | |
initAnchoredPosOfBackground = LayerBackground.anchoredPosition; | |
} | |
if (UseAcc) | |
{ | |
prevAccCache = Input.acceleration; | |
} | |
if (!SystemInfo.supportsGyroscope) | |
{ | |
UseGyro = false; | |
} | |
initScreenPosOfObject = LayerObject.anchoredPosition; | |
initScreenPosOfObject = new Vector3(Screen.width * LayerObject.anchorMin.x + initScreenPosOfObject.x, Screen.height * LayerObject.anchorMin.y + initScreenPosOfObject.y); | |
} | |
void OnEnable() | |
{ | |
if (UseGyro) | |
{ | |
Input.gyro.enabled = UseGyro; | |
Input.gyro.updateInterval = 1 / GyroUpdateSpeed; | |
} | |
} | |
void Update() | |
{ | |
var moveDir = new Vector3(tarEulerAngles.y, -tarEulerAngles.x); | |
if (LayerObject != null) | |
{ | |
if (EnableRotation) | |
{ | |
LayerObject.localRotation = Quaternion.Lerp(LayerObject.localRotation, Quaternion.Euler(tarEulerAngles), Time.deltaTime * UpdateSpeed); | |
} | |
LayerObject.anchoredPosition = Vector2.Lerp(LayerObject.anchoredPosition, initAnchoredPosOfObject + moveDir * MoveRatioOfObject, Time.deltaTime * UpdateSpeed); | |
} | |
if (LayerImage != null) | |
{ | |
LayerImage.anchoredPosition = Vector2.Lerp(LayerImage.anchoredPosition, initAnchoredPosOfImage + moveDir * MoveRatioOfImage, Time.deltaTime * UpdateSpeed); | |
} | |
if (LayerBackground != null) | |
{ | |
LayerBackground.anchoredPosition = Vector2.Lerp(LayerBackground.anchoredPosition, initAnchoredPosOfBackground + moveDir * MoveRatioOfBackground, Time.deltaTime * UpdateSpeed); | |
} | |
tarEulerAngles *= (1f - RecoverySpeedRatio); | |
bool touched = false; | |
if (UseTouch) | |
{ | |
if (Input.GetMouseButton(0)) | |
{ | |
touched = true; | |
Vector3 vecDis = (Input.mousePosition - initScreenPosOfObject) / Screen.width; | |
tarEulerAngles.x = vecDis.y * ForceOfTouch; | |
tarEulerAngles.y = -vecDis.x * ForceOfTouch; | |
} | |
} | |
if (!UseTouch || !SkipWhenTouch && !touched) | |
{ | |
if (UseAcc && UseGyro) | |
{ | |
Debug.LogError("Use Acceralator 'or' Gyro only"); | |
} | |
else if (UseGyro) | |
{ | |
var gyro = Input.gyro.rotationRateUnbiased; | |
tarEulerAngles.x += gyro.x * ForceOfGyro; | |
tarEulerAngles.y += gyro.y * ForceOfGyro; | |
} | |
else if (UseAcc) | |
{ | |
var acc = Input.acceleration; | |
float accY = (int)((acc.y - prevAccCache.y) * FilterOfAcc) / FilterOfAcc; | |
float accX = (int)((acc.x - prevAccCache.x) * FilterOfAcc) / FilterOfAcc; | |
tarEulerAngles.x += accY * ForceOfAcc; | |
tarEulerAngles.y += accX * ForceOfAcc; | |
prevAccCache = acc; | |
} | |
} | |
if (UseArrowKey) | |
{ | |
tarEulerAngles.y += Input.GetKey(KeyCode.LeftArrow) ? ForceOfArrowKey : 0; | |
tarEulerAngles.y -= Input.GetKey(KeyCode.RightArrow) ? ForceOfArrowKey : 0; | |
tarEulerAngles.x += Input.GetKey(KeyCode.UpArrow) ? ForceOfArrowKey : 0; | |
tarEulerAngles.x -= Input.GetKey(KeyCode.DownArrow) ? ForceOfArrowKey : 0; | |
} | |
SetValueRange(ref tarEulerAngles.x, RotationMax, -RotationMax); | |
SetValueRange(ref tarEulerAngles.y, RotationMax, -RotationMax); | |
} | |
void SetValueRange(ref float value, float max, float min) | |
{ | |
value = Mathf.Max(Mathf.Min(value, max), min); | |
} | |
void OnDisable() | |
{ | |
Input.gyro.enabled = false; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#if UNITY_EDITOR | |
using UnityEngine; | |
using UnityEditor; | |
[CanEditMultipleObjects] | |
[CustomEditor(typeof(GyroParallaxHelper))] | |
public class GyroParallaxHelperInspector : Editor | |
{ | |
private GyroParallaxHelper component; | |
private float _updateSpeedMin = 10; | |
private float _updateSpeedMax = 60; | |
private float _recoverySpeedRatioMin = 0f; | |
private float _recoverySpeedRatioMax = 1f; | |
private float _rotationMaxMax = 90f; | |
private float _forceOfTouchMax = 200f; | |
private float _forceOfGyroMax = 50f; | |
private float _updateSpeedOfGyroMin = 10f; | |
private float _updateSpeedOfGyroMax = 60f; | |
private float _forceOfAccMax = 200f; | |
private float _filterOfAccMin = 10f; | |
private float _filterOfAccMax = 1000f; | |
private float _forceOfArrowKeyMax = 30f; | |
private void Awake() | |
{ | |
component = (GyroParallaxHelper)target; | |
} | |
public override void OnInspectorGUI() | |
{ | |
EditorGUI.BeginChangeCheck(); | |
DrawDefaultInspector(); | |
SimpleHorizontalLine(); | |
var updateSpeed = EditorGUILayout.Slider("更新頻率:", component.UpdateSpeed, _updateSpeedMin, _updateSpeedMax); | |
var recoverySpeedRatio = EditorGUILayout.Slider("回復速度:", component.RecoverySpeedRatio, _recoverySpeedRatioMin, _recoverySpeedRatioMax); | |
SimpleHorizontalLine(); | |
var enableRotation = EditorGUILayout.Toggle("啟用旋轉:", component.EnableRotation); | |
float rotationMax = component.RotationMax; | |
if (component.EnableRotation) | |
{ | |
rotationMax = EditorGUILayout.Slider("最大角度:", component.RotationMax, 0, _rotationMaxMax); | |
} | |
float moveRatioOfObject = component.MoveRatioOfObject; | |
if (component.LayerObject != null) | |
{ | |
SimpleHorizontalLine(); | |
moveRatioOfObject = EditorGUILayout.FloatField("主物件移動倍率:", component.MoveRatioOfObject); | |
} | |
float moveRatioOfImage = component.MoveRatioOfImage; | |
if (component.LayerImage != null) | |
{ | |
SimpleHorizontalLine(); | |
moveRatioOfImage = EditorGUILayout.FloatField("圖片移動倍率:", component.MoveRatioOfImage); | |
} | |
float moveRatioOfBackground = component.MoveRatioOfBackground; | |
if (component.LayerBackground != null) | |
{ | |
SimpleHorizontalLine(); | |
moveRatioOfBackground = EditorGUILayout.FloatField("背景移動倍率:", component.MoveRatioOfBackground); | |
} | |
SimpleHorizontalLine(); | |
var useTouch = EditorGUILayout.Toggle("開啟觸控:", component.UseTouch); | |
float forceOfTouch = component.ForceOfTouch; | |
bool skipWhenTouch = component.SkipWhenTouch; | |
if (component.UseTouch) | |
{ | |
forceOfTouch = EditorGUILayout.Slider("觸控力道:", component.ForceOfTouch, 0, _forceOfTouchMax); | |
skipWhenTouch = EditorGUILayout.Toggle("觸控時忽略其他反應:", component.SkipWhenTouch); | |
} | |
SimpleHorizontalLine(); | |
EditorGUILayout.BeginHorizontal(); | |
var useGyro = EditorGUILayout.Toggle("使用陀螺儀:", component.UseGyro); | |
var useAcc = EditorGUILayout.Toggle("使用加速度計:", component.UseAcc); | |
float gyroUpdateSpeed = component.GyroUpdateSpeed; | |
float forceOfGyro = component.ForceOfGyro; | |
float forceOfAcc = component.ForceOfAcc; | |
float filterOfAcc = component.FilterOfAcc; | |
EditorGUILayout.EndHorizontal(); | |
if (component.UseGyro && component.UseAcc) | |
{ | |
EditorGUILayout.LabelField("錯誤:不建議同時使用陀螺儀及加速度計"); | |
} | |
else if(component.UseGyro) | |
{ | |
gyroUpdateSpeed = EditorGUILayout.Slider("陀螺儀更新頻率(fps):", component.GyroUpdateSpeed, _updateSpeedOfGyroMin, _updateSpeedOfGyroMax); | |
forceOfGyro = EditorGUILayout.Slider("陀螺儀力道:", component.ForceOfGyro, 0, _forceOfGyroMax); | |
} | |
else if (component.UseAcc) | |
{ | |
forceOfAcc = EditorGUILayout.Slider("加速度計力道:", component.ForceOfAcc, 0, _forceOfAccMax); | |
filterOfAcc = EditorGUILayout.Slider("加速度計濾波:", component.FilterOfAcc, _filterOfAccMin, _filterOfAccMax); | |
} | |
SimpleHorizontalLine(); | |
var useArrowKey = EditorGUILayout.Toggle("使用方向鍵:", component.UseArrowKey); | |
float forceOfArrowKey = component.ForceOfArrowKey; | |
if (component.UseArrowKey) | |
{ | |
forceOfArrowKey = EditorGUILayout.Slider("方向鍵力道:", component.ForceOfArrowKey, 0, _forceOfArrowKeyMax); | |
} | |
if (EditorGUI.EndChangeCheck()) | |
{ | |
Undo.RecordObject(component, "OnGyroParallaxChanged"); | |
component.UpdateSpeed = updateSpeed; | |
component.RecoverySpeedRatio = recoverySpeedRatio; | |
component.EnableRotation = enableRotation; | |
component.RotationMax = rotationMax; | |
component.MoveRatioOfObject = moveRatioOfObject; | |
component.MoveRatioOfImage = moveRatioOfImage; | |
component.MoveRatioOfBackground = moveRatioOfBackground; | |
component.UseTouch = useTouch; | |
component.ForceOfTouch = forceOfTouch; | |
component.SkipWhenTouch = skipWhenTouch; | |
component.UseGyro = useGyro; | |
component.ForceOfGyro = forceOfGyro; | |
component.GyroUpdateSpeed = gyroUpdateSpeed; | |
component.UseAcc = useAcc; | |
component.ForceOfAcc = forceOfAcc; | |
component.FilterOfAcc = filterOfAcc; | |
component.UseArrowKey = useArrowKey; | |
component.ForceOfArrowKey = forceOfArrowKey; | |
} | |
} | |
private void SimpleHorizontalLine() | |
{ | |
GUILayout.Space(5); | |
GUILayout.Box("", new GUILayoutOption[] { GUILayout.ExpandWidth(true), GUILayout.Height(1) }); | |
GUILayout.Space(5); | |
} | |
} | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment