init
This commit is contained in:
+385
@@ -0,0 +1,385 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using System;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.Events;
|
||||
using frame8.Logic.Misc.Visual.UI;
|
||||
using frame8.Logic.Misc.Other.Extensions;
|
||||
|
||||
namespace Com.ForbiddenByte.OSA.Util.PullToRefresh
|
||||
{
|
||||
/// <summary>
|
||||
/// Attach it to your ScrollView where the pull to refresh functionality is needed.
|
||||
/// Browse the PullToRefreshExample scene to see how the gizmo should be set up. An image is better than 1k words.
|
||||
/// </summary>
|
||||
public class PullToRefreshBehaviour : MonoBehaviour, IScrollRectProxy, IBeginDragHandler, IDragHandler, IEndDragHandler
|
||||
{
|
||||
#region Serialized fields
|
||||
/// <summary>The normalized distance relative to screen size. Always between 0 and 1</summary>
|
||||
[SerializeField] [Range(.1f, 1f)] [Tooltip("The normalized distance relative to screen size. Always between 0 and 1")]
|
||||
float _PullAmountNormalized = .25f;
|
||||
|
||||
/// <summary>The reference of the gizmo to use. If null, will try to GetComponentInChildren<PullToRefreshGizmo>()</summary>
|
||||
[SerializeField] [Tooltip("If null, will try to GetComponentInChildren()")]
|
||||
PullToRefreshGizmo _RefreshGizmo = null;
|
||||
|
||||
//[SerializeField]
|
||||
//RectTransform.Axis _Axis;
|
||||
|
||||
/// <summary></summary>
|
||||
[SerializeField]
|
||||
bool _AllowPullFromEnd = false;
|
||||
|
||||
/// <summary>If false, you'll need to call HideGizmo() manually after pull. Subscribe to PullToRefreshBehaviour.OnRefresh event to know when a refresh event occurred. This method is used when the gizmo should do an animation while the refresh is executing (for ex., when some data is downloading)</summary>
|
||||
[SerializeField] [Tooltip("If false, you'll need to call HideGizmo() manually after pull. Subscribe to PullToRefreshBehaviour.OnRefresh event to know when a refresh event occurred")]
|
||||
bool _AutoHideRefreshGizmo = true;
|
||||
#pragma warning disable 0649
|
||||
/// <summary>Quick way of playing a sound effect when the pull power reaches 1f</summary>
|
||||
[SerializeField]
|
||||
AudioClip _SoundOnPreRefresh = null;
|
||||
|
||||
/// <summary>Quick way of playing a sound effect when the refresh occurred</summary>
|
||||
[SerializeField]
|
||||
AudioClip _SoundOnRefresh = null;
|
||||
#endregion
|
||||
#pragma warning restore 0649
|
||||
|
||||
#region Unity events
|
||||
[Tooltip("Unity event fired when the pull was released")]
|
||||
/// <summary>Unity event (editable in inspector) fired when the refresh occurred</summary>
|
||||
public UnityEvent OnRefresh = null;
|
||||
|
||||
[Tooltip("Same as OnRefresh, but also gives you the refresh sign.\n" +
|
||||
"1 = top, -1 = bottom")]
|
||||
/// <summary>Same as <see cref="OnRefresh"/>, but also gives you the refresh sign. 1 = top, -1 = bottom</summary>
|
||||
public UnityEventFloat OnRefreshWithSign = null;
|
||||
|
||||
[Tooltip("Unity event (editable in inspector) fired when each frame the click/finger is dragged after it has touched the ScrollView.\n" +
|
||||
"Negative values indicate pulling from end")]
|
||||
/// <summary>
|
||||
/// Unity event (editable in inspector) fired when each frame the click/finger is dragged after it has touched the ScrollView.
|
||||
/// Negative values indicate pulling from end
|
||||
/// </summary>
|
||||
public UnityEventFloat OnPullProgress = null;
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Will be retrieved from the scrollrect. If not found, it can be assigned anytime before the first Update.
|
||||
/// If not assigned, a default proxy will be used. The purpose of this is to allow custom implementations of ScrollRect to be used
|
||||
/// </summary>
|
||||
public IScrollRectProxy externalScrollRectProxy;
|
||||
|
||||
#region IScrollRectProxy properties implementation
|
||||
public bool IsInitialized { get { return _ScrollRect != null; } }
|
||||
public Vector2 Velocity { get; set; }
|
||||
public bool IsHorizontal { get { return _ScrollRect.horizontal; } }
|
||||
public bool IsVertical { get { return _ScrollRect.vertical; } }
|
||||
public RectTransform Content { get { return _ScrollRect.content; } }
|
||||
public RectTransform Viewport { get { return _ScrollRect.viewport; } }
|
||||
double IScrollRectProxy.ContentInsetFromViewportStart { get { return Content.GetInsetFromParentEdge(Viewport, ScrollRectProxy.GetStartEdge()); } }
|
||||
double IScrollRectProxy.ContentInsetFromViewportEnd { get { return Content.GetInsetFromParentEdge(Viewport, ScrollRectProxy.GetEndEdge()); } }
|
||||
#endregion
|
||||
|
||||
IScrollRectProxy ScrollRectProxy { get { return externalScrollRectProxy == null ? this : externalScrollRectProxy; } }
|
||||
|
||||
ScrollRect _ScrollRect;
|
||||
float _ResolvedAVGScreenSize;
|
||||
bool _PlayedPreSoundForCurrentDrag;
|
||||
//bool _IgnoreCurrentDrag;
|
||||
RectTransform _RT;
|
||||
int _CurrentDragSign;
|
||||
StateEnum _State;
|
||||
|
||||
|
||||
/// <summary>Not used in this default interface implementation</summary>
|
||||
#pragma warning disable 0067
|
||||
public event Action<double> ScrollPositionChanged = delegate { };
|
||||
#pragma warning restore 0067
|
||||
|
||||
|
||||
void Awake()
|
||||
{
|
||||
_RT = transform as RectTransform;
|
||||
_ResolvedAVGScreenSize = (Screen.width + Screen.height) / 2f;
|
||||
_ScrollRect = GetComponent<ScrollRect>();
|
||||
_RefreshGizmo = GetComponentInChildren<PullToRefreshGizmo>(); // self or children
|
||||
if (_ScrollRect)
|
||||
{
|
||||
// May be null
|
||||
externalScrollRectProxy = _ScrollRect.GetComponent(typeof(IScrollRectProxy)) as IScrollRectProxy;
|
||||
}
|
||||
else
|
||||
{
|
||||
externalScrollRectProxy = GetComponentInParent(typeof(IScrollRectProxy)) as IScrollRectProxy;
|
||||
if (externalScrollRectProxy == null)
|
||||
{
|
||||
if (enabled)
|
||||
{
|
||||
Debug.Log(GetType().Name + ": no scrollRect provided and found no " + typeof(IScrollRectProxy).Name + " component among ancestors. Disabling...");
|
||||
enabled = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region IScrollRectProxy methods implementation (used if external proxy is not manually assigned)
|
||||
public void SetNormalizedPosition(double normalizedPosition) { }
|
||||
|
||||
public double GetNormalizedPosition()
|
||||
{
|
||||
if (_ScrollRect.horizontal)
|
||||
return _ScrollRect.horizontalNormalizedPosition;
|
||||
return _ScrollRect.verticalNormalizedPosition;
|
||||
}
|
||||
|
||||
public double GetContentSize() { return _RT.rect.size[_ScrollRect.horizontal ? 0 : 1]; }
|
||||
public double GetViewportSize() { return Viewport.rect.size[_ScrollRect.horizontal ? 0 : 1]; }
|
||||
|
||||
public void StopMovement() { _ScrollRect.StopMovement(); }
|
||||
#endregion
|
||||
|
||||
#region UI callbacks
|
||||
public void OnBeginDrag(PointerEventData eventData)
|
||||
{
|
||||
if (eventData.button != PointerEventData.InputButton.Left)
|
||||
return;
|
||||
|
||||
if (!isActiveAndEnabled)
|
||||
return;
|
||||
|
||||
if (_State != StateEnum.NONE)
|
||||
return;
|
||||
|
||||
if (_RefreshGizmo.IsShown)
|
||||
return;
|
||||
|
||||
if (!ScrollRectProxy.IsInitialized)
|
||||
return;
|
||||
|
||||
double dragAmountNorm, _;
|
||||
GetDragAmountNormalized(eventData, out dragAmountNorm, out _);
|
||||
if (!_AllowPullFromEnd && dragAmountNorm < 0d)
|
||||
return;
|
||||
|
||||
int curDragSign = Math.Sign(dragAmountNorm);
|
||||
_CurrentDragSign = curDragSign;
|
||||
_PlayedPreSoundForCurrentDrag = false;
|
||||
|
||||
_State = StateEnum.DRAGGING_WAITING_FOR_PULL;
|
||||
}
|
||||
|
||||
public void OnDrag(PointerEventData eventData)
|
||||
{
|
||||
if (eventData.button != PointerEventData.InputButton.Left)
|
||||
return;
|
||||
|
||||
if (!isActiveAndEnabled)
|
||||
return;
|
||||
|
||||
if (!ScrollRectProxy.IsInitialized)
|
||||
return;
|
||||
|
||||
|
||||
switch (_State)
|
||||
{
|
||||
case StateEnum.DRAGGING_WAITING_FOR_PULL:
|
||||
if (!IsContentBiggerThanViewport() || IsScrollRectAtTarget(_CurrentDragSign))
|
||||
{
|
||||
_State = StateEnum.PULLING_WAITING_FOR_RELEASE;
|
||||
goto case StateEnum.PULLING_WAITING_FOR_RELEASE;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
case StateEnum.PULLING_WAITING_FOR_RELEASE:
|
||||
if (IsContentBiggerThanViewport() && !IsScrollRectAtTarget(_CurrentDragSign))
|
||||
{
|
||||
HideGizmoInternal();
|
||||
_State = StateEnum.DRAGGING_WAITING_FOR_PULL;
|
||||
return;
|
||||
}
|
||||
|
||||
double dragAmountNorm, deltaNorm;
|
||||
GetDragAmountNormalized(eventData, out dragAmountNorm, out deltaNorm);
|
||||
if (Math.Sign(dragAmountNorm) != _CurrentDragSign)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//if (!_AllowPullFromEnd && dragAmountNorm < 0d)
|
||||
//{
|
||||
// HideGizmoInternal();
|
||||
// return;
|
||||
//}
|
||||
|
||||
double pullPower = dragAmountNorm;
|
||||
|
||||
ShowGizmoIfNeeded();
|
||||
if (_RefreshGizmo)
|
||||
_RefreshGizmo.OnPull(pullPower);
|
||||
|
||||
if (OnPullProgress != null)
|
||||
OnPullProgress.Invoke((float)pullPower);
|
||||
|
||||
if (Math.Abs(pullPower) >= 1d && !_PlayedPreSoundForCurrentDrag)
|
||||
{
|
||||
_PlayedPreSoundForCurrentDrag = true;
|
||||
|
||||
if (_SoundOnPreRefresh)
|
||||
AudioSource.PlayClipAtPoint(_SoundOnPreRefresh, Camera.main.transform.position);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//Debug.Log("eventData.pressPosition=" + eventData.pressPosition + "\n eventData.position=" + eventData.position + "\neventData.scrollDelta="+ eventData.scrollDelta);
|
||||
}
|
||||
|
||||
public void OnEndDrag(PointerEventData eventData)
|
||||
{
|
||||
if (eventData.button != PointerEventData.InputButton.Left)
|
||||
return;
|
||||
|
||||
if (!ScrollRectProxy.IsInitialized)
|
||||
return;
|
||||
|
||||
if (_State != StateEnum.PULLING_WAITING_FOR_RELEASE)
|
||||
{
|
||||
if (_State == StateEnum.DRAGGING_WAITING_FOR_PULL)
|
||||
{
|
||||
HideGizmoInternal();
|
||||
_State = StateEnum.NONE;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
bool proceedRefresh = false;
|
||||
if (isActiveAndEnabled)
|
||||
{
|
||||
proceedRefresh = true;
|
||||
if (IsContentBiggerThanViewport())
|
||||
proceedRefresh = IsScrollRectAtTarget(_CurrentDragSign);
|
||||
|
||||
if (proceedRefresh)
|
||||
{
|
||||
double dragAmount, _;
|
||||
GetDragAmountNormalized(eventData, out dragAmount, out _);
|
||||
if (Math.Sign(dragAmount) != _CurrentDragSign)
|
||||
proceedRefresh = false;
|
||||
else if (Math.Abs(dragAmount) < 1d)
|
||||
proceedRefresh = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (proceedRefresh)
|
||||
{
|
||||
if (OnRefresh != null)
|
||||
OnRefresh.Invoke();
|
||||
|
||||
if (OnRefreshWithSign != null)
|
||||
OnRefreshWithSign.Invoke(_CurrentDragSign);
|
||||
|
||||
if (_RefreshGizmo)
|
||||
_RefreshGizmo.OnRefreshed(_AutoHideRefreshGizmo);
|
||||
|
||||
if (_SoundOnRefresh)
|
||||
AudioSource.PlayClipAtPoint(_SoundOnRefresh, Camera.main.transform.position);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_RefreshGizmo)
|
||||
_RefreshGizmo.OnRefreshCancelled();
|
||||
_State = StateEnum.NONE;
|
||||
}
|
||||
|
||||
if (_RefreshGizmo && _RefreshGizmo.IsShown)
|
||||
{
|
||||
if (_AutoHideRefreshGizmo)
|
||||
{
|
||||
HideGizmoInternal();
|
||||
_State = StateEnum.NONE;
|
||||
}
|
||||
else
|
||||
{
|
||||
_State = StateEnum.AFTER_RELEASE_WAITING_FOR_GIZMO_TO_HIDE;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
// sign: 1=start(top or left), -1=end(bottom or right);
|
||||
bool IsScrollRectAtTarget(int targetDragSign)
|
||||
{
|
||||
double normPos = ScrollRectProxy.GetNormalizedPosition();
|
||||
if (ScrollRectProxy.IsHorizontal)
|
||||
normPos = 1d - normPos;
|
||||
|
||||
if (targetDragSign == 1 && normPos >= 1d)
|
||||
return true;
|
||||
if (targetDragSign == -1 && normPos <= 0d)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsContentBiggerThanViewport() { return ScrollRectProxy.GetContentSize() > _RT.rect.size[ScrollRectProxy.IsHorizontal ? 0 : 1]; }
|
||||
|
||||
public void ShowGizmoIfNeeded()
|
||||
{
|
||||
if (_RefreshGizmo && !_RefreshGizmo.IsShown)
|
||||
_RefreshGizmo.IsShown = true;
|
||||
}
|
||||
|
||||
public void HideGizmo()
|
||||
{
|
||||
HideGizmoInternal();
|
||||
if (_State == StateEnum.AFTER_RELEASE_WAITING_FOR_GIZMO_TO_HIDE)
|
||||
_State = StateEnum.NONE;
|
||||
}
|
||||
|
||||
void HideGizmoInternal()
|
||||
{
|
||||
if (_RefreshGizmo)
|
||||
_RefreshGizmo.IsShown = false;
|
||||
}
|
||||
|
||||
void GetDragAmountNormalized(PointerEventData eventData, out double total, out double delta)
|
||||
{
|
||||
total = 0d;
|
||||
delta = 0d;
|
||||
float pos;
|
||||
float maxPullAmount = _PullAmountNormalized * _ResolvedAVGScreenSize;
|
||||
if (ScrollRectProxy.IsVertical)
|
||||
{
|
||||
pos = eventData.position.y;
|
||||
float worldDragVec = pos - eventData.pressPosition.y;
|
||||
total = -worldDragVec;
|
||||
delta = -eventData.delta.y;
|
||||
}
|
||||
else
|
||||
{
|
||||
pos = eventData.position.x;
|
||||
float worldDragVec = pos - eventData.pressPosition.x;
|
||||
total = worldDragVec;
|
||||
delta = eventData.delta.x;
|
||||
}
|
||||
total /= maxPullAmount;
|
||||
delta /= maxPullAmount;
|
||||
}
|
||||
|
||||
|
||||
enum StateEnum
|
||||
{
|
||||
NONE,
|
||||
DRAGGING_WAITING_FOR_PULL,
|
||||
PULLING_WAITING_FOR_RELEASE,
|
||||
AFTER_RELEASE_WAITING_FOR_GIZMO_TO_HIDE
|
||||
}
|
||||
|
||||
|
||||
[Serializable]
|
||||
public class UnityEventFloat : UnityEvent<float> { }
|
||||
}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8a7fcb71e0128534fb984a6449319591
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
@@ -0,0 +1,50 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Com.ForbiddenByte.OSA.Util.PullToRefresh
|
||||
{
|
||||
/// <summary> Base class for gizmos that can be used with <see cref="PullToRefreshBehaviour"/> (see it for more details). Attach it to your ScrollView </summary>
|
||||
public class PullToRefreshGizmo : MonoBehaviour
|
||||
{
|
||||
/// <summary>Property that can be overriden by the inheritors. The default implementation is to set whether the game object is active or not</summary>
|
||||
public virtual bool IsShown
|
||||
{
|
||||
get { return _IsShown; }
|
||||
set
|
||||
{
|
||||
_IsShown = value;
|
||||
|
||||
gameObject.SetActive(_IsShown);
|
||||
}
|
||||
}
|
||||
|
||||
bool _IsShown;
|
||||
|
||||
|
||||
public virtual void Awake()
|
||||
{}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// <para>Called for each OnDrag event on the ScrollView. In other words, it's called continuously during moving the mouse/finger after the click</para>
|
||||
/// </summary>
|
||||
/// <param name="power">0d = didn't drag at all; .5d = dragged half-way from start; 1d = dragged from start exactly at the minimum needed point in
|
||||
/// order for a refresh event to occur; values will exceed 1f after this minimum drag amount is exceeded
|
||||
/// (which can be used to visualize the fact that after the click/finger is released, the refresh will occur).
|
||||
/// Negative values indicate a pull from the end instead of start, and the same rules apply
|
||||
/// </param>
|
||||
public virtual void OnPull(double power)
|
||||
{}
|
||||
|
||||
/// <summary> Called when the refresh did occur (dragged with at least 1f power and released)</summary>
|
||||
/// <param name="autoHide">A hint for the gizmo to know whether it should hide itself or something will hide it externally by setting <see cref="IsShown"/>=false </param>
|
||||
public virtual void OnRefreshed(bool autoHide)
|
||||
{
|
||||
if (autoHide)
|
||||
IsShown = false;
|
||||
}
|
||||
|
||||
/// <summary> Called when the click/finger was released before the pullPower reached 1f</summary>
|
||||
public virtual void OnRefreshCancelled()
|
||||
{ IsShown = false; }
|
||||
}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e3a396e6841ce6343adc9ea23c888ab8
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
+159
@@ -0,0 +1,159 @@
|
||||
using UnityEngine;
|
||||
using System;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
namespace Com.ForbiddenByte.OSA.Util.PullToRefresh
|
||||
{
|
||||
/// <summary>
|
||||
/// <para> Implementation of <see cref="PullToRefreshGizmo"/> that uses a rotating image to show the pull progress. </para>
|
||||
/// <para>The image is rotated by the amount of distance traveled by the click/finger.</para>
|
||||
/// <para>When enough pulling distance is covered the gizmo enters the "ready to refresh" state,</para>
|
||||
/// <para>the rotation amount applied is damped by <see cref="_ExcessPullRotationDamping"/> (i.e. a value of 1f won't apply any furter rotation, </para>
|
||||
/// <para>while a value of 0f will apply the same amount of rotation per distance traveled by the click/finger as before the "ready to refresh" state).</para>
|
||||
/// <para>When <see cref="OnRefreshed(bool)"/> is called with true, the gizmo will disappear; if it'll be called with false, </para>
|
||||
/// <para>it'll start auto-rotating with a speed of <see cref="_AutoRotationDegreesPerSec"/> degrees per second, until <see cref="IsShown"/> is set to false.</para>
|
||||
/// <para>This last use-case is very common for when the refresh event actually takes time (i.e. retrieving items from a server).</para>
|
||||
/// </summary>
|
||||
public class PullToRefreshRotateGizmo : PullToRefreshGizmo
|
||||
{
|
||||
#pragma warning disable 0649
|
||||
[SerializeField]
|
||||
[FormerlySerializedAs("_StartingPoint")]
|
||||
RectTransform _PullFromStartInitial = null;
|
||||
[SerializeField]
|
||||
[FormerlySerializedAs("_EndingPoint")]
|
||||
RectTransform _PullFromStartTarget = null;
|
||||
|
||||
[SerializeField]
|
||||
RectTransform _PullFromEndInitial = null;
|
||||
[SerializeField]
|
||||
RectTransform _PullFromEndTarget = null;
|
||||
#pragma warning restore 0649
|
||||
|
||||
//[Tooltip("When pulling is done from the end, this gizmo will also appear at the end, not at the start. " +
|
||||
// "\nThe gizmo's position in this case is inferred using the parent's size and _StartingPoint & _EndingPoint ")]
|
||||
//[SerializeField]
|
||||
//bool _AllowAppearingFromEnd = true;
|
||||
|
||||
[SerializeField]
|
||||
[Range(0f, 1f)]
|
||||
float _ExcessPullRotationDamping = .95f;
|
||||
|
||||
[SerializeField]
|
||||
float _AutoRotationDegreesPerSec = 200;
|
||||
|
||||
[Tooltip("Will also interpolate its own scale between the Initial's and Target's scale")]
|
||||
[SerializeField]
|
||||
bool _ScaleWithTarget = true;
|
||||
|
||||
[Tooltip("If true, it won't be affected by Time.timeScale")]
|
||||
[SerializeField]
|
||||
bool _UseUnscaledTime = true;
|
||||
|
||||
bool _WaitingForManualHide;
|
||||
|
||||
|
||||
/// <summary>Calls base implementation + resets the rotation to default each time is assigned, regardless if true or false</summary>
|
||||
public override bool IsShown
|
||||
{
|
||||
get { return base.IsShown; }
|
||||
|
||||
set
|
||||
{
|
||||
base.IsShown = value;
|
||||
|
||||
// Reset to default rotation
|
||||
transform.localRotation = Quaternion.Euler(_InitialLocalRotation);
|
||||
|
||||
if (!value)
|
||||
_WaitingForManualHide = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Vector3 _InitialLocalRotation, _InitialLocalScale;
|
||||
Transform _TR;
|
||||
|
||||
|
||||
public override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
_TR = transform;
|
||||
|
||||
_InitialLocalRotation = _TR.localRotation.eulerAngles;
|
||||
_InitialLocalScale = _TR.localScale;
|
||||
}
|
||||
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (_WaitingForManualHide)
|
||||
{
|
||||
SetLocalZRotation((_TR.localEulerAngles.z - (_UseUnscaledTime ? Time.unscaledDeltaTime : Time.deltaTime) * _AutoRotationDegreesPerSec) % 360);
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnPull(double power)
|
||||
{
|
||||
base.OnPull(power);
|
||||
|
||||
double powerAbs = Math.Abs(power);
|
||||
int powerSign = Math.Sign(power);
|
||||
float powerAbsClamped01 = Mathf.Clamp01((float)powerAbs);
|
||||
float excess = Mathf.Max(0f, (float)powerAbs - 1f);
|
||||
|
||||
float dampedExcess = excess * (1f - _ExcessPullRotationDamping);
|
||||
|
||||
SetLocalZRotation((_InitialLocalRotation.z - 360 * (powerAbsClamped01 + dampedExcess)) % 360);
|
||||
|
||||
//_TR.position = LerpUnclamped(_StartingPoint.position, _EndingPoint.position, power <= 1f ? (power - (1f - power/2)*(1f-power/2)) : (1 - 1/(1 + excess) ));
|
||||
Vector3 start, end;
|
||||
Vector3 scaleStart, scaleEnd;
|
||||
if (powerSign < 0 && _PullFromEndInitial && _PullFromEndTarget)
|
||||
{
|
||||
start = _PullFromEndInitial.position;
|
||||
end = _PullFromEndTarget.position;
|
||||
scaleStart = _PullFromEndInitial.localScale;
|
||||
scaleEnd = _PullFromEndTarget.localScale;
|
||||
}
|
||||
else
|
||||
{
|
||||
start = _PullFromStartInitial.position;
|
||||
end = _PullFromStartTarget.position;
|
||||
scaleStart = _PullFromStartInitial.localScale;
|
||||
scaleEnd = _PullFromStartTarget.localScale;
|
||||
}
|
||||
|
||||
var t01Unclamped = 2 - 2 / (1 + powerAbsClamped01);
|
||||
_TR.position = LerpUnclamped(start, end, t01Unclamped);
|
||||
if (_ScaleWithTarget)
|
||||
_TR.localScale = LerpUnclamped(scaleStart, scaleEnd, t01Unclamped);
|
||||
else
|
||||
_TR.localScale = _InitialLocalScale;
|
||||
}
|
||||
|
||||
public override void OnRefreshCancelled()
|
||||
{
|
||||
base.OnRefreshCancelled();
|
||||
|
||||
_WaitingForManualHide = false;
|
||||
}
|
||||
|
||||
public override void OnRefreshed(bool autoHide)
|
||||
{
|
||||
base.OnRefreshed(autoHide);
|
||||
|
||||
_WaitingForManualHide = !autoHide;
|
||||
}
|
||||
|
||||
Vector3 LerpUnclamped(Vector3 from, Vector3 to, float t) { return (1f - t) * from + t * to ; }
|
||||
|
||||
void SetLocalZRotation(float zRotation)
|
||||
{
|
||||
var rotE = _TR.localRotation.eulerAngles;
|
||||
rotE.z = zRotation;
|
||||
_TR.localRotation = Quaternion.Euler(rotE);
|
||||
}
|
||||
}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 26e83b34c01bd224294affa1aee5a14d
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
Reference in New Issue
Block a user