aboutsummaryrefslogtreecommitdiffstats
path: root/Assets/Scripts/Core/Rope.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Assets/Scripts/Core/Rope.cs')
-rw-r--r--Assets/Scripts/Core/Rope.cs132
1 files changed, 132 insertions, 0 deletions
diff --git a/Assets/Scripts/Core/Rope.cs b/Assets/Scripts/Core/Rope.cs
new file mode 100644
index 0000000..aff295a
--- /dev/null
+++ b/Assets/Scripts/Core/Rope.cs
@@ -0,0 +1,132 @@
+using System.Collections.Generic;
+using UnityEngine;
+
+public class Rope : MonoBehaviour
+{
+ [SerializeField] protected int constraintIterations = 15;
+ [SerializeField] protected float gravityMultiplier = 1.0f;
+ [SerializeField] protected float lineWidth = 0.2f;
+ [SerializeField] protected float ropeSegmentLength = 0.1f;
+ [SerializeField] protected int segmentCount = 35;
+
+ protected LineRenderer lr;
+ protected DistanceJoint2D dj;
+ protected GameObject player;
+ protected List<RopeSegment> ropeSegments = new List<RopeSegment>();
+ protected Vector3[] ropePositions;
+ protected bool ropeCreated = false;
+
+ // Start is called before the first frame update
+ private void Start()
+ {
+ player = GameObject.FindGameObjectWithTag("Player");
+ dj = GetComponent<DistanceJoint2D>();
+ lr = GetComponent<LineRenderer>();
+ lr.startWidth = lineWidth;
+ lr.endWidth = lineWidth;
+ ropePositions = new Vector3[segmentCount];
+ lr.positionCount = segmentCount;
+ Vector2 ropeLoc = transform.position;
+
+ for (int i = 0; i < segmentCount; i++)
+ {
+ ropeSegments.Add(new RopeSegment(ropeLoc));
+ ropeLoc.y -= ropeSegmentLength;
+ }
+ }
+
+ // Update is called once per frame
+ private void Update()
+ {
+ if (!ropeCreated)
+ {
+ CreateRope();
+ ropeCreated = true;
+ }
+ RenderLine();
+ Simulate();
+ }
+
+ private void RenderLine()
+ {
+ for (int i = 0; i < ropePositions.Length; i++)
+ {
+ ropePositions[i] = ropeSegments[i].posNow;
+ }
+ lr.SetPositions(ropePositions);
+ }
+
+ private void CreateRope()
+ {
+ dj.connectedBody = player.GetComponent<Rigidbody2D>();
+ dj.maxDistanceOnly = true;
+ dj.distance = Vector2.Distance(player.transform.position, transform.position);
+ }
+
+ private void Simulate()
+ {
+ Vector2 gravityForce = new Vector2(0f, -gravityMultiplier);
+
+ for (int i = 0; i < ropeSegments.Count; i++)
+ {
+ RopeSegment segment = ropeSegments[i];
+ Vector2 velocity = segment.posNow - segment.posOld;
+ segment.posOld = segment.posNow;
+ segment.posNow += velocity;
+ segment.posNow += gravityForce * Time.deltaTime;
+ ropeSegments[i] = segment;
+ }
+
+ for (int i = 0; i < constraintIterations; i++)
+ {
+ ApplyContraint();
+ }
+ }
+
+ private void ApplyContraint()
+ {
+ RopeSegment endSegment1 = ropeSegments[0];
+ endSegment1.posNow = transform.position;
+ ropeSegments[0] = endSegment1;
+
+ RopeSegment endSegment2 = ropeSegments[ropeSegments.Count - 1];
+ endSegment2.posNow = player.transform.position;
+ ropeSegments[ropeSegments.Count - 1] = endSegment2;
+
+ for (int i = 0; i < ropeSegments.Count - 1; i++)
+ {
+ RopeSegment segment1 = ropeSegments[i];
+ RopeSegment segment2 = ropeSegments[i + 1];
+
+ float distance = (segment1.posNow - segment2.posNow).magnitude;
+ float error = distance - ropeSegmentLength;
+ Vector2 normalChange = (segment1.posNow - segment2.posNow).normalized;
+ Vector2 change = normalChange * error;
+
+ if (i != 0)
+ {
+ segment1.posNow -= change * 0.5f;
+ ropeSegments[i] = segment1;
+ segment2.posNow += change * 0.5f;
+ ropeSegments[i + 1] = segment2;
+ }
+ else
+ {
+ segment2.posNow += change;
+ ropeSegments[i + 1] = segment2;
+ }
+ }
+ }
+
+ public struct RopeSegment
+ {
+ public Vector2 posNow;
+ public Vector2 posOld;
+
+ public RopeSegment(Vector2 pos)
+ {
+ this.posNow = pos;
+ this.posOld = pos;
+ }
+ }
+}