Skip to content

Instantly share code, notes, and snippets.

@staggartcreations
Last active March 6, 2024 12:58
Show Gist options
  • Save staggartcreations/39571498ae1f6c760db6a34d6e1b28a5 to your computer and use it in GitHub Desktop.
Save staggartcreations/39571498ae1f6c760db6a34d6e1b28a5 to your computer and use it in GitHub Desktop.
HingeJoint-based rope building component
using System;
using UnityEngine;
using UnityEngine.Serialization;
#if UNITY_EDITOR
using UnityEditor;
#endif
public class RopeGenerator : MonoBehaviour
{
public Rigidbody attachementBody;
[Space]
[Header("Generator")]
[Range(0.25f, 1f)]
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;
[Header("Physics")]
public float mass = 100;
public float drag = 1;
[Space]
[SerializeField] [HideInInspector]
private HingeJoint[] hinges;
private void LateUpdate()
{
UpdateLineRenderer();
}
private void Start()
{
//Unparent object so that it follows the attachement point freely
this.transform.parent = null;
}
public void Rebuild()
{
if (!attachementBody) attachementBody = GetComponent<Rigidbody>();
attachementBody.isKinematic = true;
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 = 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 = 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 = radius;
collider.center = new Vector3(0f, jointDistance * 0.5f, 0f);
collider.height = jointDistance;
//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>();
//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, hinges[hinges.Length-1].transform.position + (-hinges[hinges.Length-1].transform.up * jointDistance));
}
private void RebuildLineRenderer()
{
if (!lineRenderer) return;
lineRenderer.positionCount = hinges.Length+1;
lineRenderer.useWorldSpace = true;
lineRenderer.widthMultiplier = radius * 2f;
for (int i = 0; i < hinges.Length; i++)
{
lineRenderer.SetPosition(i, hinges[i].transform.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(RopeGenerator))]
public class RopeBuilderInspector : Editor
{
private RopeGenerator script;
private void OnEnable()
{
script = (RopeGenerator)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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment