fix: 火山玩法回退
This commit is contained in:
@@ -366,18 +366,13 @@ namespace AibisDream.EditorTests.Huoshan
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ParticleGeometry_UsesVisualEdgeDistanceAndShortestSeparationAxis()
|
||||
public void ParticleGeometry_UsesShortestSeparationAxisForWordBounds()
|
||||
{
|
||||
var left = new Bounds(Vector3.zero, new Vector3(4f, 1f, 0.01f));
|
||||
var right = new Bounds(
|
||||
new Vector3(4.15f, 0f, 0f),
|
||||
new Vector3(3.8f, 0f, 0f),
|
||||
new Vector3(4f, 1f, 0.01f));
|
||||
|
||||
Assert.That(
|
||||
ExpressionParticleGeometry.BoundsDistance(left, right),
|
||||
Is.EqualTo(0.15f).Within(0.0001f));
|
||||
|
||||
right.center = new Vector3(3.8f, 0f, 0f);
|
||||
Assert.That(
|
||||
ExpressionParticleGeometry.TryGetSeparation(
|
||||
left,
|
||||
|
||||
@@ -20,7 +20,6 @@ MonoBehaviour:
|
||||
floatingFontScale: 1
|
||||
nonTargetCountScale: 1
|
||||
wordSpacing: 0.18
|
||||
visualEdgeConnectionDistance: 0
|
||||
minimumReadablePhraseScale: 0.65
|
||||
- localeCode: ja-JP
|
||||
unitMode: 0
|
||||
@@ -29,7 +28,6 @@ MonoBehaviour:
|
||||
floatingFontScale: 1
|
||||
nonTargetCountScale: 1
|
||||
wordSpacing: 0.18
|
||||
visualEdgeConnectionDistance: 0
|
||||
minimumReadablePhraseScale: 0.65
|
||||
- localeCode: en
|
||||
unitMode: 1
|
||||
@@ -38,7 +36,6 @@ MonoBehaviour:
|
||||
floatingFontScale: 0.7
|
||||
nonTargetCountScale: 0.75
|
||||
wordSpacing: 0.18
|
||||
visualEdgeConnectionDistance: 0.18
|
||||
minimumReadablePhraseScale: 0.65
|
||||
- localeCode: es
|
||||
unitMode: 1
|
||||
@@ -47,7 +44,6 @@ MonoBehaviour:
|
||||
floatingFontScale: 0.7
|
||||
nonTargetCountScale: 0.75
|
||||
wordSpacing: 0.18
|
||||
visualEdgeConnectionDistance: 0.18
|
||||
minimumReadablePhraseScale: 0.65
|
||||
- localeCode: ru
|
||||
unitMode: 1
|
||||
@@ -56,7 +52,6 @@ MonoBehaviour:
|
||||
floatingFontScale: 0.7
|
||||
nonTargetCountScale: 0.75
|
||||
wordSpacing: 0.18
|
||||
visualEdgeConnectionDistance: 0.18
|
||||
minimumReadablePhraseScale: 0.65
|
||||
- localeCode: pt-BR
|
||||
unitMode: 1
|
||||
@@ -65,5 +60,4 @@ MonoBehaviour:
|
||||
floatingFontScale: 0.7
|
||||
nonTargetCountScale: 0.75
|
||||
wordSpacing: 0.18
|
||||
visualEdgeConnectionDistance: 0.18
|
||||
minimumReadablePhraseScale: 0.65
|
||||
|
||||
@@ -133,20 +133,15 @@ namespace AibisDream.MiniGame.Language
|
||||
// 跳过红色粒子
|
||||
if (p1.isRed && p2.isRed) continue;
|
||||
|
||||
if (!p1.connections.Contains(p2))
|
||||
continue;
|
||||
float distance = Vector3.Distance(p1.transform.position, p2.transform.position);
|
||||
if (distance < connectionDistance)
|
||||
{
|
||||
float alpha = Mathf.Lerp(0.7f, 0f, distance / connectionDistance) * fadeOutAlpha;
|
||||
Color lineColor = nonTargetConnectionColor;
|
||||
lineColor.a = alpha * nonTargetAlphaScale * nonTargetConnectionColor.a;
|
||||
|
||||
ResolveConnectionVisual(
|
||||
p1,
|
||||
p2,
|
||||
out Vector3 from,
|
||||
out Vector3 to,
|
||||
out float proximity);
|
||||
float alpha = Mathf.Lerp(0f, 0.7f, proximity) * fadeOutAlpha;
|
||||
Color lineColor = nonTargetConnectionColor;
|
||||
lineColor.a = alpha * nonTargetAlphaScale * nonTargetConnectionColor.a;
|
||||
|
||||
DrawClippedLine(from, to, lineColor);
|
||||
DrawClippedLine(p1.transform.position, p2.transform.position, lineColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -167,50 +162,23 @@ namespace AibisDream.MiniGame.Language
|
||||
{
|
||||
for (int j = i + 1; j < redParticles.Count; j++)
|
||||
{
|
||||
CandidateParticle first = redParticles[i];
|
||||
CandidateParticle second = redParticles[j];
|
||||
if (!first.connections.Contains(second))
|
||||
continue;
|
||||
float distance = Vector3.Distance(
|
||||
redParticles[i].transform.position,
|
||||
redParticles[j].transform.position
|
||||
);
|
||||
|
||||
ResolveConnectionVisual(
|
||||
first,
|
||||
second,
|
||||
out Vector3 from,
|
||||
out Vector3 to,
|
||||
out float proximity);
|
||||
float alpha = Mathf.Lerp(0.4f, 1f, proximity);
|
||||
Color lineColor = targetConnectionColor;
|
||||
lineColor.a = alpha * targetAlphaScale * targetConnectionColor.a;
|
||||
if (distance < connectionDistance)
|
||||
{
|
||||
float alpha = Mathf.Lerp(1f, 0.4f, distance / connectionDistance);
|
||||
Color lineColor = targetConnectionColor;
|
||||
lineColor.a = alpha * targetAlphaScale * targetConnectionColor.a;
|
||||
|
||||
DrawClippedLine(from, to, lineColor);
|
||||
DrawClippedLine(redParticles[i].transform.position, redParticles[j].transform.position, lineColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ResolveConnectionVisual(
|
||||
CandidateParticle first,
|
||||
CandidateParticle second,
|
||||
out Vector3 from,
|
||||
out Vector3 to,
|
||||
out float proximity)
|
||||
{
|
||||
if (manager != null &&
|
||||
manager.TryGetConnectionVisual(
|
||||
first,
|
||||
second,
|
||||
out from,
|
||||
out to,
|
||||
out proximity))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
from = first.transform.position;
|
||||
to = second.transform.position;
|
||||
float distance = Vector3.Distance(from, to);
|
||||
proximity = 1f - Mathf.Clamp01(distance / Mathf.Max(0.0001f, connectionDistance));
|
||||
}
|
||||
|
||||
private void DrawPropagationEffects()
|
||||
{
|
||||
Draw.LineGeometry = LineGeometry.Flat2D;
|
||||
|
||||
@@ -4,67 +4,6 @@ namespace AibisDream.MiniGame.Language
|
||||
{
|
||||
public static class ExpressionParticleGeometry
|
||||
{
|
||||
public static bool TryGetConnection(
|
||||
TextParticle first,
|
||||
TextParticle second,
|
||||
float centerDistanceLimit,
|
||||
float edgeDistanceLimit,
|
||||
out Vector3 from,
|
||||
out Vector3 to,
|
||||
out float proximity)
|
||||
{
|
||||
from = first != null ? first.transform.position : Vector3.zero;
|
||||
to = second != null ? second.transform.position : Vector3.zero;
|
||||
proximity = 0f;
|
||||
if (first == null || second == null)
|
||||
return false;
|
||||
|
||||
float centerDistance = Vector3.Distance(
|
||||
first.transform.position,
|
||||
second.transform.position);
|
||||
bool centerConnected =
|
||||
centerDistanceLimit > 0f && centerDistance < centerDistanceLimit;
|
||||
|
||||
Bounds firstBounds = first.GetVisualWorldBounds();
|
||||
Bounds secondBounds = second.GetVisualWorldBounds();
|
||||
float edgeDistance = BoundsDistance(firstBounds, secondBounds);
|
||||
bool edgeConnected =
|
||||
edgeDistanceLimit > 0f && edgeDistance <= edgeDistanceLimit;
|
||||
|
||||
if (!centerConnected && !edgeConnected)
|
||||
return false;
|
||||
|
||||
from = firstBounds.ClosestPoint(secondBounds.center);
|
||||
to = secondBounds.ClosestPoint(firstBounds.center);
|
||||
if ((to - from).sqrMagnitude < 0.000001f)
|
||||
{
|
||||
from = first.transform.position;
|
||||
to = second.transform.position;
|
||||
}
|
||||
|
||||
float centerProximity = centerConnected
|
||||
? 1f - Mathf.Clamp01(centerDistance / centerDistanceLimit)
|
||||
: 0f;
|
||||
float edgeProximity = edgeConnected
|
||||
? 1f - Mathf.Clamp01(edgeDistance / Mathf.Max(0.0001f, edgeDistanceLimit))
|
||||
: 0f;
|
||||
proximity = Mathf.Max(centerProximity, edgeProximity);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static float BoundsDistance(Bounds first, Bounds second)
|
||||
{
|
||||
float dx = Mathf.Max(
|
||||
first.min.x - second.max.x,
|
||||
second.min.x - first.max.x,
|
||||
0f);
|
||||
float dy = Mathf.Max(
|
||||
first.min.y - second.max.y,
|
||||
second.min.y - first.max.y,
|
||||
0f);
|
||||
return Mathf.Sqrt(dx * dx + dy * dy);
|
||||
}
|
||||
|
||||
public static bool TryGetSeparation(
|
||||
Bounds first,
|
||||
Bounds second,
|
||||
|
||||
@@ -22,7 +22,6 @@ namespace AibisDream.MiniGame.Language
|
||||
[SerializeField, Min(0.1f)] private float floatingFontScale = 1f;
|
||||
[SerializeField, Min(0f)] private float nonTargetCountScale = 1f;
|
||||
[SerializeField, Min(0f)] private float wordSpacing = 0.18f;
|
||||
[SerializeField, Min(0f)] private float visualEdgeConnectionDistance = 0f;
|
||||
[SerializeField, Range(0.1f, 1f)] private float minimumReadablePhraseScale = 0.65f;
|
||||
|
||||
public string LocaleCode => localeCode;
|
||||
@@ -32,7 +31,6 @@ namespace AibisDream.MiniGame.Language
|
||||
public float FloatingFontScale => floatingFontScale;
|
||||
public float NonTargetCountScale => nonTargetCountScale;
|
||||
public float WordSpacing => wordSpacing;
|
||||
public float VisualEdgeConnectionDistance => visualEdgeConnectionDistance;
|
||||
public float MinimumReadablePhraseScale => minimumReadablePhraseScale;
|
||||
|
||||
public int ScaleNonTargetCount(int baseCount)
|
||||
|
||||
@@ -1198,12 +1198,12 @@ namespace AibisDream.MiniGame.Language
|
||||
continue;
|
||||
}
|
||||
|
||||
if (TryGetConnectionVisual(
|
||||
candidateParticles[i],
|
||||
candidateParticles[j],
|
||||
out _,
|
||||
out _,
|
||||
out _))
|
||||
float distance = Vector3.Distance(
|
||||
candidateParticles[i].transform.position,
|
||||
candidateParticles[j].transform.position
|
||||
);
|
||||
|
||||
if (distance < connectionDistance)
|
||||
{
|
||||
candidateParticles[i].connections.Add(candidateParticles[j]);
|
||||
candidateParticles[j].connections.Add(candidateParticles[i]);
|
||||
@@ -1219,12 +1219,12 @@ namespace AibisDream.MiniGame.Language
|
||||
{
|
||||
for (int j = i + 1; j < candidateParticles.Count; j++)
|
||||
{
|
||||
if (TryGetConnectionVisual(
|
||||
candidateParticles[i],
|
||||
candidateParticles[j],
|
||||
out _,
|
||||
out _,
|
||||
out _))
|
||||
float distance = Vector3.Distance(
|
||||
candidateParticles[i].transform.position,
|
||||
candidateParticles[j].transform.position
|
||||
);
|
||||
|
||||
if (distance < connectionDistance)
|
||||
{
|
||||
string key = $"{Mathf.Min(i, j)}-{Mathf.Max(i, j)}";
|
||||
previousConnections[key] = true;
|
||||
@@ -1241,12 +1241,12 @@ namespace AibisDream.MiniGame.Language
|
||||
{
|
||||
for (int j = i + 1; j < candidateParticles.Count; j++)
|
||||
{
|
||||
if (TryGetConnectionVisual(
|
||||
candidateParticles[i],
|
||||
candidateParticles[j],
|
||||
out _,
|
||||
out _,
|
||||
out _))
|
||||
float distance = Vector3.Distance(
|
||||
candidateParticles[i].transform.position,
|
||||
candidateParticles[j].transform.position
|
||||
);
|
||||
|
||||
if (distance < connectionDistance)
|
||||
{
|
||||
string key = $"{Mathf.Min(i, j)}-{Mathf.Max(i, j)}";
|
||||
currentConnections[key] = true;
|
||||
@@ -1291,7 +1291,10 @@ namespace AibisDream.MiniGame.Language
|
||||
{
|
||||
if (other.isRed) continue;
|
||||
|
||||
if (red.connections.Contains(other))
|
||||
float distance = Vector3.Distance(
|
||||
red.transform.position,
|
||||
other.transform.position);
|
||||
if (distance < connectionDistance)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1299,27 +1302,6 @@ namespace AibisDream.MiniGame.Language
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool TryGetConnectionVisual(
|
||||
CandidateParticle first,
|
||||
CandidateParticle second,
|
||||
out Vector3 from,
|
||||
out Vector3 to,
|
||||
out float proximity)
|
||||
{
|
||||
float edgeDistance =
|
||||
ActiveUnitMode == ExpressionParticleUnitMode.Word
|
||||
? activeSnapshot?.Profile?.VisualEdgeConnectionDistance ?? 0.18f
|
||||
: 0f;
|
||||
return ExpressionParticleGeometry.TryGetConnection(
|
||||
first,
|
||||
second,
|
||||
connectionDistance,
|
||||
edgeDistance,
|
||||
out from,
|
||||
out to,
|
||||
out proximity);
|
||||
}
|
||||
|
||||
private void OnTargetsCompleted()
|
||||
{
|
||||
completionPhase = CompletionPhase.Completed;
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 84ac13641a36486d8f1a891bad6b1f28
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f6244beee7e24912bd0e6019ac802f92
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,19 +0,0 @@
|
||||
{
|
||||
"name": "AibisDream.Huoshan.Tests.PlayMode",
|
||||
"rootNamespace": "AibisDream.Huoshan.Tests.PlayMode",
|
||||
"references": [],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": false,
|
||||
"defineConstraints": [
|
||||
"UNITY_INCLUDE_TESTS"
|
||||
],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false,
|
||||
"optionalUnityReferences": [
|
||||
"TestAssemblies"
|
||||
]
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6ab7be47fb2561242a443b00c0089c26
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,90 +0,0 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Reflection;
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
using UnityEngine.TestTools;
|
||||
|
||||
namespace AibisDream.Huoshan.Tests.PlayMode
|
||||
{
|
||||
public sealed class ExpressionParticlePlayModeTests
|
||||
{
|
||||
private const string RuntimeAssemblyName = "Assembly-CSharp";
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator LongWords_ConnectThroughVisualEdgeDistance()
|
||||
{
|
||||
GameObject firstObject = new GameObject("FirstWordParticle");
|
||||
GameObject secondObject = new GameObject("SecondWordParticle");
|
||||
try
|
||||
{
|
||||
Type particleType = RequireRuntimeType(
|
||||
"AibisDream.MiniGame.Language.CandidateParticle");
|
||||
Component first = firstObject.AddComponent(particleType);
|
||||
Component second = secondObject.AddComponent(particleType);
|
||||
Invoke(first, "ForceSetUnitText", "internationalization");
|
||||
Invoke(second, "ForceSetUnitText", "characteristically");
|
||||
yield return null;
|
||||
|
||||
Bounds firstBounds = (Bounds)Invoke(first, "GetVisualWorldBounds");
|
||||
Bounds secondBounds = (Bounds)Invoke(second, "GetVisualWorldBounds");
|
||||
secondObject.transform.position = new Vector3(
|
||||
firstBounds.extents.x + secondBounds.extents.x + 0.1f,
|
||||
0f,
|
||||
0f);
|
||||
|
||||
Type geometryType = RequireRuntimeType(
|
||||
"AibisDream.MiniGame.Language.ExpressionParticleGeometry");
|
||||
MethodInfo connection = geometryType.GetMethod(
|
||||
"TryGetConnection",
|
||||
BindingFlags.Public | BindingFlags.Static);
|
||||
object[] arguments =
|
||||
{
|
||||
first,
|
||||
second,
|
||||
0.01f,
|
||||
0.18f,
|
||||
Vector3.zero,
|
||||
Vector3.zero,
|
||||
0f
|
||||
};
|
||||
|
||||
Assert.That(connection, Is.Not.Null);
|
||||
bool connected = (bool)connection.Invoke(null, arguments);
|
||||
Assert.That(connected, Is.True);
|
||||
Assert.That((float)arguments[6], Is.GreaterThan(0f));
|
||||
Assert.That(
|
||||
Vector3.Distance(
|
||||
firstObject.transform.position,
|
||||
secondObject.transform.position),
|
||||
Is.GreaterThan(0.01f));
|
||||
}
|
||||
finally
|
||||
{
|
||||
UnityEngine.Object.Destroy(firstObject);
|
||||
UnityEngine.Object.Destroy(secondObject);
|
||||
}
|
||||
|
||||
yield return null;
|
||||
}
|
||||
|
||||
private static Type RequireRuntimeType(string fullName)
|
||||
{
|
||||
Type type = Type.GetType($"{fullName}, {RuntimeAssemblyName}");
|
||||
Assert.That(type, Is.Not.Null, fullName);
|
||||
return type;
|
||||
}
|
||||
|
||||
private static object Invoke(
|
||||
object target,
|
||||
string methodName,
|
||||
params object[] arguments)
|
||||
{
|
||||
MethodInfo method = target.GetType().GetMethod(
|
||||
methodName,
|
||||
BindingFlags.Public | BindingFlags.Instance);
|
||||
Assert.That(method, Is.Not.Null, methodName);
|
||||
return method.Invoke(target, arguments);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 26043594097949158ba1572f70c94f78
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -89,8 +89,9 @@ truth leak 和老虎机覆盖池都使用同一份快照或同一 Unit Mode,
|
||||
粒子角色恢复。
|
||||
|
||||
Word Profile 还会缩小三类字号、降低非目标粒子数量,并启用宽度感知排版、
|
||||
字形边缘连接、Bounds 分离、屏幕边界和鼠标命中。全屏 Actor 故障/老虎机演出
|
||||
仍保持原来的字符级视觉。
|
||||
Bounds 分离、屏幕边界和鼠标命中。粒子连接仍统一使用原有的中心距离判定和
|
||||
中心到中心绘制,不受文字内容或字形宽度影响。全屏 Actor 故障/老虎机演出仍
|
||||
保持原来的字符级视觉。
|
||||
|
||||
## 内容校验
|
||||
|
||||
@@ -107,6 +108,6 @@ Word Profile 还会缩小三类字号、降低非目标粒子数量,并启用
|
||||
包含 `|`、`|` 或只有空白,并按 Locale 模式验证;
|
||||
- completion node、preset、memory key、颜色、Timeline 等结构参数不误报。
|
||||
|
||||
EditMode 与 PlayMode 测试覆盖原始字符串、空值不回退、缺 Key 占位、显式
|
||||
Locale、轮次配置、Locale/Profile 解析、Word/Grapheme 切分、快照、粒子
|
||||
数量倍率,以及真实粒子组件的 Bounds 命中和字形边缘连接行为。
|
||||
EditMode 测试覆盖原始字符串、空值不回退、缺 Key 占位、显式 Locale、轮次
|
||||
配置、Locale/Profile 解析、Word/Grapheme 切分、快照、粒子数量倍率,以及
|
||||
真实粒子组件的 Bounds 命中和宽度感知分离行为。
|
||||
|
||||
Reference in New Issue
Block a user