using FirstGearGames.Utilities.Maths;
using System.Collections.Generic;
using UnityEngine;
namespace FirstGearGames.SmoothCameraShaker
{
public class ShakableCanvas : ShakableBase
{
#region Types.
private struct StartValues
{
public StartValues(Vector3 position, Vector3 rotation)
{
Position = position;
Rotation = rotation;
}
///
/// Start position for an object.
///
public readonly Vector3 Position;
///
/// Start rotation for an object.
///
public readonly Vector3 Rotation;
}
#endregion
#region Serialized.
///
/// True to shake when the default camera shaker does. False to specify a camera shaker to use.
///
[Tooltip("True to shake when the default camera shaker does. False to specify a camera shaker to use.")]
[SerializeField]
private bool _useDefaultCameraShaker = true;
///
/// Camera shaker to monitor.
///
[Tooltip("Camera shaker to monitor.")]
[SerializeField]
private CameraShaker _cameraShaker = null;
///
/// Sets a new CameraShaker to use. This method will do nothing if using ShakableObject as the ShakerType.
///
///
public void SetCameraShaker(CameraShaker shaker)
{
if (base.ShakerType == ShakerTypes.ObjectShaker)
return;
if (_useDefaultCameraShaker)
{
if (Debug.isDebugBuild) Debug.LogWarning("Cannot set CameraShaker with UseDefaultCameraShaker set. If you wish to change CameraShaker at run-time set UseDefaultCameraShaker to false before entering play.");
}
else
{
ChangeCameraShakers(_cameraShaker, shaker, true);
}
}
///
/// True to create a parent object and attach children to it. The parent object will be shaken instead of each individual canvas child. If your direct children move at all this value must be true. Setting value as false may incur extra cost as well.
///
[Tooltip("True to create a parent object and attach children to it. The parent object will be shaken instead of each individual canvas child. If your direct children move at all this value must be true. Setting value as false may incur extra cost as well.")]
[Space(10)]
[SerializeField]
private bool _encapsulateChildren = true;
///
/// True to watch for additional children to encapsulate. This may be false if you do not add direct children to this canvas at runtime.
///
[Tooltip("True to watch for additional children to encapsulate. This may be false if you do not add direct children to this canvas at runtime.")]
[SerializeField]
private bool _monitorEncapsulation = false;
///
/// Positional shakes are multiplied by this value. Lower values will result in a lower positional magnitude.
///
[Tooltip("Positional shakes are multiplied by this value. Lower values will result in a lower positional magnitude.")]
[SerializeField]
private float _positionalMultiplier = 1f;
///
/// Rotational shakes are multiplied by this value. Lower values will result in lower ritational magnitude.
///
[Tooltip("Rotational shakes are multiplied by this value. Lower values will result in lower rotational magnitude.")]
[SerializeField]
private float _rotationalMultiplier = 1f;
///
/// True to randomly change influence direction when shaking starts.
///
[Tooltip("True to randomly change influence direction when shaking starts.")]
[Space(10)]
[SerializeField]
private bool _randomizeDirections = true;
#endregion
#region Private.
///
/// Transform children are being attached to. This only exist if EncapsulateChildren is true.
///
private RectTransform _parentRect;
///
/// Start values for children of this transform.
///
private Dictionary _childrenStartValues = new Dictionary();
///
/// Next time to clean ChildrenStartValues.
///
private float _nextCleanStartValuesTime;
///
/// Current camera shaker this canvas is subscribed to.
///
private CameraShaker _currentCameraShaker = null;
///
/// ObjectShaker used for this object. May be null if not using ObjectShaker type.
///
private ObjectShaker _objectShaker = null;
///
/// Direction to multiply position by when shaking starts.
///
private float _randomPositionMultiplier = 1f;
///
/// Direction to multiply rotation by when shaking starts.
///
private float _randomRotationMultiplier = 1f;
#endregion
private void Awake()
{
FirstInitialize();
}
private void OnEnable()
{
//Subscribe.
ChangeSubscription(true);
}
private void Update()
{
/* If fails to encapsulate new children then remove script.
* Something unrecoverable went wrong. */
if (_monitorEncapsulation && !EncapsulateChildren(false))
{
DestroyImmediate(this);
return;
}
CheckRemoveNullStartValues();
}
private void OnDisable()
{
//Unsubscribe.
ChangeSubscription(false);
ResetOffsets();
}
///
/// Initializes this script for use. Should only be cmpleted once.
///
private void FirstInitialize()
{
//If using ObjectShaker type.
if (base.ShakerType == ShakerTypes.ObjectShaker)
{
_objectShaker = GetComponentInParent();
if (_objectShaker == null)
{
Debug.LogError("ObjectShaker could not be found on or above object " + gameObject.name + ". Shakable will be destroyed.", this);
DestroyImmediate(this);
return;
}
}
Canvas canvas = GetComponent