wangguan
2020-12-29 452c75675679c44cc39b04bdb7d330d7c5c14d5c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
 
namespace MoreMountains.NiceVibrations
{
    public class WobbleButton : MonoBehaviour, IPointerExitHandler, IPointerEnterHandler
    {
        public RenderMode ParentCanvasRenderMode { get; protected set; }
 
        [Header("Bindings")]
        public Camera TargetCamera;
        public AudioSource SpringAudioSource;
        public Animator TargetAnimator;
 
        [Header("Haptics")]
        public TextAsset AHAPFile;
 
        [Header("Colors")]
        public Image TargetModel;
 
        [Header("Wobble")]
        public float OffDuration = 0.1f;
        public float MaxRange;
        public AnimationCurve WobbleCurve;
        public float DragResetDuration = 4f;
        public float WobbleFactor = 2f;
 
        protected Vector3 _neutralPosition;
        protected Canvas _canvas;
        protected Vector3 _newTargetPosition;
        protected Vector3 _eventPosition;
        protected Vector2 _workPosition;
        protected float _initialZPosition;
        protected bool _dragging;
        protected int _pointerID;
        protected PointerEventData _pointerEventData;
        protected RectTransform _rectTransform;
 
        protected Vector3 _dragEndedPosition;
        protected float _dragEndedAt;
        protected Vector3 _dragResetDirection;
        protected bool _pointerOn = false;
        protected bool _draggedOnce = false;
        protected int _sparkAnimationParameter;
 
        protected long[] _wobbleAndroidPattern = { 0, 40, 40, 80 };
        protected int[] _wobbleAndroidAmplitude = { 0, 40, 0, 80 };
 
        protected virtual void Start()
        {
            //Initialization();
        }
 
        public virtual void SetPitch(float newPitch)
        {
            SpringAudioSource.pitch = newPitch;
        }
 
        public virtual void Initialization()
        {
            _sparkAnimationParameter = Animator.StringToHash("Spark");
            ParentCanvasRenderMode = GetComponentInParent<Canvas>().renderMode;
            _canvas = GetComponentInParent<Canvas>();
            _initialZPosition = transform.position.z;
            _rectTransform = this.gameObject.GetComponent<RectTransform>();
            SetNeutralPosition();            
        }
 
        public virtual void SetNeutralPosition()
        {
            _neutralPosition = _rectTransform.transform.position;
        }
 
        protected virtual Vector3 GetWorldPosition(Vector3 testPosition)
        {
            if (ParentCanvasRenderMode == RenderMode.ScreenSpaceCamera)
            {
                RectTransformUtility.ScreenPointToLocalPointInRectangle(_canvas.transform as RectTransform, testPosition, _canvas.worldCamera, out _workPosition);
                return _canvas.transform.TransformPoint(_workPosition);
            }
            else
            {
                return testPosition;
            }
        }
 
        protected virtual void Update()
        {
            if (_pointerOn && !_dragging)
            {
                _newTargetPosition = GetWorldPosition(_pointerEventData.position);
 
                float distance = (_newTargetPosition - _neutralPosition).magnitude;
 
                if (distance < MaxRange)
                {
                    _dragging = true;
                }
                else
                {
                    _dragging = false;
                }
            }
 
            if (_dragging)
            {
                StickToPointer();
            }
            else
            {
                GoBackToInitialPosition();
            }
        }
 
        protected virtual void StickToPointer()
        {
            _draggedOnce = true;
            _eventPosition = _pointerEventData.position;
 
            _newTargetPosition = GetWorldPosition(_eventPosition);
 
            // We clamp the stick's position to let it move only inside its defined max range
            _newTargetPosition = Vector2.ClampMagnitude(_newTargetPosition - _neutralPosition, MaxRange);
            _newTargetPosition = _neutralPosition + _newTargetPosition;
            _newTargetPosition.z = _initialZPosition;
 
            transform.position = _newTargetPosition;
        }
 
        protected virtual void GoBackToInitialPosition()
        {
            if (!_draggedOnce)
            {
                return;
            }
 
            if (Time.time - _dragEndedAt < DragResetDuration)
            {
                float time = Remap(Time.time - _dragEndedAt, 0f, DragResetDuration, 0f, 1f);
                float value = WobbleCurve.Evaluate(time) * WobbleFactor;
                _newTargetPosition = Vector3.LerpUnclamped(_neutralPosition, _dragEndedPosition, value);                
                _newTargetPosition.z = _initialZPosition;
            }
            else
            {
                _newTargetPosition = _neutralPosition;
                _newTargetPosition.z = _initialZPosition;
            }
            transform.position = _newTargetPosition;
        }
        
        public virtual void OnPointerEnter(PointerEventData data)
        {
            _pointerID = data.pointerId;
            _pointerEventData = data;
            _pointerOn = true;
        }
 
        public virtual void OnPointerExit(PointerEventData data)
        {
            _eventPosition = _pointerEventData.position;
 
            _newTargetPosition = GetWorldPosition(_eventPosition);
            _newTargetPosition = Vector2.ClampMagnitude(_newTargetPosition - _neutralPosition, MaxRange);
            _newTargetPosition = _neutralPosition + _newTargetPosition;
            _newTargetPosition.z = _initialZPosition;
 
            _dragging = false;            
            _dragEndedPosition = _newTargetPosition;
            _dragEndedAt = Time.time;
            _dragResetDirection = _dragEndedPosition - _neutralPosition;
            _pointerOn = false;
 
            TargetAnimator.SetTrigger(_sparkAnimationParameter);
            SpringAudioSource.Play();
            MMVibrationManager.AdvancedHapticPattern(AHAPFile.text, _wobbleAndroidPattern, _wobbleAndroidAmplitude, -1,
                                                        _wobbleAndroidPattern, _wobbleAndroidAmplitude, _wobbleAndroidAmplitude, -1, HapticTypes.LightImpact, 
                                                        this);
        }
 
        protected virtual float Remap(float x, float A, float B, float C, float D)
        {
            float remappedValue = C + (x - A) / (B - A) * (D - C);
            return remappedValue;
        }
    }
}