diff --git a/Assets/GameContent/Feature_Huoshan/Expression/ExpressionContentCatalog.asset b/Assets/GameContent/Feature_Huoshan/Expression/ExpressionContentCatalog.asset
index 452d1dfd9..34d45704c 100644
--- a/Assets/GameContent/Feature_Huoshan/Expression/ExpressionContentCatalog.asset
+++ b/Assets/GameContent/Feature_Huoshan/Expression/ExpressionContentCatalog.asset
@@ -11,7 +11,7 @@ MonoBehaviour:
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: a86a72005fba4c99a59962fb9e92df83, type: 3}
m_Name: ExpressionContentCatalog
- m_EditorClassIdentifier:
+ m_EditorClassIdentifier:
rounds:
- id: log1
targetReference: l10n.hs.exp.log1.target
@@ -20,8 +20,8 @@ MonoBehaviour:
- id: log2
targetReference: l10n.hs.exp.log2.target
tokenReference: l10n.hs.exp.log2.tokens
- nonTargetParticleCount: 28
+ nonTargetParticleCount: 26
- id: log3
targetReference: l10n.hs.exp.log3.target
tokenReference: l10n.hs.exp.log3.tokens
- nonTargetParticleCount: 38
+ nonTargetParticleCount: 34
diff --git a/Assets/GameContent/Feature_Huoshan/Expression/ExpressionParticleLanguageProfile.asset b/Assets/GameContent/Feature_Huoshan/Expression/ExpressionParticleLanguageProfile.asset
index b87bc5e74..62efeea31 100644
--- a/Assets/GameContent/Feature_Huoshan/Expression/ExpressionParticleLanguageProfile.asset
+++ b/Assets/GameContent/Feature_Huoshan/Expression/ExpressionParticleLanguageProfile.asset
@@ -31,33 +31,33 @@ MonoBehaviour:
minimumReadablePhraseScale: 0.65
- localeCode: en
unitMode: 1
- targetFontScale: 0.75
- nonTargetFontScale: 0.7
- floatingFontScale: 0.7
- nonTargetCountScale: 0.75
+ targetFontScale: 0.85
+ nonTargetFontScale: 0.8
+ floatingFontScale: 0.8
+ nonTargetCountScale: 0.85
wordSpacing: 0.18
minimumReadablePhraseScale: 0.65
- localeCode: es
unitMode: 1
- targetFontScale: 0.75
- nonTargetFontScale: 0.7
- floatingFontScale: 0.7
- nonTargetCountScale: 0.75
+ targetFontScale: 0.85
+ nonTargetFontScale: 0.8
+ floatingFontScale: 0.8
+ nonTargetCountScale: 0.85
wordSpacing: 0.18
minimumReadablePhraseScale: 0.65
- localeCode: ru
unitMode: 1
- targetFontScale: 0.75
- nonTargetFontScale: 0.7
- floatingFontScale: 0.7
- nonTargetCountScale: 0.75
+ targetFontScale: 0.85
+ nonTargetFontScale: 0.8
+ floatingFontScale: 0.8
+ nonTargetCountScale: 0.85
wordSpacing: 0.18
minimumReadablePhraseScale: 0.65
- localeCode: pt-BR
unitMode: 1
- targetFontScale: 0.75
- nonTargetFontScale: 0.7
- floatingFontScale: 0.7
- nonTargetCountScale: 0.75
+ targetFontScale: 0.85
+ nonTargetFontScale: 0.8
+ floatingFontScale: 0.8
+ nonTargetCountScale: 0.85
wordSpacing: 0.18
minimumReadablePhraseScale: 0.65
diff --git a/Assets/Scripts/MiniGame/HuoShan/Language/LanguageParticleManager.cs b/Assets/Scripts/MiniGame/HuoShan/Language/LanguageParticleManager.cs
index 494b32e53..cae607f84 100644
--- a/Assets/Scripts/MiniGame/HuoShan/Language/LanguageParticleManager.cs
+++ b/Assets/Scripts/MiniGame/HuoShan/Language/LanguageParticleManager.cs
@@ -2222,6 +2222,44 @@ namespace AibisDream.MiniGame.Language
}
}
+ ///
+ /// 只恢复当前演出短语使用的粒子;超出短语长度的旧词保持隐藏。
+ ///
+ public void SetCurrentPresentationPhraseAlpha(
+ float targetAlpha,
+ float duration = 0f)
+ {
+ List particles = GetPresentationPhraseParticles();
+ int visibleCount = finalTargetUnits.Count > 0
+ ? Mathf.Min(finalTargetUnits.Count, particles.Count)
+ : particles.Count;
+ float alphaValue = Mathf.Clamp01(targetAlpha);
+
+ for (int i = 0; i < particles.Count; i++)
+ {
+ CandidateParticle particle = particles[i];
+ if (particle == null)
+ continue;
+
+ DOTween.Kill(particle);
+ float destinationAlpha = i < visibleCount ? alphaValue : 0f;
+ if (duration <= 0f)
+ {
+ particle.alpha = destinationAlpha;
+ }
+ else
+ {
+ DOTween.To(
+ () => particle.alpha,
+ value => particle.alpha = value,
+ destinationAlpha,
+ duration)
+ .SetEase(Ease.OutQuad)
+ .SetTarget(particle);
+ }
+ }
+ }
+
///
/// 将已完成聚焦的目标粒子改排为红色攻击词。文字必须完整放进现有目标粒子,
/// 超长时拒绝播放,避免演出层静默删字。
@@ -2433,10 +2471,12 @@ namespace AibisDream.MiniGame.Language
///
public IEnumerator SettleTruthPhraseAndWait(string text, float duration)
{
- List particles = GetPresentationPhraseParticles();
+ List units = TokenizeActiveText(text);
+ List particles = GetPresentationPhraseParticles(
+ units.Count,
+ allowExpansion: true);
if (!ValidatePresentationPhrase(text, particles, "真话稳定"))
yield break;
- List units = TokenizeActiveText(text);
PreparePresentationPhraseControl();
@@ -2555,19 +2595,74 @@ namespace AibisDream.MiniGame.Language
}
}
- private List GetPresentationPhraseParticles()
+ private List GetPresentationPhraseParticles(
+ int requiredCount = 0,
+ bool allowExpansion = false)
{
List particles = orderedRedParticles
.Where(particle => particle != null)
.Distinct()
.ToList();
- if (particles.Count > 0)
+ if (particles.Count == 0)
+ {
+ particles = targetParticles
+ .Where(particle => particle != null)
+ .OrderBy(particle => particle.transform.position.x)
+ .ToList();
+ }
+
+ if (!allowExpansion || requiredCount <= particles.Count)
return particles;
- return targetParticles
- .Where(particle => particle != null)
- .OrderBy(particle => particle.transform.position.x)
- .ToList();
+ // 最终稳定文案可能比本轮目标句更长(英文和俄文尤其常见)。
+ // 此时玩法已经结束,干扰粒子也已淡出,可以安全复用它们补足展示容量,
+ // 避免容量校验跳过整段收尾并把上一句攻击词留在红色失稳状态。
+ if (candidateParticles.Count < requiredCount)
+ EnsureCandidatePoolSize(requiredCount);
+
+ var existing = new HashSet(particles);
+ CandidateParticle[] sourceParticles = particles.ToArray();
+ Vector3 phraseCenter = sourceParticles.Length > 0
+ ? ComputeCentroid(particles)
+ : (worldCanvas != null ? worldCanvas.transform.position : transform.position);
+
+ foreach (CandidateParticle particle in candidateParticles
+ .Where(particle => particle != null && !existing.Contains(particle))
+ .OrderBy(particle =>
+ (particle.transform.position - phraseCenter).sqrMagnitude))
+ {
+ int sourceIndex = particles.Count - sourceParticles.Length;
+ Vector3 sourcePosition = sourceParticles.Length > 0
+ ? sourceParticles[sourceIndex % sourceParticles.Length].transform.position
+ : phraseCenter;
+
+ particle.transform.DOKill();
+ DOTween.Kill(particle);
+ particle.transform.position = sourcePosition;
+ particle.transform.localScale = Vector3.one * ResolvedFocusScale;
+ particle.velocity = Vector2.zero;
+ particle.isRed = true;
+ particle.isTemporaryRed = true;
+ particle.isOrange = false;
+ particle.hasEffect = false;
+ particle.isCalmed = true;
+ particle.isStatic = true;
+ particle.anxietyShakeIntensity = 0f;
+ particle.ClearFocusInterference();
+ particle.alpha = 0f;
+
+ particles.Add(particle);
+ existing.Add(particle);
+ if (!targetParticles.Contains(particle))
+ targetParticles.Add(particle);
+ if (!orderedRedParticles.Contains(particle))
+ orderedRedParticles.Add(particle);
+
+ if (particles.Count >= requiredCount)
+ break;
+ }
+
+ return particles;
}
private bool ValidatePresentationPhrase(
@@ -2698,7 +2793,7 @@ namespace AibisDream.MiniGame.Language
activeSnapshot?.Profile?.MinimumReadablePhraseScale ?? 0.65f;
if (activePhraseScale < minimumReadable)
{
- Debug.LogError(
+ Debug.LogWarning(
$"[LanguageParticleManager] 表达文字需要缩放到 {activePhraseScale:0.00}," +
$"低于 Locale Profile 最小可读值 {minimumReadable:0.00};" +
"运行时仍会缩放以保证文字完整显示。");
@@ -2770,6 +2865,8 @@ namespace AibisDream.MiniGame.Language
nonTargetParticleFontSize,
false,
nonTargetParticleBold);
+ particle.anxietyShakeIntensity = 0f;
+ particle.ClearFocusInterference();
}
}
diff --git a/Assets/Scripts/MiniGame/HuoShan/Language/LogReleasePresentationController.cs b/Assets/Scripts/MiniGame/HuoShan/Language/LogReleasePresentationController.cs
index 73ef9e9bb..c7ba2886a 100644
--- a/Assets/Scripts/MiniGame/HuoShan/Language/LogReleasePresentationController.cs
+++ b/Assets/Scripts/MiniGame/HuoShan/Language/LogReleasePresentationController.cs
@@ -901,7 +901,7 @@ namespace AibisDream.MiniGame.Language
particleManager?.PrepareTruthReleaseFromLie();
particleManager?.ApplyPresentationResolvedVisuals(presentationResolvedColor);
- particleManager?.SetTargetParticlesAlpha(1f, 0f);
+ particleManager?.SetCurrentPresentationPhraseAlpha(1f, 0f);
Bounds truthBounds = particleManager != null
? particleManager.GetFinalTruthWorldBounds()
: new Bounds(GetScreenBounds().center, Vector3.one);