绳子绑定
This commit is contained in:
@@ -3,8 +3,10 @@ using UnityEngine;
|
||||
[RequireComponent(typeof(LineRenderer))]
|
||||
public class Rope : MonoBehaviour
|
||||
{
|
||||
[Header("Demo Parameters")] [SerializeField, Min(0)]
|
||||
float mouseOffset = 10f;
|
||||
[Header("Attachment Points")] [SerializeField]
|
||||
public Transform startAttachment; // 绳子起点绑定的Transform
|
||||
|
||||
[SerializeField] public Transform endAttachment; // 绳子终点绑定的Transform
|
||||
|
||||
[Header("Verlet Parameters")] [SerializeField]
|
||||
float nodeDistance = 0.35f;
|
||||
@@ -22,12 +24,7 @@ public class Rope : MonoBehaviour
|
||||
float ropeWidth = 0.1f;
|
||||
|
||||
// 私有变量
|
||||
Camera cam;
|
||||
Vector3 gravity;
|
||||
Vector3 startLock;
|
||||
Vector3 endLock;
|
||||
bool isStartLocked = false;
|
||||
bool isEndLocked = false;
|
||||
|
||||
// 数组和缓存
|
||||
Vector3[] currentNodePositions;
|
||||
@@ -37,13 +34,12 @@ public class Rope : MonoBehaviour
|
||||
GameObject nodeTester;
|
||||
SphereCollider nodeCollider;
|
||||
int totalNodes;
|
||||
float lastTotalLength; // 用于检测长度变化
|
||||
float lastTotalLength;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
// 获取组件引用
|
||||
lineRenderer = GetComponent<LineRenderer>();
|
||||
cam = Camera.main;
|
||||
gravity = new Vector3(0, -gravityStrength, 0);
|
||||
|
||||
// 初始化节点测试器
|
||||
@@ -62,8 +58,7 @@ public class Rope : MonoBehaviour
|
||||
// 计算节点数量
|
||||
totalNodes = Mathf.FloorToInt(totalLength / nodeDistance) + 1;
|
||||
float remainingLength = totalLength % nodeDistance;
|
||||
|
||||
// 如果剩余长度大于0,增加一个节点
|
||||
|
||||
if (remainingLength > 0 && totalLength > nodeDistance)
|
||||
{
|
||||
totalNodes++;
|
||||
@@ -75,18 +70,13 @@ public class Rope : MonoBehaviour
|
||||
colliderHitBuffer = new Collider[colliderBufferSize];
|
||||
|
||||
// 初始化节点位置
|
||||
Vector3 startPos = transform.position;
|
||||
Vector3 startPos = startAttachment != null ? startAttachment.position : transform.position;
|
||||
for (int i = 0; i < totalNodes; i++)
|
||||
{
|
||||
// 如果是最后一个节点且有剩余长度,使用剩余长度
|
||||
float distance = (i == totalNodes - 1 && remainingLength > 0) ? remainingLength : nodeDistance;
|
||||
|
||||
// 如果数组已有数据,保持现有位置,否则初始化新位置
|
||||
if (currentNodePositions[i] == null)
|
||||
{
|
||||
currentNodePositions[i] = startPos;
|
||||
previousNodePositions[i] = startPos;
|
||||
}
|
||||
|
||||
currentNodePositions[i] = startPos;
|
||||
previousNodePositions[i] = startPos;
|
||||
startPos.y -= distance;
|
||||
}
|
||||
|
||||
@@ -105,55 +95,29 @@ public class Rope : MonoBehaviour
|
||||
lastTotalLength = totalLength;
|
||||
}
|
||||
|
||||
// 处理鼠标输入
|
||||
if (Input.GetMouseButtonDown(0))
|
||||
{
|
||||
if (!isStartLocked)
|
||||
{
|
||||
isStartLocked = true;
|
||||
startLock = GetMouseWorldPosition();
|
||||
}
|
||||
else if (!isEndLocked)
|
||||
{
|
||||
isEndLocked = true;
|
||||
endLock = GetMouseWorldPosition();
|
||||
}
|
||||
}
|
||||
else if (!isStartLocked)
|
||||
{
|
||||
startLock = GetMouseWorldPosition();
|
||||
}
|
||||
else if (isStartLocked && !isEndLocked)
|
||||
{
|
||||
endLock = GetMouseWorldPosition();
|
||||
}
|
||||
|
||||
DrawRope();
|
||||
}
|
||||
|
||||
void AdjustRopeLength()
|
||||
{
|
||||
// 保存旧位置
|
||||
Vector3[] oldPositions = (Vector3[])currentNodePositions.Clone();
|
||||
Vector3[] oldPrevPositions = (Vector3[])previousNodePositions.Clone();
|
||||
|
||||
// 重新初始化绳索
|
||||
InitializeRope();
|
||||
|
||||
// 尽可能保留旧位置数据
|
||||
int copyLength = Mathf.Min(oldPositions.Length, currentNodePositions.Length);
|
||||
System.Array.Copy(oldPositions, currentNodePositions, copyLength);
|
||||
System.Array.Copy(oldPrevPositions, previousNodePositions, copyLength);
|
||||
|
||||
// 如果长度增加,初始化新增节点的位置
|
||||
if (currentNodePositions.Length > oldPositions.Length)
|
||||
{
|
||||
Vector3 lastPos = oldPositions[oldPositions.Length - 1];
|
||||
for (int i = oldPositions.Length; i < currentNodePositions.Length; i++)
|
||||
{
|
||||
float distance = (i == currentNodePositions.Length - 1 && (totalLength % nodeDistance) > 0) ?
|
||||
(totalLength % nodeDistance) : nodeDistance;
|
||||
|
||||
float distance = (i == currentNodePositions.Length - 1 && (totalLength % nodeDistance) > 0)
|
||||
? (totalLength % nodeDistance)
|
||||
: nodeDistance;
|
||||
|
||||
lastPos.y -= distance;
|
||||
currentNodePositions[i] = lastPos;
|
||||
previousNodePositions[i] = lastPos;
|
||||
@@ -169,7 +133,6 @@ public class Rope : MonoBehaviour
|
||||
{
|
||||
ApplyConstraint();
|
||||
|
||||
// 减少碰撞检测频率
|
||||
if (i % (iterateCollisionsEvery + 1) == 0)
|
||||
{
|
||||
AdjustCollisions();
|
||||
@@ -177,17 +140,11 @@ public class Rope : MonoBehaviour
|
||||
}
|
||||
}
|
||||
|
||||
Vector3 GetMouseWorldPosition()
|
||||
{
|
||||
return cam.ScreenToWorldPoint(Input.mousePosition + new Vector3(0, 0, mouseOffset));
|
||||
}
|
||||
|
||||
void Simulate()
|
||||
{
|
||||
float fixedDt = Time.fixedDeltaTime;
|
||||
for (int i = 0; i < totalNodes; i++)
|
||||
{
|
||||
// 计算并应用速度
|
||||
Vector3 velocity = (currentNodePositions[i] - previousNodePositions[i]) * velocityDampen;
|
||||
previousNodePositions[i] = currentNodePositions[i];
|
||||
currentNodePositions[i] += velocity + gravity * fixedDt;
|
||||
@@ -196,14 +153,18 @@ public class Rope : MonoBehaviour
|
||||
|
||||
void ApplyConstraint()
|
||||
{
|
||||
// 锁定端点
|
||||
currentNodePositions[0] = startLock;
|
||||
if (isStartLocked && isEndLocked)
|
||||
// 绑定到起点Transform
|
||||
if (startAttachment != null)
|
||||
{
|
||||
currentNodePositions[totalNodes - 1] = endLock;
|
||||
currentNodePositions[0] = startAttachment.position;
|
||||
}
|
||||
|
||||
// 绑定到终点Transform
|
||||
if (endAttachment != null)
|
||||
{
|
||||
currentNodePositions[totalNodes - 1] = endAttachment.position;
|
||||
}
|
||||
|
||||
// 预计算所有常用值
|
||||
float halfStiffness = 0.5f * stiffness;
|
||||
int nodeCountMinusOne = totalNodes - 1;
|
||||
|
||||
@@ -213,14 +174,13 @@ public class Rope : MonoBehaviour
|
||||
Vector3 node2 = currentNodePositions[i + 1];
|
||||
Vector3 diff = node1 - node2;
|
||||
|
||||
// 计算期望的距离 - 如果是最后一个段且有剩余长度,使用剩余长度
|
||||
float desiredDistance = (i == nodeCountMinusOne - 1 && (totalLength % nodeDistance) > 0) ?
|
||||
(totalLength % nodeDistance) : nodeDistance;
|
||||
|
||||
float desiredDistance = (i == nodeCountMinusOne - 1 && (totalLength % nodeDistance) > 0)
|
||||
? (totalLength % nodeDistance)
|
||||
: nodeDistance;
|
||||
|
||||
float sqrDesiredDistance = desiredDistance * desiredDistance;
|
||||
float sqrDistance = diff.x * diff.x + diff.y * diff.y + diff.z * diff.z;
|
||||
|
||||
// 只有当距离差异超过一定阈值时才调整
|
||||
if (Mathf.Abs(sqrDistance - sqrDesiredDistance) > 0.001f)
|
||||
{
|
||||
float distance = Mathf.Sqrt(sqrDistance);
|
||||
@@ -276,4 +236,11 @@ public class Rope : MonoBehaviour
|
||||
Destroy(nodeTester);
|
||||
}
|
||||
}
|
||||
|
||||
// 公开方法用于动态设置绑定点
|
||||
public void SetAttachments(Transform start, Transform end)
|
||||
{
|
||||
startAttachment = start;
|
||||
endAttachment = end;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user