diff --git a/Assets/Dreamteck/Splines/Components/TubeGenerator.cs b/Assets/Dreamteck/Splines/Components/TubeGenerator.cs index 4e12fc92..e41f2fbc 100644 --- a/Assets/Dreamteck/Splines/Components/TubeGenerator.cs +++ b/Assets/Dreamteck/Splines/Components/TubeGenerator.cs @@ -288,7 +288,7 @@ namespace Dreamteck.Splines float anglePercent = (float)lon / sides; int index = bodyVertexCount + lon + (lat-1) * (sides + 1); Quaternion rot = Quaternion.AngleAxis(_revolve * anglePercent + rotation + 180f, -Vector3.forward) * Quaternion.AngleAxis(latAngle, Vector3.up); - _tsMesh.vertices[index] = center + lookRot * rot * -Vector3.right * (size * 0.5f * evalResult.size); + _tsMesh.vertices[index] = center + lookRot * rot * -Vector3.right * (size * 0.5f * resultSize); _tsMesh.colors[index] = vertexColor; _tsMesh.normals[index] = (_tsMesh.vertices[index] - center).normalized; float baseV = startV + capLengthPercent * latitudePercent; @@ -348,7 +348,7 @@ namespace Dreamteck.Splines float anglePercent = (float)lon / sides; int index = bodyVertexCount + capVertexCount + lon + (lat - 1) * (sides + 1); Quaternion rot = Quaternion.AngleAxis(_revolve * anglePercent + rotation + 180f, Vector3.forward) * Quaternion.AngleAxis(latAngle, -Vector3.up); - _tsMesh.vertices[index] = center + lookRot * rot * Vector3.right * size * 0.5f * evalResult.size; + _tsMesh.vertices[index] = center + lookRot * rot * Vector3.right * size * 0.5f * resultSize; _tsMesh.normals[index] = (_tsMesh.vertices[index] - center).normalized; _tsMesh.colors[index] = vertexColor; float baseV = startV + capLengthPercent * latitudePercent; diff --git a/Assets/ThemeBundles/DepartureToMultiverse/Scripts/RuntimeCore/Note/NoteVisual/DTMNoteVisualHold.cs b/Assets/ThemeBundles/DepartureToMultiverse/Scripts/RuntimeCore/Note/NoteVisual/DTMNoteVisualHold.cs index 9eadbd35..2aa716c7 100644 --- a/Assets/ThemeBundles/DepartureToMultiverse/Scripts/RuntimeCore/Note/NoteVisual/DTMNoteVisualHold.cs +++ b/Assets/ThemeBundles/DepartureToMultiverse/Scripts/RuntimeCore/Note/NoteVisual/DTMNoteVisualHold.cs @@ -59,15 +59,20 @@ namespace Ichni.RhythmGame.ThemeBundles.DepartureToMultiverse meshGenerator.spline = hold.track.trackPathSubmodule.path; tailPoint.spline = hold.track.trackPathSubmodule.path; tailPoint.autoUpdate = false; // 由调度器 Phase 6 通过 RebuildImmediate 手动刷新 + ConfigurePathNodeScaleIsolation(); - float startPercent = GetTrackPercent(hold.exactJudgeTime); - float endPercent = GetTrackPercent(hold.holdEndTime); + startPercent = GetTrackPercent(hold.exactJudgeTime); + endPercent = GetTrackPercent(hold.holdEndTime); + ApplyHoldPositionOffset(GetCurrentPositionOffset()); hold.trackPositioner.SetPercent(startPercent); + ApplyPositionerWorldOffset(hold.trackPositioner, startPercent); meshGenerator.SetClipRange(startPercent, endPercent); ApplyHoldThicknessFromScale(); headPoint.SetPercent(startPercent); + ApplyPositionerWorldOffset(headPoint, startPercent); tailPoint.SetPercent(endPercent); + ApplyPositionerWorldOffset(tailPoint, endPercent); if (isFirstGenerated) { @@ -94,15 +99,15 @@ namespace Ichni.RhythmGame.ThemeBundles.DepartureToMultiverse { materialPropertyBlock.SetFloat("_MainAlpha", 1f); rend.SetPropertyBlock(materialPropertyBlock); - note.track.trackPathSubmodule.path.RebuildImmediate(); + note?.track?.trackPathSubmodule?.path?.RebuildImmediate(); } } - foreach (EffectBase effect in effectSubmodule.effectCollection["Generate"]) + foreach (EffectBase effect in GetEffects("Generate")) { effect.Recover(); } - foreach (EffectBase effect in effectSubmodule.effectCollection["Holding"]) + foreach (EffectBase effect in GetEffects("Holding")) { effect.Recover(); } @@ -110,7 +115,7 @@ namespace Ichni.RhythmGame.ThemeBundles.DepartureToMultiverse public override void Refresh() { base.Refresh(); - foreach (EffectBase effect in effectSubmodule.effectCollection["Generate"]) + foreach (EffectBase effect in GetEffects("Generate")) { if (effect.nowEffectState == EffectBase.EffectState.Middle) { @@ -118,11 +123,7 @@ namespace Ichni.RhythmGame.ThemeBundles.DepartureToMultiverse } } - Vector2 posOffset = new Vector2(transformSubmodule.currentPosition.x, transformSubmodule.currentPosition.y); - hold.trackPositioner.motion.offset = posOffset; - meshGenerator.offset = posOffset; - headPoint.motion.offset = posOffset; - tailPoint.motion.offset = posOffset; + ApplyHoldPositionOffset(GetCurrentPositionOffset()); ApplyHoldThicknessFromScale(); } #endregion @@ -140,14 +141,84 @@ namespace Ichni.RhythmGame.ThemeBundles.DepartureToMultiverse #region [位移更新逻辑] Positional Updates private float startPercent, endPercent; + private Vector2 positionOffset; + private SplineSample offsetSample = new(); public float holdThickness => Mathf.Max(0f, transformSubmodule?.currentScale.x ?? 1f); public void ApplyHoldThicknessFromScale() { + if (meshGenerator == null) return; meshGenerator.size = holdThickness; } + private void ConfigurePathNodeScaleIsolation() + { + if (meshGenerator != null) meshGenerator.useSplineSize = false; + DisableSplineSizeScale(hold.trackPositioner); + DisableSplineSizeScale(headPoint); + DisableSplineSizeScale(tailPoint); + } + + private void DisableSplineSizeScale(SplinePositioner positioner) + { + if (positioner == null) return; + positioner.motion.applyScaleX = false; + positioner.motion.applyScaleY = false; + positioner.motion.applyScaleZ = false; + } + + private Vector2 GetCurrentPositionOffset() + { + if (transformSubmodule == null) return Vector2.zero; + return new Vector2(transformSubmodule.currentPosition.x, transformSubmodule.currentPosition.y); + } + + private List GetEffects(string key) + { + if (effectSubmodule?.effectCollection != null && + effectSubmodule.effectCollection.TryGetValue(key, out List effects)) + { + return effects; + } + + return new List(); + } + + private bool IsGenerateEffectMiddle() + { + return GetEffects("Generate").Any(e => e.nowEffectState == EffectBase.EffectState.Middle); + } + + private void ApplyHoldPositionOffset(Vector2 offset) + { + positionOffset = offset; + if (meshGenerator != null) meshGenerator.offset = offset; + ClearSplineSizeScaledOffset(hold.trackPositioner); + ClearSplineSizeScaledOffset(headPoint); + ClearSplineSizeScaledOffset(tailPoint); + } + + private void ClearSplineSizeScaledOffset(SplinePositioner positioner) + { + if (positioner == null) return; + positioner.motion.offset = Vector2.zero; + } + + private void ApplyPositionerWorldOffset(SplinePositioner positioner, float percent) + { + if (positioner == null || positioner.targetObject == null || positionOffset == Vector2.zero) return; + if (positioner.sampleCount == 0) + { + return; + } + + positioner.Evaluate(percent, ref offsetSample); + positioner.targetObject.transform.position += + offsetSample.right * positionOffset.x + + offsetSample.up * positionOffset.y; + } + public void UpdateTransform(bool refreshAll = true) { if (transformSubmodule == null) return; @@ -177,6 +248,7 @@ namespace Ichni.RhythmGame.ThemeBundles.DepartureToMultiverse { transformSubmodule.currentPosition = transformSubmodule.originalPosition + transformSubmodule.positionOffset; transform.localPosition = transformSubmodule.currentPosition; + ApplyHoldPositionOffset(GetCurrentPositionOffset()); transformSubmodule.positionDirtyMark = false; willRefresh = true; transformSubmodule.positionOffset = Vector3.zero; @@ -214,7 +286,7 @@ namespace Ichni.RhythmGame.ThemeBundles.DepartureToMultiverse public void UpdateHoldInMovableTrack() { - if (effectSubmodule.effectCollection["Generate"].Any(e => e.nowEffectState == EffectBase.EffectState.Middle)) + if (IsGenerateEffectMiddle()) { return; } @@ -239,7 +311,7 @@ namespace Ichni.RhythmGame.ThemeBundles.DepartureToMultiverse public void UpdateHoldInStaticTrack(float songTime) { - if (effectSubmodule.effectCollection["Generate"].Any(e => e.nowEffectState == EffectBase.EffectState.Middle)) + if (IsGenerateEffectMiddle()) { return; } @@ -263,13 +335,18 @@ namespace Ichni.RhythmGame.ThemeBundles.DepartureToMultiverse public void SetHoldPercentRange(float startPercent, float endPercent, bool rebuildImmediately) { + this.startPercent = startPercent; + this.endPercent = endPercent; + if (rebuildImmediately) { // autoUpdate=false 的 SplineUser 不会自行刷新,必须手动 RebuildImmediate。 hold.trackPositioner.RebuildImmediate(); } + ApplyHoldPositionOffset(positionOffset); hold.trackPositioner.SetPercent(startPercent); + ApplyPositionerWorldOffset(hold.trackPositioner, startPercent); meshGenerator.SetClipRange(startPercent, endPercent); ApplyHoldThicknessFromScale(); @@ -280,6 +357,7 @@ namespace Ichni.RhythmGame.ThemeBundles.DepartureToMultiverse } headPoint.SetPercent(startPercent); + ApplyPositionerWorldOffset(headPoint, startPercent); if (rebuildImmediately) { @@ -287,6 +365,7 @@ namespace Ichni.RhythmGame.ThemeBundles.DepartureToMultiverse } tailPoint.SetPercent(endPercent); + ApplyPositionerWorldOffset(tailPoint, endPercent); } public void SetTransformObserver() @@ -303,11 +382,7 @@ namespace Ichni.RhythmGame.ThemeBundles.DepartureToMultiverse if (transformSubmodule.positionDirtyMark) { transformSubmodule.currentPosition = transformSubmodule.originalPosition + transformSubmodule.positionOffset; - Vector2 posOffset = new Vector2(transformSubmodule.currentPosition.x, transformSubmodule.currentPosition.y); - hold.trackPositioner.motion.offset = posOffset; - meshGenerator.offset = posOffset; - headPoint.motion.offset = posOffset; - tailPoint.motion.offset = posOffset; + ApplyHoldPositionOffset(GetCurrentPositionOffset()); transformSubmodule.positionDirtyMark = false; willRefresh = true; transformSubmodule.positionOffset = Vector3.zero;