Skip to content

Added Rigidbody physics interaction to the rope's handles #11

@Led-adel-pilot

Description

@Led-adel-pilot

Made a script that adds rigidbody physics to the rope's start and end points

using UnityEngine;

namespace GogoGaga.OptimizedRopesAndCables
{
    /// <summary>
    /// Adds Rigidbody physics interaction to the rope's start and end points.
    /// This script should be added to the same GameObject as the Rope component.
    /// </summary>
    [RequireComponent(typeof(Rope))]
    public class RopeRigidbodyInteraction : MonoBehaviour
    {
        [Header("Rigidbody Interaction Settings")]
        [Tooltip("Enable physics interaction for the Start Point handle. The Start Point GameObject must have a Rigidbody component.")]
        public bool interactWithStartPoint = false;

        [Tooltip("Enable physics interaction for the End Point handle. The End Point GameObject must have a Rigidbody component.")]
        public bool interactWithEndPoint = true;

        [Header("Physics Control")]
        [Tooltip("Controls elasticity. Higher values make the rope more rigid and settle faster, like a steel cable. Lower values make it more elastic.")]
        [Range(1f, 50f)]
        public float rigidityDamping = 10f;


        private Rope rope;
        private Rigidbody startPointRb;
        private Rigidbody endPointRb;

        private void Awake()
        {
            rope = GetComponent<Rope>();
        }

        private void Start()
        {
            // Subscribe to the event to handle runtime changes of rope points
            if (rope != null)
            {
                rope.OnPointsChanged += UpdateRigidbodyReferences;
            }

            // Perform an initial update of the Rigidbody references
            UpdateRigidbodyReferences();
        }

        private void OnDestroy()
        {
            // Unsubscribe from the event when the object is destroyed to prevent memory leaks
            if (rope != null)
            {
                rope.OnPointsChanged -= UpdateRigidbodyReferences;
            }
        }

        /// <summary>
        /// This method is called when the rope's start or end points are changed.
        /// It updates the references to the Rigidbody components on the new points.
        /// </summary>
        private void UpdateRigidbodyReferences()
        {
            startPointRb = (rope.StartPoint != null) ? rope.StartPoint.GetComponent<Rigidbody>() : null;
            endPointRb = (rope.EndPoint != null) ? rope.EndPoint.GetComponent<Rigidbody>() : null;
        }

        private void FixedUpdate()
        {
            // Ensure the rope and its points are valid before applying physics
            if (rope == null || rope.StartPoint == null || rope.EndPoint == null)
            {
                return;
            }

            // Apply constraint to the start point if enabled and a Rigidbody is present
            if (interactWithStartPoint && startPointRb != null)
            {
                ApplyRopeConstraint(startPointRb, rope.EndPoint.position);
            }

            // Apply constraint to the end point if enabled and a Rigidbody is present
            if (interactWithEndPoint && endPointRb != null)
            {
                ApplyRopeConstraint(endPointRb, rope.StartPoint.position);
            }
        }

        /// <summary>
        /// Applies a physics force to a Rigidbody to keep it attached to the rope.
        /// The force acts as a damped spring, pulling the body back when the rope is stretched
        /// and damping the velocity to reduce oscillation.
        /// </summary>
        /// <param name="rb">The Rigidbody to apply the force to.</param>
        /// <param name="otherPointPosition">The position of the other end of the rope, which acts as the anchor.</param>
        private void ApplyRopeConstraint(Rigidbody rb, Vector3 otherPointPosition)
        {
            Vector3 connectionVector = otherPointPosition - rb.position;
            float currentDistance = connectionVector.magnitude;

            // Only apply a restorative force if the rope is stretched beyond its defined length
            if (currentDistance > rope.ropeLength)
            {
                // --- 1. Spring Force (Restorative) ---
                // This force pulls the Rigidbody back towards its maximum allowed distance.
                Vector3 pullDirection = connectionVector.normalized;
                float displacement = currentDistance - rope.ropeLength;
                Vector3 restorativeForce = pullDirection * displacement * rope.stiffness;

                // --- 2. Damping Force (Rigidity) ---
                // This force opposes the Rigidbody's velocity along the pull direction, reducing oscillation.
                // We project the Rigidbody's velocity onto the pull direction to find the speed of the bounce.
                float velocityAlongPullDirection = Vector3.Dot(rb.linearVelocity, pullDirection);
                // The damping force is opposite to this velocity, scaled by our new damping factor.
                Vector3 dampingForce = -pullDirection * velocityAlongPullDirection * rigidityDamping;

                // --- 3. Total Force ---
                // The final force is the combination of the spring force and the damping force.
                Vector3 totalForce = restorativeForce + dampingForce;
                
                // Apply the calculated total force to the Rigidbody.
                rb.AddForce(totalForce, ForceMode.Force);
            }
        }
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions