miepzerino
2025-03-30 d2ab30e7a69bfe7efda63ae75812207377917bd3
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
#if UNITY_PHYSICS
 
using UnityEngine;
 
namespace Flexalon
{
    /// <summary>
    /// If you add a Rigid Body or Rigid Body 2D component a gameObject which is managed by Flexalon, then
    /// the physics system will fight with Flexalon over the object's position and rotation.
    /// Adding a Rigid Body animator will resolve this by applying forces to the the rigid body component
    /// instead of changing the transform directly.
    /// </summary>
    [AddComponentMenu("Flexalon/Flexalon Rigid Body Animator"), HelpURL("https://www.flexalon.com/docs/animators")]
    public class FlexalonRigidBodyAnimator : MonoBehaviour, TransformUpdater
    {
        private FlexalonNode _node;
        private Rigidbody _rigidBody;
        private Rigidbody2D _rigidBody2D;
 
        [SerializeField]
        private float _positionForce = 5.0f;
        /// <summary> How much force should be applied each frame to move the object to the layout position. </summary>
        public float PositionForce
        {
            get => _positionForce;
            set { _positionForce = value; }
        }
 
        [SerializeField]
        private float _rotationForce = 5.0f;
        /// <summary> How much force should be applied each frame to rotation the object to the layout rotation. </summary>
        public float RotationForce
        {
            get => _rotationForce;
            set { _rotationForce = value; }
        }
 
        [SerializeField]
        private float _scaleInterpolationSpeed = 5.0f;
        /// <summary> Amount the object's scale should be interpolated towards the layout size at each frame.
        /// This value is multiplied by Time.deltaTime. </summary>
        public float ScaleInterpolationSpeed
        {
            get => _scaleInterpolationSpeed;
            set { _scaleInterpolationSpeed = value; }
        }
 
        private Vector3 _targetPosition;
        private Quaternion _targetRotation;
        private Vector3 _fromScale;
        private RectTransform _rectTransform;
 
        void OnEnable()
        {
            _node = Flexalon.GetOrCreateNode(gameObject);
            _node.SetTransformUpdater(this);
            _rigidBody = GetComponent<Rigidbody>();
            _rigidBody2D = GetComponent<Rigidbody2D>();
            _targetPosition = transform.localPosition;
            _targetRotation = transform.localRotation;
            _rectTransform = (transform is RectTransform) ? (RectTransform)transform : null;
        }
 
        void OnDisable()
        {
            _node.SetTransformUpdater(null);
            _node = null;
        }
 
        /// <inheritdoc />
        public void PreUpdate(FlexalonNode node)
        {
            _fromScale = transform.lossyScale;
        }
 
        /// <inheritdoc />
        public bool UpdatePosition(FlexalonNode node, Vector3 position)
        {
            if (_rigidBody || _rigidBody2D)
            {
                _targetPosition = position;
                return false;
            }
            else
            {
                transform.localPosition = position;
                return true;
            }
        }
 
        /// <inheritdoc />
        public bool UpdateRotation(FlexalonNode node, Quaternion rotation)
        {
            if (_rigidBody || _rigidBody2D)
            {
                _targetRotation = rotation;
                return false;
            }
            else
            {
                transform.localRotation = rotation;
                return true;
            }
        }
 
        /// <inheritdoc />
        public bool UpdateScale(FlexalonNode node, Vector3 scale)
        {
            var worldScale = transform.parent == null ? scale : Math.Mul(scale, transform.parent.lossyScale);
            if (Vector3.Distance(_fromScale, worldScale) < 0.001f)
            {
                transform.localScale = scale;
                return true;
            }
            else
            {
                var newWorldScale = Vector3.Lerp(_fromScale, worldScale, _scaleInterpolationSpeed * Time.smoothDeltaTime);
                transform.localScale = transform.parent == null ? newWorldScale : Math.Div(newWorldScale, transform.parent.lossyScale);
                return false;
            }
        }
 
        /// <inheritdoc />
        public bool UpdateRectSize(FlexalonNode node, Vector2 size)
        {
            bool done = Vector2.Distance(_rectTransform.sizeDelta, size) < 0.001f;
            var newSize = done ? size : Vector2.Lerp(_rectTransform.sizeDelta, size, _scaleInterpolationSpeed * Time.smoothDeltaTime);
            _rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, newSize.x);
            _rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, newSize.y);
            return done;
        }
 
        void FixedUpdate()
        {
            if (!_rigidBody && !_rigidBody2D)
            {
                return;
            }
 
            bool hasLayout = _node.Parent != null || (_node.Constraint != null && _node.Constraint.Target != null);
            if (!hasLayout)
            {
                return;
            }
 
            var worldPos = transform.parent ? transform.parent.localToWorldMatrix.MultiplyPoint(_targetPosition) : _targetPosition;
            var force = (worldPos - transform.position) * _positionForce;
            var rot = Quaternion.Slerp(transform.localRotation, _targetRotation, _rotationForce * Time.deltaTime);
            var rotWorldSpace = (transform.parent?.rotation ?? Quaternion.identity) * rot;
 
            if (_rigidBody)
            {
                _rigidBody.AddForce(force, ForceMode.Force);
                _rigidBody.MoveRotation(rotWorldSpace);
            }
 
            if (_rigidBody2D)
            {
                _rigidBody2D?.AddForce(force, ForceMode2D.Force);
                _rigidBody2D.MoveRotation(rotWorldSpace);
            }
        }
    }
}
 
#endif