From d2ab30e7a69bfe7efda63ae75812207377917bd3 Mon Sep 17 00:00:00 2001 From: miepzerino <o.skotnik@gmail.com> Date: Sun, 30 Mar 2025 18:50:27 +0000 Subject: [PATCH] Merge branch 'Flexalon-UI-Layouts' into develop --- Assets/Flexalon/Runtime/Animators/FlexalonRigidBodyAnimator.cs | 166 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 166 insertions(+), 0 deletions(-) diff --git a/Assets/Flexalon/Runtime/Animators/FlexalonRigidBodyAnimator.cs b/Assets/Flexalon/Runtime/Animators/FlexalonRigidBodyAnimator.cs new file mode 100644 index 0000000..7d709b0 --- /dev/null +++ b/Assets/Flexalon/Runtime/Animators/FlexalonRigidBodyAnimator.cs @@ -0,0 +1,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 \ No newline at end of file -- Gitblit v1.9.3