fix(huoshan): 优化语言粒子布局与状态重置

This commit is contained in:
2026-07-15 19:37:37 +08:00
parent 7ace1f255a
commit 1f931e987f
3 changed files with 145 additions and 46 deletions
+7 -7
View File
@@ -9259,9 +9259,9 @@ MonoBehaviour:
_ambientNoiseScale: 320
_ambientNoiseBrightness: 0.55
_calmFieldPadding: {x: 0.55, y: 0.4}
_calmFieldFeather: 0.45
_calmFieldResidualIntensity: 0.04
_calmFieldBoundaryWarp: 0.025
_calmFieldFeather: 0.85
_calmFieldResidualIntensity: 0.08
_calmFieldBoundaryWarp: 0.05
_calmFieldTransitionDuration: 0.45
--- !u!1 &751535848
GameObject:
@@ -15057,7 +15057,7 @@ MonoBehaviour:
defaultTargetSentence: "\u8FD9\u662F\u4E00\u4E2A\u6D4B\u8BD5\u793A\u4F8B"
spriteRenderer: {fileID: 2468058580162010626}
glitchController: {fileID: 741515695}
ambientNoiseDensity: 0.06
ambientNoiseDensity: 0
ambientNoiseScale: 360
ambientNoiseBrightness: 0.5
--- !u!114 &2138889541
@@ -17270,13 +17270,13 @@ MonoBehaviour:
shakeSpeed: 10
changeInterval: 0.28
floatAmplitude: 0.02
glitchBaselineMax: 0.08
glitchBaselineMax: 0
driftBias: 0.1
- shakeIntensity: 0.05
shakeSpeed: 12
changeInterval: 0.18
floatAmplitude: 0.028
glitchBaselineMax: 0.15
glitchBaselineMax: 0
driftBias: 0.15
targetConnectionThickness: 0.02
nonTargetConnectionThickness: 0.012
@@ -17310,7 +17310,7 @@ MonoBehaviour:
completionBlastForce: 3.5
completionBlastAlphaRatio: 0.35
completionCalmDelay: 0.55
completionGlitchPulsePeak: 0.25
completionGlitchPulsePeak: 0
confirmButtonFadeDuration: 0.35
confirmButtonRiseOffset: 0.35
panelStartAtEntranceProgress: 0.6
@@ -34,7 +34,7 @@ namespace AibisDream
[Header("常驻细密噪点(不随 glitch 强度消失,营造老屏幕底噪)")]
[Tooltip("常驻噪点密度,0 = 关闭(恢复旧行为:LOG1 无噪点)")]
[SerializeField, Range(0f, 0.3f)] private float ambientNoiseDensity = 0.06f;
[SerializeField, Range(0f, 0.3f)] private float ambientNoiseDensity = 0f;
[Tooltip("噪点细密程度,越大颗粒越细(glitch 主噪点默认 80")]
[SerializeField, Range(80f, 800f)] private float ambientNoiseScale = 360f;
[Tooltip("常驻噪点亮度(低于 glitch 主噪点,保持底噪感)")]
@@ -126,6 +126,7 @@ namespace AibisDream
// 新一轮重置干扰联动(解除 yarn 覆盖、基线归零)
yarnGlitchOverride = false;
gameplayGlitchBaseline = 0f;
glitchController?.TransitionTo(0f, 0.25f);
if (particleManager != null)
{
@@ -163,6 +164,7 @@ namespace AibisDream
public IEnumerator FadeOutParticlesBeforeNewRound(float duration = 0f)
{
glitchController?.ClearCalmField(true);
glitchController?.TransitionTo(0f, 0.25f);
if (particleManager == null) yield break;
yield return StartCoroutine(particleManager.FadeOutBeforeNewExpressionRound(duration));
@@ -204,6 +206,7 @@ namespace AibisDream
public void CloseView()
{
glitchController?.ClearCalmField(true);
glitchController?.TransitionTo(0f, 0f);
if (expressionView != null)
{
@@ -222,6 +225,7 @@ namespace AibisDream
public void ResetSystem(bool playEntranceEffect = true)
{
glitchController?.ClearCalmField(true);
glitchController?.TransitionTo(0f, 0.25f);
if (particleManager != null)
{
@@ -117,12 +117,12 @@ namespace AibisDream.MiniGame.Language
new InterferencePresentationPreset
{
shakeIntensity = 0.035f, shakeSpeed = 10f, changeInterval = 0.28f,
floatAmplitude = 0.02f, glitchBaselineMax = 0.08f, driftBias = 0.25f
floatAmplitude = 0.02f, glitchBaselineMax = 0f, driftBias = 0.25f
},
new InterferencePresentationPreset
{
shakeIntensity = 0.05f, shakeSpeed = 12f, changeInterval = 0.18f,
floatAmplitude = 0.028f, glitchBaselineMax = 0.15f, driftBias = 0.4f
floatAmplitude = 0.028f, glitchBaselineMax = 0f, driftBias = 0.4f
},
};
@@ -183,7 +183,7 @@ namespace AibisDream.MiniGame.Language
[Tooltip("吹散后到进入平静态的延迟(秒)")]
[SerializeField] private float completionCalmDelay = 0.55f;
[Tooltip("完成瞬间 glitch 脉冲峰值(0 关闭)")]
[SerializeField, Range(0f, 1f)] private float completionGlitchPulsePeak = 0.25f;
[SerializeField, Range(0f, 1f)] private float completionGlitchPulsePeak = 0f;
[Header("节奏统一")]
[Tooltip("完成时确认按钮淡入/上浮时长(秒)")]
@@ -1264,37 +1264,6 @@ namespace AibisDream.MiniGame.Language
}
// 激活 button 并淡入上浮(不可交互,播放火山表达确认后再解锁),与确认 timeline 并行
if (focusSequenceButton != null)
{
var btnCg = focusSequenceButton.GetComponent<CanvasGroup>();
if (btnCg == null)
btnCg = focusSequenceButton.gameObject.AddComponent<CanvasGroup>();
var btnRect = focusSequenceButton.transform as RectTransform;
if (btnRect != null && !confirmButtonBasePosCaptured)
{
confirmButtonBaseAnchoredPos = btnRect.anchoredPosition;
confirmButtonBasePosCaptured = true;
}
focusSequenceButton.gameObject.SetActive(true);
focusSequenceButton.interactable = false;
DOTween.Kill(btnCg);
btnCg.alpha = 0f;
btnCg.DOFade(1f, confirmButtonFadeDuration).SetEase(Ease.OutQuad);
if (btnRect != null)
{
btnRect.DOKill();
btnRect.anchoredPosition = confirmButtonBaseAnchoredPos + Vector2.down * confirmButtonRiseOffset;
btnRect.DOAnchorPos(confirmButtonBaseAnchoredPos, confirmButtonFadeDuration).SetEase(Ease.OutQuad);
}
}
if (confirmTimelineRoutine != null)
{
StopCoroutine(confirmTimelineRoutine);
}
confirmTimelineRoutine = StartCoroutine(PlayConfirmTimelineAndUnlockButton());
foreach (var particle in candidateParticles)
{
if (!particle.isRed)
@@ -1319,6 +1288,135 @@ namespace AibisDream.MiniGame.Language
/// 延迟后进入平静态;同时打一次 glitch 短脉冲。
/// </summary>
private void PlayCompletionBurst()
{
if (completionBurstRoutine != null)
{
StopCoroutine(completionBurstRoutine);
}
completionBurstRoutine = StartCoroutine(PlayCalmCompletionRoutine());
}
private IEnumerator PlayCalmCompletionRoutine()
{
float fadeDuration = Mathf.Max(0.05f, completionCalmDelay);
float moveDuration = Mathf.Max(0.05f, completionShockwaveDuration);
if (connectionRenderer != null)
{
DOTween.To(() => connectionRenderer.NonTargetAlphaScale, v => connectionRenderer.NonTargetAlphaScale = v, 0f, fadeDuration)
.SetEase(Ease.OutQuad)
.SetTarget(this);
}
foreach (var particle in candidateParticles)
{
if (particle == null)
continue;
particle.velocity = Vector2.zero;
if (!particle.isRed)
{
particle.isCalmed = true;
particle.isStatic = true;
FadeOutTextParticle(particle, fadeDuration);
}
else
{
particle.isStatic = true;
particle.isCalmed = true;
particle.changeSpeedMultiplier = 1f;
}
}
foreach (var particle in floatingParticles)
{
if (particle == null)
continue;
particle.isCalmed = true;
particle.velocity = Vector2.zero;
FadeOutTextParticle(particle, fadeDuration);
}
int tweenTargetCount = orderedRedParticles.Count;
int completedTweens = 0;
for (int i = 0; i < orderedRedParticles.Count; i++)
{
var particle = orderedRedParticles[i];
if (particle == null)
{
completedTweens++;
continue;
}
if (i < finalTargetCharacters.Count)
{
particle.ForceSetCharacter(finalTargetCharacters[i]);
}
Vector3 targetPos = finalTargetPositions.Count > i
? finalTargetPositions[i]
: (worldCanvas != null ? worldCanvas.transform.position : Vector3.zero);
particle.alpha = particle.baseAlpha;
particle.transform.DOKill();
particle.transform.DOMove(targetPos, moveDuration)
.SetEase(Ease.InOutQuad)
.OnComplete(() => completedTweens++);
particle.transform.DOScale(Vector3.one * focusZoomScale, moveDuration).SetEase(Ease.OutQuad);
}
if (tweenTargetCount > 0)
{
while (completedTweens < tweenTargetCount)
{
yield return null;
}
}
else
{
yield return new WaitForSeconds(fadeDuration);
}
ShowFocusSequenceButton();
if (confirmTimelineRoutine != null)
{
StopCoroutine(confirmTimelineRoutine);
}
confirmTimelineRoutine = StartCoroutine(PlayConfirmTimelineAndUnlockButton());
completionBurstRoutine = null;
}
private void ShowFocusSequenceButton()
{
if (focusSequenceButton == null)
return;
var btnCg = focusSequenceButton.GetComponent<CanvasGroup>();
if (btnCg == null)
btnCg = focusSequenceButton.gameObject.AddComponent<CanvasGroup>();
var btnRect = focusSequenceButton.transform as RectTransform;
if (btnRect != null && !confirmButtonBasePosCaptured)
{
confirmButtonBaseAnchoredPos = btnRect.anchoredPosition;
confirmButtonBasePosCaptured = true;
}
focusSequenceButton.gameObject.SetActive(true);
focusSequenceButton.interactable = false;
DOTween.Kill(btnCg);
btnCg.alpha = 0f;
btnCg.DOFade(1f, confirmButtonFadeDuration).SetEase(Ease.OutQuad);
if (btnRect != null)
{
btnRect.DOKill();
btnRect.anchoredPosition = confirmButtonBaseAnchoredPos + Vector2.down * confirmButtonRiseOffset;
btnRect.DOAnchorPos(confirmButtonBaseAnchoredPos, confirmButtonFadeDuration).SetEase(Ease.OutQuad);
}
}
private void PlayCompletionBurstLegacy()
{
Vector3 center = ComputeCentroid(targetParticles);
@@ -1523,10 +1621,7 @@ namespace AibisDream.MiniGame.Language
for (int i = 0; i < orderedRedParticles.Count; i++)
{
var particle = orderedRedParticles[i];
Vector3 offset = particle.transform.position - focusCentroid;
float indexCenter = (orderedRedParticles.Count - 1) * 0.5f;
Vector3 spreadOffset = new Vector3((i - indexCenter) * spreadDistance, Mathf.Sin(i * 1.4f) * spreadDistance * 0.6f, 0f);
Vector3 focusPosition = focusTargetCenter + offset * focusZoomScale + spreadOffset;
Vector3 focusPosition = particle.transform.position;
Vector3 finalPosition = finalTargetPositions.Count > i ? finalTargetPositions[i] : focusTargetCenter;
focusPosition = ClampPositionToBounds(focusPosition, focusClipBounds);
finalPosition = ClampPositionToBounds(finalPosition, focusClipBounds);