修改rope脚本

This commit is contained in:
Bob.Song
2025-11-05 15:46:53 +08:00
parent 6ccd2e16bd
commit 3e739facde
10 changed files with 1382 additions and 180 deletions

View File

@@ -36,13 +36,6 @@ namespace NBF
}
}
public struct OnSplitParams
{
public int minParticleIndex;
public int maxParticleIndex;
public Measurements preSplitMeasurements;
}
public struct EditorColors
{
public Color ropeSegments;
@@ -80,9 +73,8 @@ namespace NBF
{
[Tooltip("使用简单线渲染而非完整网格渲染。适用于细绳如鱼线,性能更好。")]
public bool useSimpleLineRenderer;
[Tooltip("简单线渲染的宽度。")]
public float simpleLineWidth;
[Tooltip("简单线渲染的宽度。")] public float simpleLineWidth;
}
[Space] public RenderingSettings rendering = new RenderingSettings()
@@ -91,13 +83,6 @@ namespace NBF
simpleLineWidth = 0.02f
};
// public CustomMeshSettings customMesh = new CustomMeshSettings()
// {
// mesh = null,
// rotation = 90.0f,
// scale = Vector3.one,
// stretch = false,
// };
[Tooltip("用于初始放置绳子在世界中的生成点。目前,连续的生成点对被视为线性线段。")] [DisableInPlayMode]
public List<float3> spawnPoints = new List<float3>();
@@ -157,7 +142,7 @@ namespace NBF
solverIterations = 2,
};
[System.Serializable]
public struct CollisionSettings
{
@@ -218,7 +203,7 @@ namespace NBF
protected bool initialized;
protected bool computingSimulationFrame;
protected bool simulationDisabledPrevFrame;
protected bool wasSplit;
protected float timeSinceFixedUpdate;
protected JobHandle simulationFrameHandle;
@@ -380,7 +365,6 @@ namespace NBF
/// </summary>
/// <param name="particleIndex">模拟粒子的索引</param>
/// <param name="position">世界空间中的期望位置</param>
/// <param name="maxImpulseStrength">可使用的最大允许冲量强度。如果为零,则不应用限制。</param>
public void SetPositionAt(int particleIndex, float3 position)
{
if (!Initialize() || particleIndex < 0 || particleIndex >= positions.Length)
@@ -606,91 +590,10 @@ namespace NBF
return positions.GetLengthOfCurve(isLoop);
}
protected Rope InstantiateSplitRope(int minIdx, int maxIdx, string identifier)
{
var count = maxIdx - minIdx + 1;
if (minIdx < 0 || maxIdx > positions.Length - 1 || count < 2)
{
return null;
}
// 创建两个大致放置在新绳子位置的生成点(这将创建漂亮的双切线)
var targetLength = _measurements.realCurveLength * ((float)count / _measurements.particleCount);
var point0 = positions[minIdx];
var point1 = positions[maxIdx];
var delta = point1 - point0;
var simplifiedLength = math.length(delta);
point1 += math.normalizesafe(delta) * (targetLength - simplifiedLength);
var rope = Instantiate(gameObject, Vector3.zero, Quaternion.identity).GetComponent<Rope>();
rope.name = identifier;
rope.isLoop = false;
rope.spawnPoints = new List<float3>()
{
point0,
point1,
};
if (rope.Initialize())
{
// 现在更新模拟粒子以完全匹配原始绳子
for (int i = 0; i < rope.positions.Length; i++)
{
var sourceIdx = minIdx + i;
if (sourceIdx >= positions.Length)
{
break;
}
rope.positions[i] = positions[sourceIdx];
rope.prevPositions[i] = prevPositions[sourceIdx];
}
// 使新绳子与旧绳子大小相同
rope._measurements.realCurveLength = rope.GetCurrentLength();
rope._measurements.particleSpacing = _measurements.particleSpacing;
var param = new OnSplitParams()
{
minParticleIndex = minIdx,
maxParticleIndex = maxIdx,
preSplitMeasurements = _measurements,
};
rope.SendMessage("OnRopeSplit", param, SendMessageOptions.DontRequireReceiver);
}
return rope;
}
/// <summary>
/// 在特定模拟粒子处分割绳子并返回新实例化游戏对象的绳子组件。确保
/// 提供的数组正好有2个槽位。将向每个新创建的绳子发送Unity消息'OnRopeSplit(Rope.OnSplitParams)'。
/// 计算真实曲线
/// </summary>
/// <param name="particleIndex">分割点的模拟粒子索引</param>
/// <param name="outNewRopes">如果不为null一个正好有2个元素的数组其中将返回新的绳子游戏对象</param>
public void SplitAt(int particleIndex, Rope[] outNewRopes = null)
{
if (!Initialize() || (outNewRopes != null && outNewRopes.Length != 2) || wasSplit)
{
return;
}
wasSplit = true;
var fst = InstantiateSplitRope(0, particleIndex, name + "_split0");
var snd = InstantiateSplitRope(particleIndex + 1, positions.Length - 1, name + "_split1");
Destroy(gameObject);
if (outNewRopes != null)
{
outNewRopes[0] = fst;
outNewRopes[1] = snd;
}
}
protected void ComputeRealCurve(Allocator allocator, out Measurements measurements,
out NativeArray<float3> points)
{
@@ -800,7 +703,7 @@ namespace NBF
{
lineRenderer = gameObject.AddComponent<LineRenderer>();
}
lineRenderer.useWorldSpace = true;
lineRenderer.loop = isLoop;
lineRenderer.widthMultiplier = rendering.simpleLineWidth;
@@ -809,7 +712,7 @@ namespace NBF
lineRenderer.receiveShadows = false;
lineRenderer.alignment = LineAlignment.View;
}
// 状态
ComputeRealCurve(Allocator.Persistent, out _measurements, out positions);
@@ -957,6 +860,9 @@ namespace NBF
protected Collider[] collisionQueryBuffer = new Collider[MaxCollisionPlanesPerParticle];
/// <summary>
/// 更新碰撞平面
/// </summary>
public void UpdateCollisionPlanes()
{
if (!collisions.enabled)
@@ -1059,6 +965,9 @@ namespace NBF
Profiler.EndSample();
}
/// <summary>
/// 准备刚体连接
/// </summary>
protected void PrepareRigidbodyConnections()
{
Profiler.BeginSample(nameof(PrepareRigidbodyConnections));
@@ -1116,6 +1025,9 @@ namespace NBF
Profiler.EndSample();
}
/// <summary>
/// 应用刚体反馈
/// </summary>
protected void ApplyRigidbodyFeedback()
{
Profiler.BeginSample(nameof(ApplyRigidbodyFeedback));
@@ -1179,6 +1091,9 @@ namespace NBF
Profiler.EndSample();
}
/// <summary>
/// 安排下一个模拟帧
/// </summary>
protected void ScheduleNextSimulationFrame()
{
Profiler.BeginSample(nameof(ScheduleNextSimulationFrame));
@@ -1240,6 +1155,9 @@ namespace NBF
Profiler.EndSample();
}
/// <summary>
/// 时间表插值
/// </summary>
protected void ScheduleInterpolation()
{
if (interpolation == RopeInterpolation.None)
@@ -1302,6 +1220,9 @@ namespace NBF
Profiler.EndSample();
}
/// <summary>
/// 完成先前的模拟帧
/// </summary>
protected void CompletePreviousSimulationFrame()
{
if (!computingSimulationFrame)
@@ -1317,46 +1238,6 @@ namespace NBF
Profiler.EndSample();
}
protected static void FillMeshFrames(ref NativeArray<float3> positions, ref NativeArray<float3> bitangents,
Matrix4x4[] meshFrames, float spacing, bool isLoop, float rotationOffset, Vector3 scaleMultiplier,
bool stretch)
{
var scale = scaleMultiplier * 0.5f * spacing;
if (stretch)
{
scale.z = scaleMultiplier.z * 0.5f;
}
var currentRotation = 0.0f;
for (var i = 0; i < positions.Length; i++) // 在这里使用positions数组希望编译器能优化掉边界检查...
{
var tangent = Vector3.zero;
if (isLoop)
{
tangent = positions[(i + 1) % positions.Length] - positions[i];
}
else
{
tangent = i < positions.Length - 1
? positions[i + 1] - positions[i]
: positions[i] - positions[i - 1];
}
var frameScale = stretch
? new Vector3(scale.x, scale.y, scale.z * tangent.magnitude)
: scale;
tangent.Normalize();
var frameRotation = Quaternion.LookRotation(tangent, bitangents[i]) *
Quaternion.Euler(0.0f, 0.0f, currentRotation);
currentRotation += rotationOffset;
customMeshFrames[i] = Matrix4x4.TRS(positions[i], frameRotation, frameScale);
}
}
protected static Matrix4x4[] customMeshFrames;
protected void SubmitToRenderer()
{
if (material == null)
@@ -1502,6 +1383,8 @@ namespace NBF
}
#endif
#region Jobs
[BurstCompile]
private struct SimulateJob : IJob
{
@@ -1807,5 +1690,7 @@ namespace NBF
}
}
}
#endregion
}
}