using System;
using System.Collections.Generic;
using UnityEngine;
#if ENABLE_INPUT_SYSTEM && !ENABLE_LEGACY_INPUT_MANAGER
using UnityEngine.InputSystem;
#endif
namespace MoreMountains.Tools
{
///
/// Use this class to bind a number of UI layers to the movements of a mouse cursor, or a mobile device gyroscope, or even have it be piloted by another script
/// By setting different speed/amplitude values for each of your UI layers, you'll be able to create a nice parallax effect
///
public class MMParallaxUI : MonoBehaviour
{
///
/// A class used to store layer settings
///
[Serializable]
public class ParallaxLayer
{
/// the rect transform for this layer
public RectTransform Rect;
/// the speed at which this layer should move
public float Speed = 2f;
/// the maximum distance this layer can travel from its starting position
public float Amplitude = 50f;
/// the starting position for this layer
[HideInInspector]
public Vector2 StartPosition;
/// if this is false, this layer won't move
public bool Active = true;
}
/// the possible modes used to pilot this parallax rig
public enum Modes { Mouse, Gyroscope, Script }
/// the selected mode for this parallax setup. note that gyroscope mode is only available on mobile devices
public Modes Mode = Modes.Mouse;
/// a multiplier to apply to all layers' amplitudes
public float AmplitudeMultiplier = 1f;
/// a speed multiplier to apply to all layers' speeds
public float SpeedMultiplier = 1f;
/// a list of all the layers to pilot
public List ParallaxLayers;
protected Vector2 _referencePosition;
protected Vector3 _newPosition;
protected Vector2 _mousePosition;
///
/// On Start we initialize our reference position
///
protected virtual void Start()
{
Initialization();
}
///
/// Initializes the start position of all layers
///
public virtual void Initialization()
{
foreach (ParallaxLayer layer in ParallaxLayers)
{
layer.StartPosition = layer.Rect.position;
}
}
///
/// On Update, moves all layers according to the selected mode
///
protected virtual void Update()
{
MoveLayers();
}
///
/// Computes the input data according to the selected mode, and moves the layers accordingly
///
protected virtual void MoveLayers()
{
switch (Mode)
{
case Modes.Gyroscope:
_referencePosition = MMGyroscope.CalibratedInputAcceleration;
break;
case Modes.Mouse:
#if ENABLE_INPUT_SYSTEM && !ENABLE_LEGACY_INPUT_MANAGER
_mousePosition = Mouse.current.position.ReadValue();
#else
_mousePosition = Input.mousePosition;
#endif
_referencePosition = Camera.main.ScreenToViewportPoint(_mousePosition);
break;
}
foreach (ParallaxLayer layer in ParallaxLayers)
{
if (layer.Active)
{
_newPosition.x = Mathf.Lerp(layer.Rect.position.x, layer.StartPosition.x + _referencePosition.x * layer.Amplitude * AmplitudeMultiplier, layer.Speed * SpeedMultiplier * Time.deltaTime);
_newPosition.y = Mathf.Lerp(layer.Rect.position.y, layer.StartPosition.y + _referencePosition.y * layer.Amplitude * AmplitudeMultiplier, layer.Speed * SpeedMultiplier * Time.deltaTime);
_newPosition.z = 0;
layer.Rect.position = _newPosition;
}
}
}
///
/// Sets a new reference position, to use when in Script mode
///
///
public virtual void SetReferencePosition(Vector3 newReferencePosition)
{
_referencePosition = newReferencePosition;
}
}
}