using System.Collections.Generic; using UnityEngine; using DG.Tweening; [RequireComponent(typeof(LineRenderer))] public class PhysicLineSegment : MonoBehaviour { public float segmentSpacing = 0.1f; public int k = 30; private Vector3 start; private Vector3 end; public List particles = new List(); private List sticks = new List(); [HideInInspector] public LineRenderer lineRenderer; private int segmentCount; public float gravity = -9.8f; private float originalLength; private float targetLength; public void Initialize(Vector3 start, Vector3 end) { particles.Clear(); sticks.Clear(); if (lineRenderer != null) { lineRenderer.positionCount = 0; } this.start = start; this.end = end; originalLength = Vector3.Distance(start, end); targetLength = originalLength; // 初始化目标长度 segmentCount = Mathf.RoundToInt(originalLength / segmentSpacing); lineRenderer = GetComponent(); // Initialize particles for (int i = 0; i < segmentCount; i++) { var particle = new VerletParticle(Vector3.Lerp(start, end, i / (float)segmentCount)); particles.Add(particle); } // Initialize sticks for (int i = 0; i < segmentCount - 1; i++) { sticks.Add(new VerletStick(particles[i], particles[i + 1], segmentSpacing)); } // Lock the first particle particles[0].isLocked = true; lineRenderer.positionCount = segmentCount; } void FixedUpdate() { UpdateLine(); for (int i = 0; i < segmentCount; i++) { if (lineRenderer != null) { lineRenderer.SetPosition(i, particles[i].position); } } } void UpdateLine() { // Apply gravity to particles for (int i = 1; i < particles.Count; i++) { particles[i].ApplyForce(Vector3.up * gravity * Time.deltaTime); particles[i].UpdatePosition(); } // Update sticks for (int ik = 0; ik < k; ik++) { foreach (var stick in sticks) { stick.UpdateStick(); } } } public void SetTargetLength(float newLength, float duration) { DOTween.To(() => targetLength, x => targetLength = x, newLength, duration); } public void UpdateLineLength(float newLength) { // 计算新的段数 int newSegmentCount = Mathf.RoundToInt(newLength / segmentSpacing); // 如果新的段数大于当前段数,增加粒子 if (newSegmentCount > segmentCount) { for (int i = segmentCount; i < newSegmentCount; i++) { var particle = new VerletParticle(Vector3.Lerp(start, end, i / (float)newSegmentCount)); particles.Add(particle); if (i > 0) { sticks.Add(new VerletStick(particles[i - 1], particles[i], segmentSpacing)); } } } // 如果新的段数小于当前段数,减少粒子 else if (newSegmentCount < segmentCount) { particles.RemoveRange(newSegmentCount, segmentCount - newSegmentCount); sticks.RemoveRange(newSegmentCount - 1, segmentCount - newSegmentCount); } // 更新段数 segmentCount = newSegmentCount; if(lineRenderer!=null) { lineRenderer.positionCount = segmentCount; } // 更新粒子位置 for (int i = 0; i < segmentCount; i++) { particles[i].position = Vector3.Lerp(start, end, i / (float)segmentCount); } } public void UpdatePlug(Transform plug) { if (plug != null && particles.Count > 1) { Vector3 plugPosition = particles[particles.Count - 1].position; float plugLength = plug.GetComponent().bounds.size.y; Vector3 direction = particles[particles.Count - 1].position - particles[particles.Count - 2].position; float angle = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg; plug.rotation = Quaternion.Euler(0, 0, angle - 90f); plug.position = plugPosition + direction.normalized * (plugLength / 2); } } public void UpdateEndPoint(Transform transform) { particles[particles.Count - 1].isLocked = true; particles[particles.Count - 1].position = transform.position; } }