Skip to content

Instantly share code, notes, and snippets.

@staggartcreations
Last active March 6, 2024 12:58
Show Gist options
  • Select an option

  • Save staggartcreations/39571498ae1f6c760db6a34d6e1b28a5 to your computer and use it in GitHub Desktop.

Select an option

Save staggartcreations/39571498ae1f6c760db6a34d6e1b28a5 to your computer and use it in GitHub Desktop.

Revisions

  1. staggartcreations revised this gist Feb 9, 2024. 1 changed file with 59 additions and 30 deletions.
    89 changes: 59 additions & 30 deletions Rope.cs
    Original file line number Diff line number Diff line change
    @@ -1,37 +1,54 @@
    using System;
    using UnityEngine;
    using UnityEngine.Serialization;
    #if UNITY_EDITOR
    using UnityEditor;
    #endif

    [RequireComponent(typeof(Rigidbody))]
    public class Rope : MonoBehaviour
    public class RopeGenerator : MonoBehaviour
    {
    public LineRenderer lineRenderer;
    public Transform endPoint;
    public Rigidbody attachementBody;

    [Space]

    [Header("Generator")]
    [Range(0.25f, 1f)]
    public float jointDistance = 1f;
    public float width = 0.05f;
    public float jointDistance = 0.5f;
    public Vector3 offset;

    [Space]

    [Header("Appearance")]
    public LineRenderer lineRenderer;
    public float length = 5f;
    [Range(0.025f, 0.25f)]
    public float radius = 0.05f;

    [SerializeField]
    [Header("Physics")]
    public float mass = 100;
    public float drag = 1;

    [Space]

    [SerializeField] [HideInInspector]
    private HingeJoint[] hinges;
    private Rigidbody startRigidBody;
    private Rigidbody endRigidBody;
    private HingeJoint endJoint;

    private void LateUpdate()
    {
    UpdateLineRenderer();
    }
    public void Rebuild()

    private void Start()
    {
    if (!endPoint) return;
    //Unparent object so that it follows the attachement point freely
    this.transform.parent = null;
    }

    if (!startRigidBody) startRigidBody = GetComponent<Rigidbody>();
    startRigidBody.isKinematic = true;
    public void Rebuild()
    {
    if (!attachementBody) attachementBody = GetComponent<Rigidbody>();
    attachementBody.isKinematic = true;

    float length = (transform.position - endPoint.position).magnitude;
    int segmentCount = Mathf.RoundToInt(length / jointDistance);

    if (hinges != null)
    @@ -45,34 +62,44 @@ public void Rebuild()
    }
    hinges = new HingeJoint[segmentCount];

    Vector3 direction = (endPoint.position - transform.position).normalized;
    Vector3 direction = Vector3.down;
    Vector3 localDirection = transform.TransformDirection(direction);

    for (int i = 0; i < hinges.Length; i++)
    {
    GameObject hingeObj = new GameObject("Hinge_" + i);
    hingeObj.transform.up = direction;
    hingeObj.transform.parent = this.transform;
    hingeObj.transform.localPosition = localDirection * (i * jointDistance);
    hingeObj.transform.localPosition = offset + localDirection * (i * jointDistance);

    HingeJoint joint = hingeObj.AddComponent<HingeJoint>();
    Rigidbody rb = joint.GetComponent<Rigidbody>();
    rb.mass = mass;
    rb.drag = drag;

    CapsuleCollider collider = joint.gameObject.AddComponent<CapsuleCollider>();
    collider.radius = width;
    collider.radius = radius;
    collider.center = new Vector3(0f, jointDistance * 0.5f, 0f);
    collider.height = jointDistance;

    if (i == 0) joint.connectedBody = startRigidBody;
    //Make the last joint a sphere, to be used as an attachement point
    if (i == hinges.Length-1)
    {
    collider.height = 0f;
    collider.center = Vector3.zero;
    collider.gameObject.name = "End Point";
    }

    if (i == 0) joint.connectedBody = attachementBody;
    if (i > 0) joint.connectedBody = hinges[i - 1].GetComponent<Rigidbody>();

    hinges[i] = joint;
    }

    if (endJoint == null) endJoint = endPoint.GetComponent<HingeJoint>();
    if (endJoint == null) endJoint = endPoint.gameObject.AddComponent<HingeJoint>();
    if (endRigidBody == null) endRigidBody = endPoint.GetComponent<Rigidbody>();
    //if (endJoint == null) endJoint = endPoint.GetComponent<HingeJoint>();
    //if (endJoint == null) endJoint = endPoint.gameObject.AddComponent<HingeJoint>();

    endJoint.connectedBody = hinges[hinges.Length - 1].GetComponent<Rigidbody>();
    //endJoint.connectedBody = hinges[hinges.Length - 1].GetComponent<Rigidbody>();

    RebuildLineRenderer();
    }
    @@ -86,7 +113,7 @@ private void UpdateLineRenderer()
    lineRenderer.SetPosition(i, hinges[i].transform.position);
    }

    lineRenderer.SetPosition(lineRenderer.positionCount-1, endPoint.position);
    lineRenderer.SetPosition(lineRenderer.positionCount-1, hinges[hinges.Length-1].transform.position + (-hinges[hinges.Length-1].transform.up * jointDistance));
    }

    private void RebuildLineRenderer()
    @@ -95,25 +122,27 @@ private void RebuildLineRenderer()

    lineRenderer.positionCount = hinges.Length+1;
    lineRenderer.useWorldSpace = true;
    lineRenderer.widthMultiplier = width*2f;
    lineRenderer.widthMultiplier = radius * 2f;

    for (int i = 0; i < hinges.Length; i++)
    {
    lineRenderer.SetPosition(i, hinges[i].transform.position);
    }

    lineRenderer.SetPosition(lineRenderer.positionCount-1, endPoint.position);
    lineRenderer.SetPosition(lineRenderer.positionCount-1, hinges[hinges.Length-1].transform.position + (-hinges[hinges.Length-1].transform.up * jointDistance));
    //lineRenderer.SetPosition(lineRenderer.positionCount-1, endPoint.position);
    }
    }

    #if UNITY_EDITOR
    [CustomEditor(typeof(Rope))]
    [CustomEditor(typeof(RopeGenerator))]
    public class RopeBuilderInspector : Editor
    {
    private Rope script;
    private RopeGenerator script;

    private void OnEnable()
    {
    script = (Rope)target;
    script = (RopeGenerator)target;
    }
    public override void OnInspectorGUI()
    {
  2. staggartcreations created this gist Mar 5, 2021.
    131 changes: 131 additions & 0 deletions Rope.cs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,131 @@
    using UnityEngine;
    #if UNITY_EDITOR
    using UnityEditor;
    #endif

    [RequireComponent(typeof(Rigidbody))]
    public class Rope : MonoBehaviour
    {
    public LineRenderer lineRenderer;
    public Transform endPoint;

    [Range(0.25f, 1f)]
    public float jointDistance = 1f;
    public float width = 0.05f;

    [SerializeField]
    private HingeJoint[] hinges;
    private Rigidbody startRigidBody;
    private Rigidbody endRigidBody;
    private HingeJoint endJoint;

    private void LateUpdate()
    {
    UpdateLineRenderer();
    }

    public void Rebuild()
    {
    if (!endPoint) return;

    if (!startRigidBody) startRigidBody = GetComponent<Rigidbody>();
    startRigidBody.isKinematic = true;

    float length = (transform.position - endPoint.position).magnitude;
    int segmentCount = Mathf.RoundToInt(length / jointDistance);

    if (hinges != null)
    {
    for (int i = 0; i < hinges.Length; i++)
    {
    DestroyImmediate(hinges[i].gameObject);
    }

    hinges = null;
    }
    hinges = new HingeJoint[segmentCount];

    Vector3 direction = (endPoint.position - transform.position).normalized;
    Vector3 localDirection = transform.TransformDirection(direction);

    for (int i = 0; i < hinges.Length; i++)
    {
    GameObject hingeObj = new GameObject("Hinge_" + i);
    hingeObj.transform.up = direction;
    hingeObj.transform.parent = this.transform;
    hingeObj.transform.localPosition = localDirection * (i * jointDistance);

    HingeJoint joint = hingeObj.AddComponent<HingeJoint>();

    CapsuleCollider collider = joint.gameObject.AddComponent<CapsuleCollider>();
    collider.radius = width;
    collider.center = new Vector3(0f, jointDistance * 0.5f, 0f);
    collider.height = jointDistance;

    if (i == 0) joint.connectedBody = startRigidBody;
    if (i > 0) joint.connectedBody = hinges[i - 1].GetComponent<Rigidbody>();

    hinges[i] = joint;
    }

    if (endJoint == null) endJoint = endPoint.GetComponent<HingeJoint>();
    if (endJoint == null) endJoint = endPoint.gameObject.AddComponent<HingeJoint>();
    if (endRigidBody == null) endRigidBody = endPoint.GetComponent<Rigidbody>();

    endJoint.connectedBody = hinges[hinges.Length - 1].GetComponent<Rigidbody>();

    RebuildLineRenderer();
    }

    private void UpdateLineRenderer()
    {
    if (!lineRenderer) return;

    for (int i = 0; i < hinges.Length; i++)
    {
    lineRenderer.SetPosition(i, hinges[i].transform.position);
    }

    lineRenderer.SetPosition(lineRenderer.positionCount-1, endPoint.position);
    }

    private void RebuildLineRenderer()
    {
    if (!lineRenderer) return;

    lineRenderer.positionCount = hinges.Length+1;
    lineRenderer.useWorldSpace = true;
    lineRenderer.widthMultiplier = width*2f;

    for (int i = 0; i < hinges.Length; i++)
    {
    lineRenderer.SetPosition(i, hinges[i].transform.position);
    }

    lineRenderer.SetPosition(lineRenderer.positionCount-1, endPoint.position);
    }
    }
    #if UNITY_EDITOR
    [CustomEditor(typeof(Rope))]
    public class RopeBuilderInspector : Editor
    {
    private Rope script;

    private void OnEnable()
    {
    script = (Rope)target;
    }
    public override void OnInspectorGUI()
    {
    EditorGUI.BeginChangeCheck();

    base.OnInspectorGUI();

    //Can't destroy objects in OnValidate, so do it here
    if (EditorGUI.EndChangeCheck())
    {
    script.Rebuild();
    }
    }
    }
    #endif