Skip to content

Instantly share code, notes, and snippets.

@jackyli-work
Created February 29, 2020 07:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jackyli-work/0f067dd82c91473ac656c3e6aa65af51 to your computer and use it in GitHub Desktop.
Save jackyli-work/0f067dd82c91473ac656c3e6aa65af51 to your computer and use it in GitHub Desktop.
GyroParallax
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;
}
}
#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