// CTOR

        public FilteredFP(FP i_RaiseStepFactor, FP i_LowerStepFactor)
        {
            m_Position = 0.0f;

            m_RaiseStepFactor = MathFP.Max(i_RaiseStepFactor, FP.Zero);
            m_LowerStepFactor = MathFP.Max(i_LowerStepFactor, FP.Zero);
        }
        public FP GetValueAt(FP i_Percentage)
        {
            FP p = MathFP.Clamp01(i_Percentage);

            FP value = m_Min + p * (m_Max - m_Min);

            return(value);
        }
        // TrueSyncBehaviour's interface

        public override void OnSyncedUpdate()
        {
            base.OnSyncedUpdate();

            if (!m_Running)
            {
                return;
            }

            FP area = m_Width * m_Height;

            if (area <= FP.Zero)
            {
                return;
            }

            FP deltaTime = TrueSyncManager.deltaTimeMain;

            TSVector2 center = tsTransform2D.position;

            TSCollider2D[] colliders = TSPhysics2D.OverlapBoxAll(center, size, m_Angle, m_LayerMask);

            if (colliders != null)
            {
                if (colliders.Length > 0)
                {
                    for (int index = 0; index < colliders.Length; ++index)
                    {
                        TSCollider2D currentCollider = colliders[index];

                        if (currentCollider == null)
                        {
                            continue;
                        }

                        TSRigidBody2D rigidbody = currentCollider.GetComponent <TSRigidBody2D>();
                        if (rigidbody != null)
                        {
                            // Drag

                            TSVector2 currentVelocity = rigidbody.velocity;
                            currentVelocity   *= FP.One / (FP.One + (deltaTime * m_Drag));
                            rigidbody.velocity = currentVelocity;

                            // Force

                            FP angle = MathFP.ClampAngle(m_ForceAngle, FP.Zero, 360f);

                            TSVector2 forceDirection = TSVector2.right;
                            forceDirection = forceDirection.Rotate(angle);

                            rigidbody.AddForce(forceDirection * m_ForceMagnitude);
                        }
                    }
                }
            }
        }
        // LOGIC

        public FP Step(FP i_Target, FP i_FrameTime)
        {
            FP smoothStepFactor = (i_Target < m_Position) ? m_LowerStepFactor : m_RaiseStepFactor;
            FP smoothFactor     = (smoothStepFactor > FP.Zero) ? FP.One - MathFP.Pow(FP.Half, i_FrameTime / smoothStepFactor) : FP.One;

            m_Position += (i_Target - m_Position) * smoothFactor;

            return(m_Position);
        }
        // INTERNALS

        private void InternalSetTimeScale(FP i_Value)
        {
            m_TimeScale = MathFP.Max(FP.Zero, i_Value);

            if (m_TimeScale == FP.One)
            {
                Time.timeScale = 1f;
            }
            else
            {
                Time.timeScale = m_TimeScale.AsFloat();
            }
        }
        private void OnDrawGizmosSelected()
        {
            if (!m_DrawGizmos)
            {
                return;
            }

            Color oldColor = Gizmos.color;

            Gizmos.color = Color.white;

            Vector2 center = tsTransform2D.position.ToVector();

            float halfWidth  = m_Width.AsFloat() / 2f;
            float halfHeight = m_Height.AsFloat() / 2f;

            Vector2 topLeft     = new Vector2(center.x - halfWidth, center.y + halfHeight);
            Vector2 topRight    = new Vector2(center.x + halfWidth, center.y + halfHeight);
            Vector2 bottomLeft  = new Vector2(center.x - halfWidth, center.y - halfHeight);
            Vector2 bottomRight = new Vector3(center.x + halfWidth, center.y - halfHeight);

            Vector2 localTopLeft     = topLeft - center;
            Vector2 localTopRight    = topRight - center;
            Vector2 localBottomLeft  = bottomLeft - center;
            Vector2 localBottomRight = bottomRight - center;

            if (m_Angle != FP.Zero)
            {
                FP    angleFP = MathFP.GetNormalizedAngle(m_Angle);
                float angle   = angleFP.AsFloat();

                localTopLeft     = localTopLeft.Rotate(angle);
                localTopRight    = localTopRight.Rotate(angle);
                localBottomLeft  = localBottomLeft.Rotate(angle);
                localBottomRight = localBottomRight.Rotate(angle);
            }

            Gizmos.DrawLine(center + localTopLeft, center + localTopRight);
            Gizmos.DrawLine(center + localTopRight, center + localBottomRight);
            Gizmos.color = Color.blue;
            Gizmos.DrawLine(center + localBottomRight, center + localBottomLeft);
            Gizmos.color = Color.white;
            Gizmos.DrawLine(center + localBottomLeft, center + localTopLeft);

            Gizmos.color = oldColor;
        }
        // TrueSyncBehaviour's interface

        public override void OnSyncedTriggerStay(TSCollision2D i_Collision)
        {
            base.OnSyncedCollisionStay(i_Collision);

            GameObject otherGo = i_Collision.gameObject;

            if (otherGo == null)
            {
                return;
            }

            bool valid = ValidateGameObject(otherGo);

            if (!valid)
            {
                return;
            }

            if (m_Running)
            {
                FP deltaTime = TrueSyncManager.deltaTimeMain;

                TSRigidBody2D rigidbody = otherGo.GetComponent <TSRigidBody2D>();
                if (rigidbody != null)
                {
                    // Drag

                    TSVector2 currentVelocity = rigidbody.velocity;
                    currentVelocity   *= FP.One / (FP.One + (deltaTime * m_Drag));
                    rigidbody.velocity = currentVelocity;

                    // Force

                    FP angle = MathFP.ClampAngle(m_ForceAngle, FP.Zero, 360f);

                    TSVector2 forceDirection = TSVector2.right;
                    forceDirection = forceDirection.Rotate(angle);

                    rigidbody.AddForce(forceDirection * m_ForceMagnitude);
                }
            }
        }