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 ropeSegments = new List(); protected Vector3[] ropePositions; protected bool ropeCreated = false; // Start is called before the first frame update protected void Start() { player = GameObject.FindGameObjectWithTag("Player"); dj = GetComponent(); lr = GetComponent(); 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 protected void Update() { if (!ropeCreated) { CreateRope(); ropeCreated = true; } else { } RenderLine(); Simulate(); } protected void RenderLine() { for (int i = 0; i < ropePositions.Length; i++) { ropePositions[i] = ropeSegments[i].posNow; } lr.SetPositions(ropePositions); } protected void CreateRope() { dj.connectedBody = player.GetComponent(); dj.maxDistanceOnly = true; dj.distance = Vector2.Distance(player.transform.position, transform.position); } protected 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(); } } protected 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; } } }