Merge branch 'feature/TextUpdate' into 'develop'

Feature/text update

See merge request aibis-dream/aibis-dream!559
This commit is contained in:
2025-11-17 12:43:45 +00:00
83 changed files with 2840 additions and 3588 deletions
File diff suppressed because it is too large Load Diff
@@ -579,11 +579,11 @@ MonoBehaviour:
m_Metadata:
m_Items: []
- m_Id: 1487731321634816
m_Localized: "\u6267\u884C\u5207\u9664\u6A21\u5757"
m_Localized: "\u6267\u884C\u6A21\u5757\u5207\u9664"
m_Metadata:
m_Items: []
- m_Id: 1487731279691776
m_Localized: "\u6267\u884C\u5207\u9664\u6A21\u5757"
m_Localized: "\u6267\u884C\u6A21\u5757\u5207\u9664"
m_Metadata:
m_Items: []
- m_Id: 1487731321634819
@@ -607,7 +607,7 @@ MonoBehaviour:
m_Metadata:
m_Items: []
- m_Id: 1487731321634817
m_Localized: "\u6267\u884C\u5207\u9664\u6A21\u5757"
m_Localized: "\u6267\u884C\u6A21\u5757\u5207\u9664"
m_Metadata:
m_Items: []
- m_Id: 30120683173318656
@@ -626,6 +626,14 @@ MonoBehaviour:
m_Localized: "\u903B\u8F91"
m_Metadata:
m_Items: []
- m_Id: 53970478019121152
m_Localized: "\u9009\u98791"
m_Metadata:
m_Items: []
- m_Id: 53970478052675584
m_Localized: "\u9009\u98792"
m_Metadata:
m_Items: []
references:
version: 2
RefIds: []
@@ -203,6 +203,10 @@ MonoBehaviour:
m_Key: chapter_continue
m_Metadata:
m_Items: []
- m_Id: 73229033469382656
m_Key: setting_textSpeed_slow
m_Metadata:
m_Items: []
m_Metadata:
m_Items: []
m_KeyGenerator:
+5 -1
View File
@@ -85,7 +85,7 @@ MonoBehaviour:
m_Metadata:
m_Items: []
- m_Id: 22296675749900
m_Localized: WINDOW MODE
m_Localized: SCREEN MODE
m_Metadata:
m_Items: []
- m_Id: 22296675749901
@@ -220,6 +220,10 @@ MonoBehaviour:
m_Localized: Continue
m_Metadata:
m_Items: []
- m_Id: 73229033469382656
m_Localized: SLOW
m_Metadata:
m_Items: []
references:
version: 2
RefIds:
+5 -1
View File
@@ -89,7 +89,7 @@ MonoBehaviour:
m_Metadata:
m_Items: []
- m_Id: 22296675749900
m_Localized: "\u7A97\u53E3\u6A21\u5F0F"
m_Localized: "\u5C4F\u5E55\u6A21\u5F0F"
m_Metadata:
m_Items: []
- m_Id: 22296675749901
@@ -209,6 +209,10 @@ MonoBehaviour:
m_Metadata:
m_Items:
- rid: 7917695939544875419
- m_Id: 73229033469382656
m_Localized: "\u6162\u901F"
m_Metadata:
m_Items: []
references:
version: 2
RefIds:
Binary file not shown.
@@ -1,153 +0,0 @@
fileFormatVersion: 2
guid: b939a31a2f1b6524982f857bf92bf218
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 12
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
flipGreenChannel: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
ignoreMipmapLimit: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 0
aniso: 1
mipBias: 0
wrapU: 1
wrapV: 1
wrapW: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 8
textureShape: 1
singleChannelComponent: 0
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
swizzle: 50462976
cookieLightType: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: WebGL
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Android
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Server
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID: 5e97eb03825dee720800000000000000
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
nameFileIdTable: {}
mipmapLimitGroupName:
pSDRemoveMatte: 0
userData:
assetBundleName:
assetBundleVariant:
+9 -12
View File
@@ -463,18 +463,15 @@ MonoBehaviour:
m_PostInfinity: 2
m_RotationOrder: 4
_filter:
- 0.004854369
- 0.021177985
- 0.06010355
- 0.106563106
- 0.14548868
- 0.1618123
- 0.1618123
- 0.14548868
- 0.106563106
- 0.06010355
- 0.021177985
- 0.004854369
- 0.007228916
- 0.043749984
- 0.12409639
- 0.20444278
- 0.24096388
- 0.20444278
- 0.12409639
- 0.043749984
- 0.007228916
--- !u!114 &-6086986437317696584
MonoBehaviour:
m_ObjectHideFlags: 3
@@ -22,7 +22,6 @@ position: 250,200
<<fade_out>>
<<play_sfx "event:/Scriptal/sea_loop">>
我知道我不应该在这里,<waitfor=0.5><br>但是在醒来之前,<waitfor=0.3>我还有很多时间。 #line:0e3b3ba
<<hide_dialog>>
<<wait 1>>
+402 -313
View File
@@ -493,7 +493,7 @@ MonoBehaviour:
styleSheet: {fileID: 0}
databaseActions: {fileID: 11400000, guid: de78232a60d74f6459e57e5606304209, type: 2}
defaultAppearancesTags:
- 'fade '
- step
defaultDisappearancesTags:
- fade
defaultBehaviorsTags: []
@@ -521,7 +521,7 @@ MonoBehaviour:
m_text: "\u5BF9\u8BDD\u5185\u5BB9\u663E\u793A\u5728\u8FD9\u91CC<sub>\u652F\u6301\u5BCC\u6587\u672C</sub>"
m_isRightToLeft: 0
m_fontAsset: {fileID: 11400000, guid: c7fc4cbba4b38a04c8985d4dbce12a73, type: 2}
m_sharedMaterial: {fileID: -6659093157667844055, guid: f242fb3dde1933640859f1c54591c9c8, type: 2}
m_sharedMaterial: {fileID: -5947736473428621296, guid: c7fc4cbba4b38a04c8985d4dbce12a73, type: 2}
m_fontSharedMaterials: []
m_fontMaterial: {fileID: 0}
m_fontMaterials: []
@@ -584,7 +584,7 @@ MonoBehaviour:
m_margin: {x: 0, y: 0, z: 0, w: 0}
m_isUsingLegacyAnimationComponent: 0
m_isVolumetricText: 0
m_hasFontAssetChanged: 1
m_hasFontAssetChanged: 0
m_baseMaterial: {fileID: 0}
m_maskOffset: {x: 0, y: 0, z: 0, w: 0}
--- !u!222 &27659202
@@ -1559,195 +1559,6 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 85815d386fde43dca8b4be1cfd26fe89, type: 3}
m_Name:
m_EditorClassIdentifier:
--- !u!1001 &71838975
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
serializedVersion: 3
m_TransformParent: {fileID: 781740447}
m_Modifications:
- target: {fileID: 215275187407609090, guid: 1f392e4cea7cf3943a25361ff1d1ff85, type: 3}
propertyPath: m_Sprite
value:
objectReference: {fileID: 704217432, guid: 3fb22d1d71379f54f8dec756b08e3307, type: 3}
- target: {fileID: 1284103664181101717, guid: 1f392e4cea7cf3943a25361ff1d1ff85, type: 3}
propertyPath: m_Pivot.x
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 1284103664181101717, guid: 1f392e4cea7cf3943a25361ff1d1ff85, type: 3}
propertyPath: m_Pivot.y
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 1284103664181101717, guid: 1f392e4cea7cf3943a25361ff1d1ff85, type: 3}
propertyPath: m_AnchorMax.x
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 1284103664181101717, guid: 1f392e4cea7cf3943a25361ff1d1ff85, type: 3}
propertyPath: m_AnchorMax.y
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 1284103664181101717, guid: 1f392e4cea7cf3943a25361ff1d1ff85, type: 3}
propertyPath: m_AnchorMin.x
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 1284103664181101717, guid: 1f392e4cea7cf3943a25361ff1d1ff85, type: 3}
propertyPath: m_AnchorMin.y
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 1284103664181101717, guid: 1f392e4cea7cf3943a25361ff1d1ff85, type: 3}
propertyPath: m_SizeDelta.x
value: 453.11
objectReference: {fileID: 0}
- target: {fileID: 1284103664181101717, guid: 1f392e4cea7cf3943a25361ff1d1ff85, type: 3}
propertyPath: m_SizeDelta.y
value: 70.009995
objectReference: {fileID: 0}
- target: {fileID: 1284103664181101717, guid: 1f392e4cea7cf3943a25361ff1d1ff85, type: 3}
propertyPath: m_LocalPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1284103664181101717, guid: 1f392e4cea7cf3943a25361ff1d1ff85, type: 3}
propertyPath: m_LocalPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1284103664181101717, guid: 1f392e4cea7cf3943a25361ff1d1ff85, type: 3}
propertyPath: m_LocalPosition.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1284103664181101717, guid: 1f392e4cea7cf3943a25361ff1d1ff85, type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 1284103664181101717, guid: 1f392e4cea7cf3943a25361ff1d1ff85, type: 3}
propertyPath: m_LocalRotation.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1284103664181101717, guid: 1f392e4cea7cf3943a25361ff1d1ff85, type: 3}
propertyPath: m_LocalRotation.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1284103664181101717, guid: 1f392e4cea7cf3943a25361ff1d1ff85, type: 3}
propertyPath: m_LocalRotation.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1284103664181101717, guid: 1f392e4cea7cf3943a25361ff1d1ff85, type: 3}
propertyPath: m_AnchoredPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1284103664181101717, guid: 1f392e4cea7cf3943a25361ff1d1ff85, type: 3}
propertyPath: m_AnchoredPosition.y
value: -300
objectReference: {fileID: 0}
- target: {fileID: 1284103664181101717, guid: 1f392e4cea7cf3943a25361ff1d1ff85, type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1284103664181101717, guid: 1f392e4cea7cf3943a25361ff1d1ff85, type: 3}
propertyPath: m_LocalEulerAnglesHint.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1284103664181101717, guid: 1f392e4cea7cf3943a25361ff1d1ff85, type: 3}
propertyPath: m_LocalEulerAnglesHint.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3741179239662950829, guid: 1f392e4cea7cf3943a25361ff1d1ff85, type: 3}
propertyPath: m_IsActive
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4083462688583332915, guid: 1f392e4cea7cf3943a25361ff1d1ff85, type: 3}
propertyPath: m_Padding.m_Top
value: 10
objectReference: {fileID: 0}
- target: {fileID: 4083462688583332915, guid: 1f392e4cea7cf3943a25361ff1d1ff85, type: 3}
propertyPath: m_Padding.m_Left
value: 5
objectReference: {fileID: 0}
- target: {fileID: 4083462688583332915, guid: 1f392e4cea7cf3943a25361ff1d1ff85, type: 3}
propertyPath: m_Padding.m_Right
value: 15
objectReference: {fileID: 0}
- target: {fileID: 4083462688583332915, guid: 1f392e4cea7cf3943a25361ff1d1ff85, type: 3}
propertyPath: m_Padding.m_Bottom
value: 10
objectReference: {fileID: 0}
- target: {fileID: 4698362591619572577, guid: 1f392e4cea7cf3943a25361ff1d1ff85, type: 3}
propertyPath: m_MinWidth
value: 0
objectReference: {fileID: 0}
- target: {fileID: 5463321828217487701, guid: 1f392e4cea7cf3943a25361ff1d1ff85, type: 3}
propertyPath: m_AnchorMax.y
value: 1
objectReference: {fileID: 0}
- target: {fileID: 5463321828217487701, guid: 1f392e4cea7cf3943a25361ff1d1ff85, type: 3}
propertyPath: m_AnchorMin.y
value: 1
objectReference: {fileID: 0}
- target: {fileID: 5463321828217487701, guid: 1f392e4cea7cf3943a25361ff1d1ff85, type: 3}
propertyPath: m_SizeDelta.x
value: 433.11
objectReference: {fileID: 0}
- target: {fileID: 5463321828217487701, guid: 1f392e4cea7cf3943a25361ff1d1ff85, type: 3}
propertyPath: m_SizeDelta.y
value: 50.01
objectReference: {fileID: 0}
- target: {fileID: 5463321828217487701, guid: 1f392e4cea7cf3943a25361ff1d1ff85, type: 3}
propertyPath: m_AnchoredPosition.x
value: 221.555
objectReference: {fileID: 0}
- target: {fileID: 5463321828217487701, guid: 1f392e4cea7cf3943a25361ff1d1ff85, type: 3}
propertyPath: m_AnchoredPosition.y
value: -60.01
objectReference: {fileID: 0}
- target: {fileID: 8272198623999747867, guid: 1f392e4cea7cf3943a25361ff1d1ff85, type: 3}
propertyPath: m_AnchorMax.y
value: 1
objectReference: {fileID: 0}
- target: {fileID: 8272198623999747867, guid: 1f392e4cea7cf3943a25361ff1d1ff85, type: 3}
propertyPath: m_AnchorMin.y
value: 1
objectReference: {fileID: 0}
- target: {fileID: 8272198623999747867, guid: 1f392e4cea7cf3943a25361ff1d1ff85, type: 3}
propertyPath: m_SizeDelta.x
value: 64.01
objectReference: {fileID: 0}
- target: {fileID: 8272198623999747867, guid: 1f392e4cea7cf3943a25361ff1d1ff85, type: 3}
propertyPath: m_SizeDelta.y
value: 32.01
objectReference: {fileID: 0}
- target: {fileID: 8272198623999747867, guid: 1f392e4cea7cf3943a25361ff1d1ff85, type: 3}
propertyPath: m_AnchoredPosition.x
value: 52.005005
objectReference: {fileID: 0}
- target: {fileID: 8272198623999747867, guid: 1f392e4cea7cf3943a25361ff1d1ff85, type: 3}
propertyPath: m_AnchoredPosition.y
value: -36.004997
objectReference: {fileID: 0}
- target: {fileID: 8352794458094198668, guid: 1f392e4cea7cf3943a25361ff1d1ff85, type: 3}
propertyPath: m_Name
value: Bubble
objectReference: {fileID: 0}
- target: {fileID: 8352794458094198668, guid: 1f392e4cea7cf3943a25361ff1d1ff85, type: 3}
propertyPath: m_IsActive
value: 0
objectReference: {fileID: 0}
- target: {fileID: 8947926204029201251, guid: 1f392e4cea7cf3943a25361ff1d1ff85, type: 3}
propertyPath: testMaxWidth
value: -1
objectReference: {fileID: 0}
- target: {fileID: 8947926204029201251, guid: 1f392e4cea7cf3943a25361ff1d1ff85, type: 3}
propertyPath: testPivotType
value: 8
objectReference: {fileID: 0}
- target: {fileID: 8947926204029201251, guid: 1f392e4cea7cf3943a25361ff1d1ff85, type: 3}
propertyPath: testBubbleStyle
value:
objectReference: {fileID: 11400000, guid: e5e5761693b62ef4891f7f08ec8bcbd8, type: 2}
m_RemovedComponents: []
m_RemovedGameObjects: []
m_AddedGameObjects: []
m_AddedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: 1f392e4cea7cf3943a25361ff1d1ff85, type: 3}
--- !u!1 &72512885
GameObject:
m_ObjectHideFlags: 0
@@ -1778,7 +1589,6 @@ Transform:
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 1584263514}
- {fileID: 1936621685}
m_Father: {fileID: 1009826577}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
@@ -1794,8 +1604,8 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 8912c53f0d9943940a6bb7e59888ada8, type: 3}
m_Name:
m_EditorClassIdentifier:
quickRunMode: 0
autoRunMode: 0
lineAdvanceInput: {fileID: 1977401368}
isInOption: 0
--- !u!1 &77816930
GameObject:
m_ObjectHideFlags: 0
@@ -4886,14 +4696,12 @@ RectTransform:
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 238296902}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 781740447}
- {fileID: 1612148020}
m_Father: {fileID: 1604842429}
m_Children: []
m_Father: {fileID: 1829169896}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 1}
@@ -4912,6 +4720,8 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: a76234ef7ee34400b306a4823081ba62, type: 3}
m_Name:
m_EditorClassIdentifier:
widthEstimation: {fileID: 1318260399}
centerBubble: {fileID: 1403558896}
--- !u!1 &246580517
GameObject:
m_ObjectHideFlags: 0
@@ -5740,6 +5550,160 @@ MonoBehaviour:
m_EditorClassIdentifier:
objWidth: 700
objHeight: 550
--- !u!1001 &309628996
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
serializedVersion: 3
m_TransformParent: {fileID: 430924359}
m_Modifications:
- target: {fileID: 27177156846382951, guid: e45f5fd66e7512444a9a27161cf51b7f, type: 3}
propertyPath: m_SizeDelta.x
value: 180
objectReference: {fileID: 0}
- target: {fileID: 1032211294988139403, guid: e45f5fd66e7512444a9a27161cf51b7f, type: 3}
propertyPath: m_StringReference.m_TableEntryReference.m_KeyId
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1032211294988139403, guid: e45f5fd66e7512444a9a27161cf51b7f, type: 3}
propertyPath: m_StringReference.m_TableReference.m_TableCollectionName
value: GUID:994c69bf4b2403043bc9562f2d24ee56
objectReference: {fileID: 0}
- target: {fileID: 4099831927643554877, guid: e45f5fd66e7512444a9a27161cf51b7f, type: 3}
propertyPath: prop
value: TextSpeed
objectReference: {fileID: 0}
- target: {fileID: 4099831927643554877, guid: e45f5fd66e7512444a9a27161cf51b7f, type: 3}
propertyPath: label
value: setting_textSpeed
objectReference: {fileID: 0}
- target: {fileID: 4099831927643554877, guid: e45f5fd66e7512444a9a27161cf51b7f, type: 3}
propertyPath: options.Array.size
value: 3
objectReference: {fileID: 0}
- target: {fileID: 4099831927643554877, guid: e45f5fd66e7512444a9a27161cf51b7f, type: 3}
propertyPath: options.Array.data[0].prop
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 4099831927643554877, guid: e45f5fd66e7512444a9a27161cf51b7f, type: 3}
propertyPath: options.Array.data[1].prop
value: 1.0
objectReference: {fileID: 0}
- target: {fileID: 4099831927643554877, guid: e45f5fd66e7512444a9a27161cf51b7f, type: 3}
propertyPath: options.Array.data[2].prop
value: 3.0
objectReference: {fileID: 0}
- target: {fileID: 4099831927643554877, guid: e45f5fd66e7512444a9a27161cf51b7f, type: 3}
propertyPath: options.Array.data[0].label
value: setting_textSpeed_slow
objectReference: {fileID: 0}
- target: {fileID: 4099831927643554877, guid: e45f5fd66e7512444a9a27161cf51b7f, type: 3}
propertyPath: options.Array.data[1].label
value: setting_textSpeed_default
objectReference: {fileID: 0}
- target: {fileID: 4099831927643554877, guid: e45f5fd66e7512444a9a27161cf51b7f, type: 3}
propertyPath: options.Array.data[2].label
value: setting_textSpeed_fast
objectReference: {fileID: 0}
- target: {fileID: 5006247552854995519, guid: e45f5fd66e7512444a9a27161cf51b7f, type: 3}
propertyPath: m_text
value: "\u6587\u5B57\u901F\u5EA6"
objectReference: {fileID: 0}
- target: {fileID: 5654956763089875896, guid: e45f5fd66e7512444a9a27161cf51b7f, type: 3}
propertyPath: m_Name
value: Text Speed
objectReference: {fileID: 0}
- target: {fileID: 5824597425683931436, guid: e45f5fd66e7512444a9a27161cf51b7f, type: 3}
propertyPath: m_Pivot.x
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 5824597425683931436, guid: e45f5fd66e7512444a9a27161cf51b7f, type: 3}
propertyPath: m_Pivot.y
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 5824597425683931436, guid: e45f5fd66e7512444a9a27161cf51b7f, type: 3}
propertyPath: m_AnchorMax.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 5824597425683931436, guid: e45f5fd66e7512444a9a27161cf51b7f, type: 3}
propertyPath: m_AnchorMax.y
value: 1
objectReference: {fileID: 0}
- target: {fileID: 5824597425683931436, guid: e45f5fd66e7512444a9a27161cf51b7f, type: 3}
propertyPath: m_AnchorMin.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 5824597425683931436, guid: e45f5fd66e7512444a9a27161cf51b7f, type: 3}
propertyPath: m_AnchorMin.y
value: 1
objectReference: {fileID: 0}
- target: {fileID: 5824597425683931436, guid: e45f5fd66e7512444a9a27161cf51b7f, type: 3}
propertyPath: m_SizeDelta.x
value: 200
objectReference: {fileID: 0}
- target: {fileID: 5824597425683931436, guid: e45f5fd66e7512444a9a27161cf51b7f, type: 3}
propertyPath: m_SizeDelta.y
value: 50
objectReference: {fileID: 0}
- target: {fileID: 5824597425683931436, guid: e45f5fd66e7512444a9a27161cf51b7f, type: 3}
propertyPath: m_LocalPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 5824597425683931436, guid: e45f5fd66e7512444a9a27161cf51b7f, type: 3}
propertyPath: m_LocalPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 5824597425683931436, guid: e45f5fd66e7512444a9a27161cf51b7f, type: 3}
propertyPath: m_LocalPosition.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 5824597425683931436, guid: e45f5fd66e7512444a9a27161cf51b7f, type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 5824597425683931436, guid: e45f5fd66e7512444a9a27161cf51b7f, type: 3}
propertyPath: m_LocalRotation.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 5824597425683931436, guid: e45f5fd66e7512444a9a27161cf51b7f, type: 3}
propertyPath: m_LocalRotation.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 5824597425683931436, guid: e45f5fd66e7512444a9a27161cf51b7f, type: 3}
propertyPath: m_LocalRotation.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 5824597425683931436, guid: e45f5fd66e7512444a9a27161cf51b7f, type: 3}
propertyPath: m_AnchoredPosition.x
value: 100
objectReference: {fileID: 0}
- target: {fileID: 5824597425683931436, guid: e45f5fd66e7512444a9a27161cf51b7f, type: 3}
propertyPath: m_AnchoredPosition.y
value: -230
objectReference: {fileID: 0}
- target: {fileID: 5824597425683931436, guid: e45f5fd66e7512444a9a27161cf51b7f, type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 5824597425683931436, guid: e45f5fd66e7512444a9a27161cf51b7f, type: 3}
propertyPath: m_LocalEulerAnglesHint.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 5824597425683931436, guid: e45f5fd66e7512444a9a27161cf51b7f, type: 3}
propertyPath: m_LocalEulerAnglesHint.z
value: 0
objectReference: {fileID: 0}
m_RemovedComponents: []
m_RemovedGameObjects: []
m_AddedGameObjects: []
m_AddedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: e45f5fd66e7512444a9a27161cf51b7f, type: 3}
--- !u!224 &309628997 stripped
RectTransform:
m_CorrespondingSourceObject: {fileID: 5824597425683931436, guid: e45f5fd66e7512444a9a27161cf51b7f, type: 3}
m_PrefabInstance: {fileID: 309628996}
m_PrefabAsset: {fileID: 0}
--- !u!1 &314243161
GameObject:
m_ObjectHideFlags: 0
@@ -6447,7 +6411,7 @@ GameObject:
- component: {fileID: 367483176}
m_Layer: 5
m_Name: Top Bar
m_TagString: Selectable
m_TagString: MainUI
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
@@ -6543,7 +6507,7 @@ MonoBehaviour:
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_Sprite: {fileID: 951630327, guid: ca909870d485bde44b1e652490df203f, type: 3}
m_Sprite: {fileID: 0}
m_Type: 1
m_PreserveAspect: 0
m_FillCenter: 1
@@ -6726,11 +6690,58 @@ MonoBehaviour:
Data3: 1610383794
Data4: -1468709119
Path: event:/Amb/amb
--- !u!224 &375324529 stripped
RectTransform:
m_CorrespondingSourceObject: {fileID: 1284103664181101717, guid: 1f392e4cea7cf3943a25361ff1d1ff85, type: 3}
m_PrefabInstance: {fileID: 71838975}
--- !u!1 &381795661
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 381795662}
- component: {fileID: 381795663}
m_Layer: 5
m_Name: Option View
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &381795662
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 381795661}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 1612148020}
- {fileID: 1586904153}
m_Father: {fileID: 1604842429}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &381795663
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 381795661}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 56ee480f25a146839afa8ff058ddfc7a, type: 3}
m_Name:
m_EditorClassIdentifier:
defaultOptions: {fileID: 1612148021}
centerOptions: {fileID: 1586904157}
--- !u!1 &387773934
GameObject:
m_ObjectHideFlags: 0
@@ -7049,6 +7060,7 @@ RectTransform:
- {fileID: 1865858738}
- {fileID: 2395518499295578437}
- {fileID: 1518372517}
- {fileID: 309628997}
m_Father: {fileID: 1937938010}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 1}
@@ -12314,42 +12326,6 @@ CanvasRenderer:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 773911909}
m_CullTransparentMesh: 1
--- !u!1 &781740446
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 781740447}
m_Layer: 5
m_Name: Bubbles
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &781740447
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 781740446}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 375324529}
m_Father: {fileID: 238296903}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &788983287 stripped
MonoBehaviour:
m_CorrespondingSourceObject: {fileID: 2261302370767925378, guid: a1dbef2a0a50ecf49a39eae2d3e486b2, type: 3}
@@ -18590,7 +18566,7 @@ RectTransform:
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 1604842429}
m_Father: {fileID: 1829169896}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
@@ -20191,18 +20167,18 @@ RectTransform:
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1403558892}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 27659198}
m_Father: {fileID: 1604842429}
m_Father: {fileID: 1829169896}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_SizeDelta: {x: 1820.0001, y: 980.2295}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &1403558895
CanvasRenderer:
@@ -20221,9 +20197,10 @@ MonoBehaviour:
m_GameObject: {fileID: 1403558892}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: d6722100b986b0f42994441d3c0aa9e7, type: 3}
m_Script: {fileID: 11500000, guid: 67e53e476f874efd9d847b50dc16d6c8, type: 3}
m_Name:
m_EditorClassIdentifier:
dialogText: {fileID: 27659199}
--- !u!1 &1411435708
GameObject:
m_ObjectHideFlags: 0
@@ -21188,6 +21165,14 @@ PrefabInstance:
propertyPath: m_SizeDelta.x
value: 180
objectReference: {fileID: 0}
- target: {fileID: 1032211294988139403, guid: e45f5fd66e7512444a9a27161cf51b7f, type: 3}
propertyPath: m_StringReference.m_TableEntryReference.m_KeyId
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1032211294988139403, guid: e45f5fd66e7512444a9a27161cf51b7f, type: 3}
propertyPath: m_StringReference.m_TableReference.m_TableCollectionName
value: GUID:994c69bf4b2403043bc9562f2d24ee56
objectReference: {fileID: 0}
- target: {fileID: 4099831927643554877, guid: e45f5fd66e7512444a9a27161cf51b7f, type: 3}
propertyPath: options.Array.size
value: 2
@@ -21278,7 +21263,7 @@ PrefabInstance:
objectReference: {fileID: 0}
- target: {fileID: 5824597425683931436, guid: e45f5fd66e7512444a9a27161cf51b7f, type: 3}
propertyPath: m_AnchoredPosition.y
value: -190
value: -150
objectReference: {fileID: 0}
- target: {fileID: 5824597425683931436, guid: e45f5fd66e7512444a9a27161cf51b7f, type: 3}
propertyPath: m_LocalEulerAnglesHint.x
@@ -21866,50 +21851,6 @@ CanvasRenderer:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1563634750}
m_CullTransparentMesh: 1
--- !u!1 &1584263513
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1584263514}
- component: {fileID: 1584263515}
m_Layer: 0
m_Name: Line View
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &1584263514
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1584263513}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 72512886}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &1584263515
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1584263513}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 465bacc132ec6ce4e85f8e68354f60ad, type: 3}
m_Name:
m_EditorClassIdentifier:
--- !u!1 &1586904152
GameObject:
m_ObjectHideFlags: 0
@@ -21924,7 +21865,7 @@ GameObject:
- component: {fileID: 1586904156}
- component: {fileID: 1586904157}
m_Layer: 5
m_Name: Center Option
m_Name: Center Options
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
@@ -21937,12 +21878,12 @@ RectTransform:
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1586904152}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 1604842429}
m_Father: {fileID: 381795662}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 1}
@@ -22022,10 +21963,10 @@ MonoBehaviour:
m_GameObject: {fileID: 1586904152}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 144fae82f06c3c248b4fb76f6823baba, type: 3}
m_Script: {fileID: 11500000, guid: 8b56b42b68f74c719dd5f36a4696d61b, type: 3}
m_Name:
m_EditorClassIdentifier:
choiceButtonPrefab: {fileID: 2831695685783823246, guid: 7b38c32597bbad84e92958938ef655dd, type: 3}
choiceButtonPrefab: {fileID: 659956759807646603, guid: 4973083c3562511409a2ff2639fbe31b, type: 3}
--- !u!1001 &1592246586
PrefabInstance:
m_ObjectHideFlags: 0
@@ -22393,7 +22334,8 @@ GameObject:
- component: {fileID: 1604842428}
- component: {fileID: 1604842427}
- component: {fileID: 1604842426}
- component: {fileID: 1604842430}
- component: {fileID: 1604842431}
- component: {fileID: 1604842432}
m_Layer: 5
m_Name: Dialog Canvas
m_TagString: Untagged
@@ -22476,10 +22418,9 @@ RectTransform:
m_LocalScale: {x: 0, y: 0, z: 0}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 1318260398}
- {fileID: 1586904153}
- {fileID: 1403558893}
- {fileID: 238296903}
- {fileID: 381795662}
- {fileID: 1829169896}
- {fileID: 1977401367}
m_Father: {fileID: 1110722291}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
@@ -22487,7 +22428,7 @@ RectTransform:
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_Pivot: {x: 0, y: 0}
--- !u!114 &1604842430
--- !u!114 &1604842431
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
@@ -22496,13 +22437,23 @@ MonoBehaviour:
m_GameObject: {fileID: 1604842425}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: c14c52217dac70244b02fe48d9462bae, type: 3}
m_Script: {fileID: 11500000, guid: a38dd6a979b842b280fb73c921999a69, type: 3}
m_Name:
m_EditorClassIdentifier:
widthEstimation: {fileID: 1318260399}
blockDuration: 0.5
autoSkipDelay: 1
autoHideDuration: 0.2
lineView: {fileID: 1829169897}
optionView: {fileID: 381795663}
--- !u!225 &1604842432
CanvasGroup:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1604842425}
m_Enabled: 1
m_Alpha: 1
m_Interactable: 1
m_BlocksRaycasts: 1
m_IgnoreParentGroups: 0
--- !u!1 &1605070473
GameObject:
m_ObjectHideFlags: 0
@@ -22989,8 +22940,9 @@ GameObject:
serializedVersion: 6
m_Component:
- component: {fileID: 1612148020}
- component: {fileID: 1612148021}
m_Layer: 5
m_Name: Options
m_Name: Default Options
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
@@ -23003,7 +22955,7 @@ RectTransform:
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1612148019}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
@@ -23012,13 +22964,25 @@ RectTransform:
- {fileID: 515401844}
- {fileID: 2033425616}
- {fileID: 432383798}
m_Father: {fileID: 238296903}
m_Father: {fileID: 381795662}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &1612148021
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1612148019}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 14d86fd6c1664941a0c693acb51c6b4b, type: 3}
m_Name:
m_EditorClassIdentifier:
--- !u!1 &1620453319
GameObject:
m_ObjectHideFlags: 0
@@ -23402,6 +23366,7 @@ GameObject:
- component: {fileID: 1655147933}
- component: {fileID: 1655147932}
- component: {fileID: 1655147931}
- component: {fileID: 1655147934}
m_Layer: 0
m_Name: EventSystem
m_TagString: Untagged
@@ -23459,6 +23424,19 @@ Transform:
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &1655147934
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1655147930}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: f55689aa6dac4461bba273d8987762dd, type: 3}
m_Name:
m_EditorClassIdentifier:
isLocked: 0
--- !u!1 &1689237971
GameObject:
m_ObjectHideFlags: 0
@@ -24811,6 +24789,60 @@ CanvasRenderer:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1804770167}
m_CullTransparentMesh: 1
--- !u!1 &1829169895
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1829169896}
- component: {fileID: 1829169897}
m_Layer: 5
m_Name: Line View
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &1829169896
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1829169895}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 1318260398}
- {fileID: 1403558893}
- {fileID: 238296903}
m_Father: {fileID: 1604842429}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &1829169897
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1829169895}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: f0d1630fcebe4fb38afd0a2bc7b3112b, type: 3}
m_Name:
m_EditorClassIdentifier:
lineViewTypes: 000000000500000002000000
advanceInput: {fileID: 1977401368}
bubbleGroup: {fileID: 238296904}
--- !u!1 &1846916304
GameObject:
m_ObjectHideFlags: 0
@@ -25460,7 +25492,8 @@ MonoBehaviour:
yarnProject: {fileID: 0}
_variableStorage: {fileID: 314243163}
dialogueViews:
- {fileID: 1584263515}
- {fileID: 1829169897}
- {fileID: 381795663}
startNode: Start
startAutomatically: 0
runSelectedOptionAsLine: 0
@@ -26182,6 +26215,54 @@ CanvasRenderer:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1970860740}
m_CullTransparentMesh: 1
--- !u!1 &1977401366
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1977401367}
- component: {fileID: 1977401368}
m_Layer: 5
m_Name: Line Advance Input
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &1977401367
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1977401366}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 1604842429}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 100, y: 100}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &1977401368
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1977401366}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 4269da1f8c364e319da84b5fee61bafe, type: 3}
m_Name:
m_EditorClassIdentifier:
--- !u!1 &1982630668
GameObject:
m_ObjectHideFlags: 0
@@ -44561,7 +44642,7 @@ PrefabInstance:
objectReference: {fileID: 0}
- target: {fileID: 305064715333190683, guid: 2c1bcc3613815c74fb44cc1db21f524e, type: 3}
propertyPath: m_AnchoredPosition.y
value: -110
value: -70
objectReference: {fileID: 0}
- target: {fileID: 305064715333190683, guid: 2c1bcc3613815c74fb44cc1db21f524e, type: 3}
propertyPath: m_LocalEulerAnglesHint.x
@@ -44595,6 +44676,14 @@ PrefabInstance:
propertyPath: m_SizeDelta.x
value: 18.68
objectReference: {fileID: 0}
- target: {fileID: 6550843177228825060, guid: 2c1bcc3613815c74fb44cc1db21f524e, type: 3}
propertyPath: m_StringReference.m_TableEntryReference.m_KeyId
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6550843177228825060, guid: 2c1bcc3613815c74fb44cc1db21f524e, type: 3}
propertyPath: m_StringReference.m_TableReference.m_TableCollectionName
value: GUID:994c69bf4b2403043bc9562f2d24ee56
objectReference: {fileID: 0}
m_RemovedComponents: []
m_RemovedGameObjects: []
m_AddedGameObjects: []
@@ -55,7 +55,7 @@ namespace AibisDream
[YarnCommand("hide_dialog")]
public static void HideDialog()
{
DialogCanvasManager.Instance.HideDialog();
BubbleGroup.Instance.HideDialog();
}
[YarnCommand("fade_in")]
@@ -135,13 +135,6 @@ namespace AibisDream
return panel.FlashRed(duration);
}
[YarnCommand("switch_dialog_viewer")]
public static void SwitchDialogViewer(string viewerTypeStr)
{
var viewType = Enum.Parse<DialogViewType>(viewerTypeStr);
DialogCanvasManager.Instance.SwitchDialogView(viewType);
}
#endregion
}
}
+116 -28
View File
@@ -2,7 +2,6 @@ using System;
using AibisDream.Framework;
using AibisDream.Kit;
using UnityEngine;
using UnityEngine.Events;
using Yarn.Unity;
namespace AibisDream
@@ -12,15 +11,7 @@ namespace AibisDream
private DialogueRunner _dialogueRunner;
private LocalisedLineProvider _lineProvider;
# region controller状态标识
public bool quickRunMode;
public bool autoRunMode;
# endregion
public static UnityAction OnDialogueStart;
public static UnityAction OnDialogueComplete;
[SerializeField] private LineAdvanceInput lineAdvanceInput;
private void Start()
{
@@ -29,16 +20,47 @@ namespace AibisDream
_dialogueRunner.onDialogueStart.AddListener(() =>
{
EnumEventSystem.Global.Send(InteractionEventEnum.End);
OnDialogueStart?.Invoke();
EnumEventSystem.Global.Send(InteractionEventEnum.DialogStart);
});
_dialogueRunner.onDialogueComplete.AddListener(() =>
{
EnumEventSystem.Global.Send(InteractionEventEnum.Start);
OnDialogueComplete?.Invoke();
EnumEventSystem.Global.Send(InteractionEventEnum.DialogEnd);
});
}
private void OnEnable()
{
EnumEventSystem.Global.Register(GameLoopEnum.GameStart, ResetAdvanceMode);
EnumEventSystem.Global.Register(DialogEventEnum.OptionShow, OnOptionShow);
EnumEventSystem.Global.Register<DialogEventEnum, LineInfo>(DialogEventEnum.OptionSelected, OnOptionSelected);
}
private void OnDisable()
{
EnumEventSystem.Global.UnRegister(GameLoopEnum.GameStart, ResetAdvanceMode);
EnumEventSystem.Global.UnRegister(DialogEventEnum.OptionShow, OnOptionShow);
EnumEventSystem.Global.UnRegister<DialogEventEnum, LineInfo>(DialogEventEnum.OptionSelected, OnOptionSelected);
}
private void ResetAdvanceMode()
{
advanceMode = new AdvanceMode
{
isAuto = false,
isQuick = false
};
isInOption = false;
lineSyncToken = null;
Time.timeScale = 1f;
lineAdvanceInput.ResetAdvanceMode();
}
#region Yarn控制
/// <summary>
/// 开启对话
/// </summary>
@@ -50,17 +72,11 @@ namespace AibisDream
_dialogueRunner.StartDialogue("Start");
}
public string GetCurLocalizedTableName()
{
return _lineProvider.GetStringTableName();
}
public void StopDialog()
{
_dialogueRunner.Stop();
StorageSystem.Instance.Clear();
DialogCanvasManager.Instance.HideDialog();
DialogCanvasManager.Instance.SwitchDialogView(DialogViewType.StandardBubble);
DialogUIManager.Instance.HideDialog();
}
public void LoadDialog(YarnProject yarnProject)
@@ -78,7 +94,7 @@ namespace AibisDream
Debug.LogWarning($"对话正在运行中,无法启动新节点: {nodeName}");
return;
}
if (CheckIfNodeExistInCurrentYarnProject(nodeName))
{
_dialogueRunner.StartDialogue(nodeName);
@@ -100,15 +116,87 @@ namespace AibisDream
}
}
/// <summary>
/// 跳到下一句
/// </summary>
public void JumpLine()
#endregion
#region
public AdvanceMode advanceMode;
public void SwitchAutoMode()
{
if (!DialogCanvasManager.Instance.TrySkipLine())
advanceMode.isAuto = !advanceMode.isAuto;
lineAdvanceInput.SwitchAdvanceHandler(advanceMode.CurrentMode);
}
public void SwitchQuickMode()
{
advanceMode.isQuick = !advanceMode.isQuick;
lineAdvanceInput.SwitchAdvanceHandler(advanceMode.CurrentMode);
Time.timeScale = advanceMode.CurrentMode == AdvanceModeEnum.Quick ? 8f : 1f;
}
#endregion
public LineSyncToken lineSyncToken;
public bool isInOption;
public LineSyncState GetDialogState()
{
if (lineSyncToken != null && lineSyncToken.state != LineSyncState.Advanced)
{
DialogCanvasManager.Instance.NextStep();
return lineSyncToken.state;
}
else if (isInOption)
{
return LineSyncState.InOption;
}
else
{
return LineSyncState.Default;
}
}
private void OnOptionShow()
{
isInOption = true;
}
private void OnOptionSelected(LineInfo lineInfo)
{
isInOption = false;
}
}
public struct AdvanceMode
{
public bool isAuto;
public bool isQuick;
public AdvanceModeEnum CurrentMode
{
get
{
if (isQuick)
{
return AdvanceModeEnum.Quick;
}
else if (isAuto)
{
return AdvanceModeEnum.Auto;
}
else
{
return AdvanceModeEnum.Default;
}
}
}
}
public enum AdvanceModeEnum
{
Default,
Auto,
Quick
}
}
@@ -0,0 +1,143 @@
using System;
using AibisDream.Framework;
using UnityEngine;
namespace AibisDream
{
public class LineAdvanceInput : MonoBehaviour
{
#region
private LineSyncToken _curSyncToken;
private ILineAdvanceHandler _handler;
#endregion
private ILineAdvanceHandler _defaultHandler = new DefaultAdvanceHandler();
private ILineAdvanceHandler _quickHandler = new QuickAdvanceHandler();
private ILineAdvanceHandler _autoHandler = new AutoAdvanceHandler();
private void OnEnable()
{
ResetAdvanceMode();
}
public void RunLine(LineSyncToken lineSyncEvent)
{
_curSyncToken = lineSyncEvent;
}
private void Update()
{
_handler.Handle(_curSyncToken, IsInputAvailable);
}
public void SwitchAdvanceHandler(AdvanceModeEnum advanceMode)
{
_handler = advanceMode switch
{
AdvanceModeEnum.Auto => _autoHandler,
AdvanceModeEnum.Quick => _quickHandler,
AdvanceModeEnum.Default => _defaultHandler,
_ => _defaultHandler,
};
}
public void ResetAdvanceMode()
{
_handler = _defaultHandler;
}
#region
private bool IsInputAvailable()
{
return GameManager.Instance.state.IsInputAvailable()
&& _curSyncToken != null
&& _curSyncToken.state != LineSyncState.Advanced;
}
#endregion
}
public interface ILineAdvanceHandler
{
void Handle(LineSyncToken token, Func<bool> isAvailable);
static ILineAdvanceHandler Create(bool autoMode)
{
return autoMode ? new AutoAdvanceHandler() : new DefaultAdvanceHandler();
}
}
public class DefaultAdvanceHandler : ILineAdvanceHandler
{
public void Handle(LineSyncToken token, Func<bool> isAvailable)
{
if (Input.GetMouseButtonDown(0) || Input.GetKeyDown(KeyCode.Space))
{
if (isAvailable())
{
HandleInput(token);
}
}
}
private void HandleInput(LineSyncToken token)
{
switch (token.state)
{
case LineSyncState.PlayText:
token.TrySkip();
break;
case LineSyncState.WaitForAdvance:
token.TryAdvance();
break;
case LineSyncState.WaitForAutoAdvance:
token.TryAdvance();
break;
}
}
}
public class AutoAdvanceHandler : ILineAdvanceHandler
{
public void Handle(LineSyncToken token, Func<bool> isAvailable)
{
if (!isAvailable())
{
return;
}
// 如果已经可以继续了,就直接往下
if (token.state == LineSyncState.WaitForAutoAdvance)
{
token.TryAdvance();
}
}
}
public class QuickAdvanceHandler : ILineAdvanceHandler
{
public void Handle(LineSyncToken token, Func<bool> isAvailable)
{
if (!isAvailable())
{
return;
}
// 加速模式强制快进
if (token.state == LineSyncState.PlayText)
{
token.TrySkip();
}
// 如果已经可以继续了,就直接往下
if (token.state is LineSyncState.AdvanceDelay or LineSyncState.WaitForAdvance or LineSyncState.WaitForAutoAdvance)
{
token.ForceAdvance();
}
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 4269da1f8c364e319da84b5fee61bafe
timeCreated: 1761032421
@@ -0,0 +1,74 @@
using System;
using System.Collections.Generic;
using AibisDream.Utility;
using UnityEngine;
using Yarn.Unity;
namespace AibisDream
{
public class LineRunner : DialogueViewBase
{
[SerializeField] private DialogViewType[] lineViewTypes;
[SerializeField] private LineAdvanceInput advanceInput;
[SerializeField] private BubbleGroup bubbleGroup;
private readonly Dictionary<DialogViewType, ILineView> _screenViewDict = new();
public override void RunLine(LocalizedLine dialogueLine, Action onDialogueLineFinished)
{
LineSyncToken lineSyncEvent;
if (dialogueLine.GetCharacterVo().dialogViewType == DialogViewType.Screen)
{
// 自动推进视图
lineSyncEvent = LineSyncToken.CreateAuto(dialogueLine, onDialogueLineFinished);
DialogController.Instance.lineSyncToken = lineSyncEvent;
if (_screenViewDict.TryGetValue(DialogViewType.Screen, out var view))
{
view.RunLine(lineSyncEvent);
}
else
{
Debug.LogWarning($"未注册的视图类型: {dialogueLine.GetCharacterVo().dialogViewType}");
}
}
else if (dialogueLine.GetCharacterVo().dialogViewType == DialogViewType.Task)
{
lineSyncEvent = LineSyncToken.CreateImmediate(dialogueLine, onDialogueLineFinished);
DialogController.Instance.lineSyncToken = lineSyncEvent;
if (_screenViewDict.TryGetValue(DialogViewType.Task, out var view))
{
view.RunLine(lineSyncEvent);
}
else
{
Debug.LogWarning($"未注册的视图类型: {dialogueLine.GetCharacterVo().dialogViewType}");
}
}
else
{
// 手动推进视图
lineSyncEvent = LineSyncToken.CreateDefault(dialogueLine, onDialogueLineFinished);
DialogController.Instance.lineSyncToken = lineSyncEvent;
bubbleGroup.RunLine(lineSyncEvent);
}
// 最后交给推进处理
advanceInput.RunLine(lineSyncEvent);
}
public void RegisterView(DialogViewType dialogViewType, ILineView view)
{
_screenViewDict.Add(dialogViewType, view);
}
public void UnRegisterView(DialogViewType dialogViewType)
{
_screenViewDict.Remove(dialogViewType);
}
}
public interface ILineView
{
void RunLine(LineSyncToken token);
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: f0d1630fcebe4fb38afd0a2bc7b3112b
timeCreated: 1761032402
@@ -0,0 +1,220 @@
using System;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using AibisDream.Framework;
using AibisDream.Kit;
using AibisDream.Utility;
using UnityEngine;
using Yarn.Unity;
namespace AibisDream
{
public class LineSyncToken
{
private Action _nextStep;
private readonly ITextShown _textShown;
public LineInfo lineInfo;
public LineSyncState state;
public CancellationTokenSource AdvanceDelayToken { get; private set; }
public event Action SkipTextAnima;
public event Action OnAdvance;
public static LineSyncToken CreateAuto(LocalizedLine lineInfo, Action nextStep)
{
return new LineSyncToken(lineInfo, nextStep, new AutoNextTextShown());
}
public static LineSyncToken CreateImmediate(LocalizedLine lineInfo, Action nextStep)
{
return new LineSyncToken(lineInfo, nextStep, new ImmediateTextShown());
}
public static LineSyncToken CreateDefault(LocalizedLine lineInfo, Action nextStep)
{
return new LineSyncToken(lineInfo, nextStep, new DefaultTextShown());
}
public LineSyncToken(LocalizedLine lineInfo, Action nextStep, ITextShown textShown)
{
this.lineInfo = LineInfo.Generate(lineInfo);
_nextStep = nextStep;
_textShown = textShown;
}
public void TrySkip()
{
if (state == LineSyncState.PlayText)
{
SkipTextAnima?.Invoke();
SkipTextAnima = null;
}
else
{
Debug.Log($"line{lineInfo.lineId} 状态为{state}, 不能跳过文本");
}
}
public void TryAdvance()
{
if (state == LineSyncState.WaitForAdvance || state == LineSyncState.WaitForAutoAdvance)
{
Advance();
Dispose();
}
else
{
Debug.Log($"line{lineInfo.lineId} 状态为{state}, 不能向前推进");
}
}
public void ForceAdvance()
{
if (state != LineSyncState.Advanced)
{
// 先中断延时
AdvanceDelayToken?.Cancel();
// 推进
Advance();
Dispose();
}
}
private void Advance()
{
EnumEventSystem.Global.Send(DialogEventEnum.LineEnd);
OnAdvance?.Invoke();
OnAdvance = null;
_nextStep?.Invoke();
state = LineSyncState.Advanced;
}
private void Dispose()
{
_nextStep = null;
SkipTextAnima = null;
}
public async void TextShown()
{
AdvanceDelayToken = new CancellationTokenSource();
EnumEventSystem.Global.Send(DialogEventEnum.LineShown);
await _textShown.OnTextShown(this);
}
public void TextStart()
{
if (state != LineSyncState.Default)
{
Debug.LogWarning($"line{lineInfo.lineId} 状态为{state}, 不能开始文本");
return;
}
state = LineSyncState.PlayText;
EnumEventSystem.Global.Send(DialogEventEnum.LineStart, lineInfo);
}
}
public struct LineInfo
{
public string lineId;
public string lineText;
public CharacterVo character;
public bool isAutoSkip;
public bool isOption;
public static LineInfo Generate(LocalizedLine dialogueLine)
{
return new LineInfo
{
lineId = dialogueLine.TextID,
lineText = dialogueLine.TextWithoutCharacterName.Text,
character = dialogueLine.GetCharacterVo(),
isAutoSkip = dialogueLine.IsAutoSkipLine(),
isOption = false
};
}
public string GetRecordLine()
{
const string allowedTagsPattern = @"(<|{)(?!\/?(b|i|color)(?=>|\s|=))[^(>|})]+(>|})";
var res = Regex.Replace(lineText, allowedTagsPattern, "");
return res;
}
public int CalcAutoDelayTime()
{
var delayTime = lineText.RemoveRichTextTags().Length * ConstRef.CharacterDelayTime;
return CommonUtil.Limit(delayTime, ConstRef.LineMaxDelay, ConstRef.LineMinDelay);
}
public int CalcDelayTime()
{
return ConstRef.FixedDelay;
}
}
public interface ITextShown
{
Task OnTextShown(LineSyncToken token);
}
public class DefaultTextShown : ITextShown
{
public async Task OnTextShown(LineSyncToken token)
{
try
{
token.state = LineSyncState.AdvanceDelay;
await Task.Delay(token.lineInfo.CalcDelayTime(), token.AdvanceDelayToken.Token);
token.state = LineSyncState.WaitForAdvance;
await Task.Delay(token.lineInfo.CalcAutoDelayTime(), token.AdvanceDelayToken.Token);
token.state = LineSyncState.WaitForAutoAdvance;
}
catch (TaskCanceledException)
{
// 跳过,无事发生
}
}
}
public class AutoNextTextShown : ITextShown
{
public async Task OnTextShown(LineSyncToken token)
{
try
{
token.state = LineSyncState.AdvanceDelay;
await Task.Delay(token.lineInfo.CalcDelayTime(), token.AdvanceDelayToken.Token);
token.state = LineSyncState.WaitForAutoAdvance;
token.TryAdvance();
}
catch (TaskCanceledException)
{
// 跳过,无事发生
}
}
}
public class ImmediateTextShown : ITextShown
{
public async Task OnTextShown(LineSyncToken token)
{
token.state = LineSyncState.WaitForAdvance;
}
}
public enum LineSyncState
{
Default,
PlayText,
AdvanceDelay,
WaitForAdvance,
WaitForAutoAdvance,
Advanced,
// 仅限DialogController使用
InOption
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: fc70491af0c642d28147d3dbf6a70ca6
timeCreated: 1761551427
-65
View File
@@ -1,65 +0,0 @@
using System;
using AibisDream.Framework;
using AibisDream.Utility;
using UnityEngine;
using Yarn.Unity;
namespace AibisDream
{
public class LineView : DialogueViewBase
{
public override void RunLine(LocalizedLine dialogueLine, Action onDialogueLineFinished)
{
string lineId = dialogueLine.TextID;
string shortText = dialogueLine.TextWithoutCharacterName.Text.Length > 30
? dialogueLine.TextWithoutCharacterName.Text.Substring(0, 30) + "..."
: dialogueLine.TextWithoutCharacterName.Text;
Debug.Log($"[对话流程] [{lineId}] ===== 开始处理 =====");
Debug.Log($"[对话流程] [{lineId}] 文本内容: {shortText}");
EnumEventSystem.Global.Send(DialogEventEnum.LineStart, DialogText.GetLine(dialogueLine));
HandleLineOutput(dialogueLine, onDialogueLineFinished);
if (DialogController.Instance.quickRunMode)
{
Debug.Log($"[快速模式] [{lineId}] ===== 快速处理开始 =====");
// 快速模式:直接跳过文本显示并继续
bool skipResult = DialogCanvasManager.Instance.TrySkipLine(true);
Debug.Log($"[快速模式] [{lineId}] TrySkipLine结果: {skipResult}");
EnumEventSystem.Global.Send(DialogEventEnum.LineShown);
Debug.Log($"[快速模式] [{lineId}] LineShown事件已发送");
DialogCanvasManager.Instance.NextStep();
Debug.Log($"[快速模式] [{lineId}] NextStep已调用");
Debug.Log($"[快速模式] [{lineId}] ===== 快速处理完成 =====");
}
else
{
Debug.Log($"[正常模式] [{lineId}] 等待用户交互");
}
Debug.Log($"[对话流程] [{lineId}] ===== 处理完成 =====");
}
private void HandleLineOutput(LocalizedLine dialogueLine, Action onDialogueLineFinished)
{
string lineId = dialogueLine.TextID;
Debug.Log($"[文本显示] [{lineId}] 开始显示文本");
DialogCanvasManager.Instance.ShowLine(dialogueLine.TextWithoutCharacterName.Text,
dialogueLine.GetCharacterVo(), onDialogueLineFinished, dialogueLine.TextID,
dialogueLine.IsAutoSkipLine());
}
public override void RunOptions(DialogueOption[] dialogueOptions, Action<int> onOptionSelected)
{
Debug.Log($"[选项显示] ===== 显示 {dialogueOptions.Length} 个选项 =====");
EnumEventSystem.Global.Send(DialogEventEnum.OptionShow);
var options = DialogOption.GeneOptions(dialogueOptions, onOptionSelected);
DialogCanvasManager.Instance.ShowOptions(options);
}
}
}
@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 465bacc132ec6ce4e85f8e68354f60ad
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,33 @@
using System;
using AibisDream.Framework;
using UnityEngine;
using Yarn.Unity;
namespace AibisDream
{
public class OptionView : DialogueViewBase
{
[SerializeField] private DefaultOptions defaultOptions;
[SerializeField] private CenterOptions centerOptions;
public override void RunOptions(DialogueOption[] dialogueOptions, Action<int> onOptionSelected)
{
EnumEventSystem.Global.Send(DialogEventEnum.OptionShow);
var options = DialogOption.GeneOptions(dialogueOptions, onOptionSelected);
var viewType = options[0].Character.dialogViewType;
switch (viewType)
{
case DialogViewType.Default:
defaultOptions.ShowOptions(options);
break;
case DialogViewType.CenterOption:
centerOptions.ShowOptions(options);
break;
default:
Debug.Log($"选项{options[0].Character.key}没有找到选项框");
break;
}
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 56ee480f25a146839afa8ff058ddfc7a
timeCreated: 1761032377
@@ -220,7 +220,7 @@ namespace AibisDream
private void RegisterDialogEvents()
{
// 监听对话结束事件
DialogController.OnDialogueComplete += OnDialogueComplete;
EnumEventSystem.Global.Register(InteractionEventEnum.DialogEnd, OnDialogueComplete);
}
/// <summary>
@@ -250,10 +250,7 @@ namespace AibisDream
/// </summary>
private void OnDestroy()
{
if (DialogController.Instance != null)
{
DialogController.OnDialogueComplete -= OnDialogueComplete;
}
EnumEventSystem.Global.UnRegister(InteractionEventEnum.DialogEnd, OnDialogueComplete);
}
#endregion
@@ -1,4 +1,5 @@
using UnityEngine;
using AibisDream.Framework;
using UnityEngine;
using DG.Tweening;
using AibisDream.Kit;
@@ -50,14 +51,14 @@ namespace AibisDream.FixSystem
private void OnEnable()
{
DialogController.OnDialogueStart += HandleDialogueStart;
DialogController.OnDialogueComplete += HandleDialogueComplete;
EnumEventSystem.Global.Register(InteractionEventEnum.DialogEnd, HandleDialogueComplete);
EnumEventSystem.Global.Register(InteractionEventEnum.DialogStart, HandleDialogueStart);
}
private void OnDisable()
{
DialogController.OnDialogueStart -= HandleDialogueStart;
DialogController.OnDialogueComplete -= HandleDialogueComplete;
EnumEventSystem.Global.UnRegister(InteractionEventEnum.DialogEnd, HandleDialogueComplete);
EnumEventSystem.Global.UnRegister(InteractionEventEnum.DialogStart, HandleDialogueStart);
}
private void InitComponentRefs()
@@ -149,7 +150,6 @@ namespace AibisDream.FixSystem
private void HandleDialogueComplete()
{
Debug.Log("Dialog End");
isInDialog = false;
}
@@ -171,7 +171,6 @@ namespace AibisDream.FixSystem
// 加载气泡
var data = FixSystemCenter.SystemDic.Get<ScreenSystem>().BubbleSlotGroup.CollectData();
BubbleGroup.Instance.LoadBubbles(data);
DialogCanvasManager.Instance.SwitchDialogView(DialogViewType.StandardBubble);
// 开启交互
bodyModuleSystem.EnableSystem();
@@ -1,10 +1,11 @@
using System;
using System.Collections;
using AibisDream.Framework;
using AibisDream.Kit;
namespace AibisDream.FixSystem
{
public class FixSystemCenter : Kit.Singleton<FixSystemCenter>
public class FixSystemCenter : Singleton<FixSystemCenter>
{
public FixState CurState => StateMachine.CurState;
@@ -1,24 +1,26 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using AibisDream.Framework;
using AibisDream.Kit;
using AibisDream.Utility;
using DG.Tweening;
using Febucci.UI;
using Febucci.UI.Core;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
namespace AibisDream.FixSystem
{
public class ScreenSystem : MonoBehaviour, IDialogView
public class ScreenSystem : MonoBehaviour, ILineView
{
#region
[SerializeField] private TMP_Text title;
[SerializeField] private RectTransform textRoot;
[SerializeField] private TMP_Text textForEstimation;
[SerializeField] private int maxLineNum = 10;
private GameObject _textItemPrefab;
private Queue<TypewriterByCharacter> _lineQueue;
@@ -26,8 +28,6 @@ namespace AibisDream.FixSystem
public TaskScreen TaskScreen { get; private set; }
public int maxLineNum = 10;
#endregion
private void Awake()
@@ -47,15 +47,15 @@ namespace AibisDream.FixSystem
private void Register()
{
FixSystemCenter.SystemDic.Register(this);
DialogCanvasManager.Instance.RegisterDialogView(DialogViewType.Screen, this);
DialogCanvasManager.Instance.RegisterDialogView(DialogViewType.Task, TaskScreen);
DialogUIManager.Instance.RegisterScreenView(DialogViewType.Screen, this);
DialogUIManager.Instance.RegisterScreenView(DialogViewType.Task, TaskScreen);
}
private void OnDestroy()
{
FixSystemCenter.SystemDic.Unregister<ScreenSystem>();
DialogCanvasManager.Instance.UnregisterDialogView(DialogViewType.Screen);
DialogCanvasManager.Instance.UnregisterDialogView(DialogViewType.Task);
DialogUIManager.Instance.UnRegisterScreenView(DialogViewType.Screen);
DialogUIManager.Instance.UnRegisterScreenView(DialogViewType.Task);
}
#region
@@ -64,7 +64,7 @@ namespace AibisDream.FixSystem
{
title.text = targetTitle;
}
public void ClearTextScreen()
{
while (_lineQueue.Count > 0)
@@ -72,7 +72,7 @@ namespace AibisDream.FixSystem
var text = _lineQueue.Dequeue();
Destroy(text.gameObject);
}
ShowTitle(string.Empty);
}
@@ -83,85 +83,57 @@ namespace AibisDream.FixSystem
#endregion
#region
public void ShowLine(string dialogLine, CharacterVo character, Action nextStep, string lineId, bool isAutoSkip = false)
public void RunLine(LineSyncToken token)
{
Debug.Log($"[ScreenSystem] ShowLine - 原始文本: '{dialogLine}'");
if (string.IsNullOrWhiteSpace(dialogLine))
// 空格延长一点避免报错
if (string.IsNullOrWhiteSpace(token.lineInfo.lineText))
{
dialogLine = " ";
// Debug.Log("[ScreenSystem] ShowLine - 空文本被替换为空格");
token.lineInfo.lineText = " ";
}
ShowTitle(character.GetActorName());
// 显示标题
ShowTitle(token.lineInfo.character.GetActorName());
// 显示文本
TypewriterCore textItemTypewriter = AddText(token.lineInfo.lineText);
textItemTypewriter.SetTypewriterSpeed(GetTextSpeedValue());
textItemTypewriter.onTextShowed.AddListener(() => OnTextShown(token, textItemTypewriter));
token.TextStart();
// 强制更新布局
LayoutRebuilder.ForceRebuildLayoutImmediate(textRoot);
}
private float GetTextSpeedValue()
{
var textSpeedStr = SettingLoader.Instance.TryRead("TextSpeed", out string textSpeed) ? textSpeed : "1";
return float.TryParse(textSpeedStr, NumberStyles.Float, CultureInfo.InvariantCulture, out float result) ? result : 1f;
}
private void OnTextShown(LineSyncToken syncToken, TypewriterCore typewriter)
{
typewriter.onTextShowed.RemoveAllListeners();
syncToken.TextShown();
}
private TypewriterByCharacter AddText(string newLine)
{
// 生成新文本组件
var textItem = Instantiate(_textItemPrefab, textRoot);
var textItemTypewriter = textItem.GetComponent<TypewriterByCharacter>();
// 估算文本高度
var newLineNum = EstimateLineNum(dialogLine);
var newLineNum = EstimateLineNum(newLine);
var oldLineNum = CalcTotalLineNum();
if (newLineNum + oldLineNum > maxLineNum)
{
Destroy(_lineQueue.Dequeue().gameObject);
}
_lineQueue.Enqueue(textItemTypewriter);
// 播放文本
textItemTypewriter.ShowText(dialogLine);
textItemTypewriter.onTextShowed.AddListener(() => AfterLineShown(textItemTypewriter, nextStep));
// 强制更新布局
LayoutRebuilder.ForceRebuildLayoutImmediate(textRoot);
Debug.Log($"[ScreenSystem] ShowLine - 文本播放开始,nextStep是否为null: {nextStep == null}");
textItemTypewriter.ShowText(newLine);
return textItemTypewriter;
}
private void AfterLineShown(TypewriterByCharacter typewriter, Action nextStop)
{
Debug.Log("[ScreenSystem] AfterLineShown - 文本显示完成");
Debug.Log($"[ScreenSystem] AfterLineShown - nextStop是否为null: {nextStop == null}");
EnumEventSystem.Global.Send(DialogEventEnum.LineShown);
ActionKit.Delay(0.1f, () =>
{
Debug.Log("[ScreenSystem] AfterLineShown - 延迟结束,调用回调");
EnumEventSystem.Global.Send(DialogEventEnum.LineEnd);
nextStop.Invoke();
Debug.Log("[ScreenSystem] AfterLineShown - 回调调用完成");
}).StartGlobal();
typewriter.onTextShowed.RemoveAllListeners();
}
public void ShowOptions(DialogOption[] dialogueOptions)
{
Debug.Log("不能在显示屏显示对话");
}
public void HideDialog()
{
// HideDialog应该由其他函数控制
}
public bool TrySkipLine(bool isAutoSkip)
{
// 这里不能跳过对话
return true;
}
public void NextStep()
{
// 这里不能手动跳到下一行
}
public void OnLocalizationChanged(string value)
{
// 屏幕不需要本地化
}
#endregion
private int EstimateLineNum(string text)
{
textForEstimation.text = text;
@@ -1,7 +1,5 @@
using System;
using System.Collections.Generic;
using AibisDream.Framework;
using AibisDream.Kit;
using AibisDream.Utility;
using TMPro;
using UnityEngine;
@@ -9,7 +7,7 @@ using UnityEngine.UI;
namespace AibisDream
{
public class TaskScreen : MonoBehaviour, IDialogView
public class TaskScreen : MonoBehaviour, ILineView
{
#region
@@ -24,74 +22,6 @@ namespace AibisDream
_taskListParent = transform.Find("Record");
_taskItemPrefab = ResourceKit.LoadAssetSync<GameObject>(ConstRef.TaskItemName);
}
#region
// TODO 随时切换回头再加,先直接赋值
// public void ShowLine(string dialogLine, CharacterVo character, Action nextStep, string lineId, bool isAutoSkip = false)
// {
// var taskItem = Instantiate(_taskItemPrefab, _taskListParent);
// // 设置本地化数据
//
// var localize = taskItem.GetComponent<LocalizedText>();
// localize.SetLocalizedText(DialogController.Instance.GetCurLocalizedTableName(), lineId);
// _taskDict[lineId] = localize;
//
// EnumEventSystem.Global.Send(DialogEventEnum.LineShown);
// EnumEventSystem.Global.Send(DialogEventEnum.LineEnd);
// nextStep.Invoke();
// LayoutRebuilder.ForceRebuildLayoutImmediate(_taskListParent.GetComponent<RectTransform>());
// }
public void ShowLine(string dialogLine, CharacterVo character, Action nextStep, string lineId,
bool isAutoSkip = false)
{
if (_taskDict.ContainsKey(lineId))
{
EnumEventSystem.Global.Send(DialogEventEnum.LineShown);
EnumEventSystem.Global.Send(DialogEventEnum.LineEnd);
nextStep.Invoke();
return;
}
var taskItem = Instantiate(_taskItemPrefab, _taskListParent);
var task = taskItem.GetComponent<TMP_Text>();
task.text = $"\u25cf {dialogLine}";
_taskDict[lineId] = taskItem;
EnumEventSystem.Global.Send(DialogEventEnum.LineShown);
EnumEventSystem.Global.Send(DialogEventEnum.LineEnd);
nextStep.Invoke();
LayoutRebuilder.ForceRebuildLayoutImmediate(_taskListParent.GetComponent<RectTransform>());
}
public void ShowOptions(DialogOption[] dialogueOptions)
{
Debug.Log("Task 面板不能显示选项");
}
public void HideDialog()
{
// 无法隐藏
}
public bool TrySkipLine(bool isForceSkip = false)
{
// 直接继续不跳过
return true;
}
public void NextStep()
{
// 这里不能手动跳到下一行
}
public void OnLocalizationChanged(string value)
{
// TODO 有需要可以调整文本
}
#endregion
public void CompleteTask(string lineId)
{
@@ -109,5 +39,25 @@ namespace AibisDream
}
_taskDict.Clear();
}
public void RunLine(LineSyncToken token)
{
if (_taskDict.ContainsKey(token.lineInfo.lineId))
{
EnumEventSystem.Global.Send(DialogEventEnum.LineShown);
token.ForceAdvance();
return;
}
var taskItem = Instantiate(_taskItemPrefab, _taskListParent);
var task = taskItem.GetComponent<TMP_Text>();
task.text = $"\u25cf {token.lineInfo.lineText}";
token.TextStart();
_taskDict[token.lineInfo.lineId] = taskItem;
token.TextShown();
token.ForceAdvance();
LayoutRebuilder.ForceRebuildLayoutImmediate(_taskListParent.GetComponent<RectTransform>());
}
}
}
@@ -11,7 +11,7 @@ using STOP_MODE = FMOD.Studio.STOP_MODE;
namespace AibisDream.Kit
{
public class AudioManager : Singleton<AudioManager>, IAudioManager
public class AudioManager : Singleton<AudioManager>
{
private const string AmbStateName = "scene";
@@ -46,14 +46,14 @@ namespace AibisDream.Kit
private void RegisterEvent()
{
// 语音相关
_removeTrigger.Add(EnumEventSystem.Global.Register<DialogEventEnum, DialogText>(DialogEventEnum.LineStart, OnLineStart));
_removeTrigger.Add(EnumEventSystem.Global.Register<DialogEventEnum, LineInfo>(DialogEventEnum.LineStart, OnLineStart));
_removeTrigger.Add(EnumEventSystem.Global.Register(DialogEventEnum.LineShown, OnLineShown));
// 场景切换相关
_removeTrigger.Add(EnumEventSystem.Global.Register<EventEnum, string>(EventEnum.SceneLoad, OnSceneLoad));
_removeTrigger.Add(EnumEventSystem.Global.Register<EventEnum, FixState>(EventEnum.FixStateSwitch, OnFixStateChange));
_removeTrigger.Add(EnumEventSystem.Global.Register(GameLoopEnum.GameQuit, OnGameQuit));
}
private void RegisterData()
{
// 注册数据
@@ -247,7 +247,7 @@ namespace AibisDream.Kit
#endregion
public void OnLineStart(DialogText dialogText)
public void OnLineStart(LineInfo dialogText)
{
if (_voiceInstance.IsPlaying())
{
@@ -255,12 +255,12 @@ namespace AibisDream.Kit
_voiceInstance.release();
}
if (string.IsNullOrEmpty(dialogText.actor.voicePath) || !FModEx.IsEventExist(dialogText.actor.VoicePath))
if (string.IsNullOrEmpty(dialogText.character.voicePath) || !FModEx.IsEventExist(dialogText.character.VoicePath))
{
return;
}
_voiceInstance = RuntimeManager.CreateInstance(dialogText.actor.VoicePath);
_voiceInstance = RuntimeManager.CreateInstance(dialogText.character.VoicePath);
_voiceInstance.start();
}
+2 -1
View File
@@ -84,6 +84,7 @@ namespace AibisDream.Kit
{
Aside,
Player,
MainActor
MainActor,
Center
}
}
+12 -1
View File
@@ -88,12 +88,23 @@ namespace AibisDream.Framework
if (!_eventDict.TryGetValue(typeof(T), out var e)) return;
if (e.Length <= kv || e[kv] == null) return;
if (e[kv] is EasyEvent tempEvent)
{
tempEvent.UnRegister(onEvent);
}
}
public void UnRegister<T, TE>(T key, Action<TE> onEvent) where T : IConvertible
{
var kv = key.ToInt32(null);
if (!_eventDict.TryGetValue(typeof(T), out var e)) return;
if (e.Length <= kv || e[kv] == null) return;
if (e[kv] is EasyEvent<TE> tempEvent)
{
tempEvent.UnRegister(onEvent);
}
}
public void UnRegister<T>(T key) where T : IConvertible
{
@@ -1,76 +1,120 @@
using AibisDream.Kit;
using System.Collections.Generic;
using AibisDream.Kit;
using UnityEngine;
namespace AibisDream.Framework
{
public class EventSystemEx : SingletonBase<EventSystemEx>
public class EventSystemEx : Singleton<EventSystemEx>
{
#region
public bool isLocked;
#endregion
public GameObject pointerOverObj;
public GameObject draggingObj;
public GameObject holdingObj;
private List<GameObject> pointerOverObjList;
private List<GameObject> draggingObjList;
private List<GameObject> holdingObjList;
#region
public void OnPointerEnter(IInteraction interaction)
{
pointerOverObj = interaction.GetGameObject();
EnumEventSystem.Global.Send(TriggerEnum.PointerEnter, interaction);
if (!pointerOverObjList.Contains(interaction.GetGameObject()))
{
pointerOverObjList.Add(interaction.GetGameObject());
}
}
public void OnPointerExit(IInteraction interaction)
{
if (pointerOverObj == interaction.GetGameObject())
{
EnumEventSystem.Global.Send(TriggerEnum.PointerExit, interaction);
pointerOverObj = null;
}
pointerOverObjList.Remove(interaction.GetGameObject());
}
public void OnPointerDown(IInteraction interaction)
{
EnumEventSystem.Global.Send(TriggerEnum.PointerDown, interaction);
holdingObj = interaction.GetGameObject();
if (!holdingObjList.Contains(interaction.GetGameObject()))
{
holdingObjList.Add(interaction.GetGameObject());
}
}
public void OnPointerUp(IInteraction interaction)
{
if (holdingObj == interaction.GetGameObject())
holdingObjList.Remove(interaction.GetGameObject());
}
public void OnDrag(IInteraction interaction)
{
if (!draggingObjList.Contains(interaction.GetGameObject()))
{
EnumEventSystem.Global.Send(TriggerEnum.PointerUp, interaction);
holdingObj = null;
draggingObjList.Add(interaction.GetGameObject());
}
}
public void OnEndDrag(IInteraction interaction)
{
draggingObjList.Remove(interaction.GetGameObject());
}
public void OnBeginDrag(IInteraction interaction)
{
if (!draggingObjList.Contains(interaction.GetGameObject()))
{
draggingObjList.Add(interaction.GetGameObject());
}
}
public TriggerEnum GetPointerState()
{
if (holdingObjList.Count > 0 || draggingObjList.Count > 0)
{
return TriggerEnum.Dragging;
}
else if (pointerOverObjList.Count > 0)
{
return TriggerEnum.PointerOver;
}
else
{
return TriggerEnum.None;
}
}
#endregion
#region
#region
public override void OnSingletonInit()
{
pointerOverObjList = new List<GameObject>();
draggingObjList = new List<GameObject>();
holdingObjList = new List<GameObject>();
EnumEventSystem.Global.Register(GameLoopEnum.GameStart, ClearAll);
EnumEventSystem.Global.Register(GameLoopEnum.GameQuit, ClearAll);
}
#endregion
#region
private EventSystemEx()
private void ClearAll()
{
pointerOverObjList.Clear();
draggingObjList.Clear();
holdingObjList.Clear();
}
public override void OnSingletonDestroy()
{
EnumEventSystem.Global.UnRegister(GameLoopEnum.GameStart, ClearAll);
EnumEventSystem.Global.UnRegister(GameLoopEnum.GameQuit, ClearAll);
}
#endregion
}
public enum TriggerEnum
{
PointerEnter,
PointerExit,
PointerDown,
PointerUp
None,
Dragging,
PointerOver
}
}
@@ -102,6 +102,24 @@ namespace AibisDream.Framework
base.OnPointerUp(eventData);
}
}
public override void OnDrag(PointerEventData eventData)
{
EventSystemEx.Instance.OnDrag(_interaction);
base.OnDrag(eventData);
}
public override void OnEndDrag(PointerEventData eventData)
{
EventSystemEx.Instance.OnEndDrag(_interaction);
base.OnEndDrag(eventData);
}
public override void OnBeginDrag(PointerEventData eventData)
{
EventSystemEx.Instance.OnEndDrag(_interaction);
base.OnBeginDrag(eventData);
}
}
public interface IInteraction
-3
View File
@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 9a9cfd121f9a45c0a72e5f056e7ce308
timeCreated: 1732358305
@@ -1,16 +0,0 @@
using UnityEngine;
namespace AibisDream.Framework
{
public interface IMoveable
{
bool IsBlock { get; }
void StartMove();
void Move(Vector2 mousePos);
void StopMove();
}
}
@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: c5c7b28802d266d499177b7fa8f9f2cd
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -1,74 +0,0 @@
using UnityEngine;
namespace AibisDream.Framework
{
public class MoveableSystem : IMonoKit
{
private bool _isDragging;
private IMoveable _dragObj;
private Vector3 _offset;
private readonly Camera _camera = Camera.main;
public void OnUpdate()
{
// 鼠标按下
if (Input.GetMouseButtonDown(0))
{
OnMouseClickDown();
}
// 鼠标按住
if (Input.GetMouseButton(0) && _isDragging)
{
OnMouseHolding();
}
// 鼠标松开
if (Input.GetMouseButtonUp(0))
{
OnMouseClickUp();
}
}
private void OnMouseClickDown()
{
// 按下时发出检查射线
Ray ray = _camera.ScreenPointToRay(Input.mousePosition);
RaycastHit2D hit = Physics2D.Raycast(ray.origin, ray.direction);
// 检测命中的物体
if (hit.collider && hit.collider.CompareTag("Moveable"))
{
_dragObj = hit.collider.gameObject.GetComponent<IMoveable>();
if (_dragObj == null) return;
if (_dragObj.IsBlock) return;
_dragObj.StartMove();
_offset = hit.collider.transform.position - GetMouseAsWorldPoint();
_isDragging = true;
}
}
private void OnMouseHolding()
{
_dragObj.Move(GetMouseAsWorldPoint() + _offset);
}
private void OnMouseClickUp()
{
if (!_isDragging) return;
_dragObj?.StopMove();
_dragObj = null;
_isDragging = false;
}
private Vector3 GetMouseAsWorldPoint()
{
Vector3 mousePoint = Input.mousePosition;
mousePoint.z = _camera.nearClipPlane;
return _camera.ScreenToWorldPoint(mousePoint);
}
}
}
@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 5d755460ba0142f39c5677d8f948c777
timeCreated: 1732358554
@@ -16,6 +16,8 @@ namespace AibisDream.Framework
public static LocalizationTable ActorTable { get; private set; }
public static Locale CurrentLocale => LocalizationSettings.SelectedLocale;
static LocalizationKit()
{
#if UNITY_EDITOR
@@ -23,9 +25,15 @@ namespace AibisDream.Framework
#else
_paramTable = new LocalizationTable(ParamTableName);
ActorTable = new LocalizationTable(ActorTableName);
LocalizationSettings.SelectedLocaleChanged += OnLocaleChanged;
#endif
}
private static void OnLocaleChanged(Locale locale)
{
EnumEventSystem.Global.Send(SettingChangeEvent.LocaleChanged, locale);
}
#if UNITY_EDITOR
private static void OnPlayModeChanged(PlayModeStateChange playMode)
{
@@ -36,6 +44,7 @@ namespace AibisDream.Framework
ActorTable?.Dispose();
_paramTable = new LocalizationTable(ParamTableName);
ActorTable = new LocalizationTable(ActorTableName);
LocalizationSettings.SelectedLocaleChanged += OnLocaleChanged;
}
else if (playMode == PlayModeStateChange.ExitingPlayMode)
{
@@ -43,27 +52,28 @@ namespace AibisDream.Framework
ActorTable?.Dispose();
_paramTable = null;
ActorTable = null;
LocalizationSettings.SelectedLocaleChanged -= OnLocaleChanged;
}
}
#endif
public static async void SwitchLanguage(string localeCode)
{
// 等待本地化系统初始化完成
await LocalizationSettings.InitializationOperation.Task;
var selectedLocale =
LocalizationSettings.AvailableLocales.Locales.Find(locale => locale.Identifier.Code == localeCode);
public static async void SwitchLanguage(string localeCode)
{
// 等待本地化系统初始化完成
await LocalizationSettings.InitializationOperation.Task;
if (selectedLocale)
{
LocalizationSettings.SelectedLocale = selectedLocale;
var selectedLocale =
LocalizationSettings.AvailableLocales.Locales.Find(locale => locale.Identifier.Code == localeCode);
if (selectedLocale)
{
LocalizationSettings.SelectedLocale = selectedLocale;
}
else
{
Debug.LogWarning($"Locale with code {localeCode} not found.");
}
}
else
{
Debug.LogWarning($"Locale with code {localeCode} not found.");
}
}
/// <summary>
/// 本地化参数
@@ -75,7 +85,7 @@ namespace AibisDream.Framework
{
// 非本地化参数直接返回
if (!param.StartsWith(LocalizationPrefix)) return param;
var localizationKey = param[LocalizationPrefix.Length..];
// 获取本地化值
if (table.TryGetValue(localizationKey, out var value))
@@ -87,7 +97,7 @@ namespace AibisDream.Framework
Debug.LogWarning($"Variable Key '{localizationKey}' not found in localization table.");
return localizationKey;
}
/// <summary>
/// 本地化参数
/// </summary>
@@ -97,18 +107,18 @@ namespace AibisDream.Framework
{
return LocalizeParam(param, _paramTable);
}
public static string GetL10NParamKey(string key)
{
// 本地化参数则去除前缀,非本地化参数直接返回
return key.StartsWith(LocalizationPrefix) ? key[LocalizationPrefix.Length..] : key;
}
/// <summary>
/// 确保本地化系统已初始化
/// </summary>
/// <returns>初始化操作</returns>
public static async System.Threading.Tasks.Task EnsureInitialized()
public static async void EnsureInitialized()
{
await LocalizationSettings.InitializationOperation.Task;
}
@@ -127,16 +137,16 @@ namespace AibisDream.Framework
Debug.Log($"开始初始化表格{tableName}");
InitializeAsync();
}
private async void InitializeAsync()
{
// 等待本地化系统初始化完成
await LocalizationSettings.InitializationOperation.Task;
_stringTable = LocalizationSettings.StringDatabase.GetTable(TableName);
LocalizationSettings.SelectedLocaleChanged += OnLocaleChanged;
_isInitialized = true;
Debug.Log($"表格{TableName}已成功加载");
}
@@ -23,7 +23,6 @@ namespace AibisDream.Framework
{
_iocContainer ??= new IOCContainer();
// 在这里添加相应的工具
Register(new MoveableSystem());
Register(new TransTest());
}
+8 -2
View File
@@ -35,8 +35,8 @@ namespace AibisDream
public enum InteractionEventEnum
{
Start,
End
DialogStart,
DialogEnd
}
public struct DialogText
@@ -69,4 +69,10 @@ namespace AibisDream
{
VariableSet
}
public enum SettingChangeEvent
{
TextSpeed,
LocaleChanged
}
}
+70 -3
View File
@@ -18,6 +18,8 @@ namespace AibisDream
{
#region
public GameLoopState state;
private TalkSceneSO[] _totalSceneSos;
public RunMode runMode;
@@ -129,7 +131,7 @@ namespace AibisDream
// 音频全部暂停
AudioManager.Instance.PauseAll();
// 关闭Dialog
DialogCanvasManager.Instance.CloseCanvas();
DialogUIManager.Instance.CloseCanvas();
}
public void ContinueGame()
@@ -141,7 +143,7 @@ namespace AibisDream
// 音频继续
AudioManager.Instance.UnPauseAll();
// 打开Dialog
DialogCanvasManager.Instance.OpenCanvas();
DialogUIManager.Instance.OpenCanvas();
}
public void QuitGame()
@@ -177,7 +179,7 @@ namespace AibisDream
// 音频继续
AudioManager.Instance.UnPauseAll();
// 打开Dialog
DialogCanvasManager.Instance.OpenCanvas();
DialogUIManager.Instance.OpenCanvas();
yield return UIManager.Instance.GetPanel<PlayToolPanel>().FadeOutAsync();
}
@@ -240,6 +242,44 @@ namespace AibisDream
{
return _currentTalkSceneSo.Value.name;
}
#region
private IUnRegister[] _unRegisters;
private void OnEnable()
{
RegisterEvents();
}
private void OnDisable()
{
UnRegisterEvents();
}
private void RegisterEvents()
{
_unRegisters = new IUnRegister[6];
_unRegisters[0] = EnumEventSystem.Global.Register(GameLoopEnum.GameStart, () => state.OnGame(true));
_unRegisters[1] = EnumEventSystem.Global.Register(GameLoopEnum.PauseGame, () => state.OnPause(true));
_unRegisters[2] = EnumEventSystem.Global.Register(GameLoopEnum.GameQuit, () => state.OnGame(false));
_unRegisters[3] = EnumEventSystem.Global.Register(GameLoopEnum.UnPauseGame, () => state.OnPause(false));
_unRegisters[4] = EnumEventSystem.Global.Register(InteractionEventEnum.DialogStart, () => state.OnDialog(true));
_unRegisters[5] = EnumEventSystem.Global.Register(InteractionEventEnum.DialogEnd, () => state.OnDialog(false));
}
private void UnRegisterEvents()
{
foreach (var unRegister in _unRegisters)
{
unRegister.UnRegister();
}
}
#endregion
}
/// <summary>
@@ -287,6 +327,33 @@ namespace AibisDream
}
}
public struct GameLoopState
{
public bool isInGame;
public bool isInDialog;
public bool isInPause;
public void OnGame(bool isInGame)
{
this.isInGame = isInGame;
}
public void OnPause(bool isInPause)
{
this.isInPause = isInPause;
}
public void OnDialog(bool isInDialog)
{
this.isInDialog = isInDialog;
}
public bool IsInputAvailable()
{
return isInGame && isInDialog && !isInPause;
}
}
public enum RunMode
{
Product,
+14 -6
View File
@@ -3,7 +3,6 @@ using System.Globalization;
using AibisDream.Framework;
using AibisDream.Kit;
using UnityEngine;
using UnityEngine.Localization.Settings;
namespace AibisDream
{
@@ -13,7 +12,7 @@ namespace AibisDream
public class SettingLoader
{
private static readonly string SettingPath = Application.streamingAssetsPath + "/Config/setting.json";
private readonly ConfigContainer _container;
private SettingLoader()
@@ -25,6 +24,11 @@ namespace AibisDream
_container.OnWrite += OnSettingChanged;
}
private void Dispose()
{
_container.OnWrite -= OnSettingChanged;
}
private void LoadAllSetting()
{
var settingConfig = _container.ReadAll();
@@ -34,7 +38,7 @@ namespace AibisDream
}
}
private async void OnSettingChanged(string propName, string value)
private void OnSettingChanged(string propName, string value)
{
// 配置项同步
switch (propName)
@@ -43,7 +47,7 @@ namespace AibisDream
AudioManager.Instance.SetVolume(float.Parse(value, CultureInfo.InvariantCulture));
break;
case "TextSpeed":
// TODO 调整文字速度
EnumEventSystem.Global.Send(SettingChangeEvent.TextSpeed, value);
break;
case "Resolution":
// TODO 调整分辨率
@@ -54,7 +58,6 @@ namespace AibisDream
break;
case "Language":
// 确保本地化系统已初始化
await LocalizationSettings.InitializationOperation.Task;
LocalizationKit.SwitchLanguage(value);
break;
default:
@@ -77,13 +80,18 @@ namespace AibisDream
{
return _container.ReadAll();
}
#region
public static SettingLoader Instance { get; private set; }
public static void Init()
{
if (Instance != null)
{
Instance.Dispose();
Instance = null;
}
Instance = new SettingLoader();
}
+4 -4
View File
@@ -40,8 +40,8 @@ namespace AibisDream
_trigger = GetComponent<EventTriggerEx>();
_trigger.Register(EventTriggerType.Drag, OnDrag);
_trigger.Register(EventTriggerType.BeginDrag, StartMove);
_trigger.Register(EventTriggerType.EndDrag, StopMove);
_trigger.Register(EventTriggerType.PointerDown, StartMove);
_trigger.Register(EventTriggerType.PointerUp, StopMove);
}
private void Start()
@@ -108,10 +108,10 @@ namespace AibisDream
transform.DOPause();
}
public void StopMove(BaseEventData eventData)
private void StopMove(BaseEventData eventData)
{
// 正常情况下不会出错
if (eventData is not PointerEventData pointerData) return;
if (eventData is not PointerEventData) return;
if (targetShaft)
{
+2 -2
View File
@@ -68,8 +68,8 @@ namespace AibisDream
private void OnEnable()
{
var unRegister1 = EnumEventSystem.Global.Register(InteractionEventEnum.Start, () => _isInteractive = true);
var unRegister2 = EnumEventSystem.Global.Register(InteractionEventEnum.End, () => _isInteractive = false);
var unRegister1 = EnumEventSystem.Global.Register(InteractionEventEnum.DialogEnd, () => _isInteractive = true);
var unRegister2 = EnumEventSystem.Global.Register(InteractionEventEnum.DialogStart, () => _isInteractive = false);
_evtUnRegisters = new[] { unRegister1, unRegister2 };
}
-1
View File
@@ -13,7 +13,6 @@ namespace AibisDream
public override void OnSingletonInit()
{
// 加载气泡
DialogCanvasManager.Instance.SwitchDialogView(DialogViewType.StandardBubble);
BubbleGroup.Instance.LoadBubbles(bubbleSlotGroup.CollectData());
}
@@ -46,6 +46,11 @@ namespace AibisDream
_stringEvent.SetEntry(getBool.Invoke() ? data.trueKey : data.falseKey);
}
}
public void FreshState()
{
AfterClick();
}
}
[Serializable]
+59 -264
View File
@@ -1,42 +1,18 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using AibisDream.Framework;
using AibisDream.Framework;
using AibisDream.Kit;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
namespace AibisDream
{
public class CursorManager : Singleton<CursorManager>
{
private const float DelayTime = 0.1f;
[SerializeField] private GameObject border;
[SerializeField]
private GameObject border;
[Header("指针图片")] public Sprite defaultCursor;
public Sprite nextTalk, talking, option, interactive, holding, disable;
private Image _cursor;
private GraphicRaycaster _raycaster;
private Sprite _curCursor;
private CursorState _stateCache;
#region
private Coroutine _switchCoroutine;
private CursorState _curState = CursorState.Default;
private bool _isTalking;
private bool _isInGame;
#endregion
// 卸载时注销事件
private readonly List<IUnRegister> _unRegisters = new();
private void Start()
{
@@ -48,147 +24,12 @@ namespace AibisDream
private void InitCursor()
{
Cursor.visible = false;
SwitchCursor(defaultCursor);
}
private void OnEnable()
{
RegisterEvent();
}
private void OnDisable()
{
// 注销所有事件
foreach (var eventUnRegister in _unRegisters)
{
eventUnRegister.UnRegister();
}
_unRegisters.Clear();
_cursor.sprite = defaultCursor;
}
private void InitRefs()
{
_cursor = transform.Find("Cursor").GetComponent<Image>();
_raycaster = UIManager.Instance.Canvas.GetComponent<GraphicRaycaster>();
}
private void RegisterEvent()
{
// 此处监听所有可能对鼠标状态产生影响的事件
RegisterGameEvent();
RegisterDialogEvent();
RegisterTriggerEvent();
}
private void RegisterGameEvent()
{
_unRegisters.Add(EnumEventSystem.Global.Register(GameLoopEnum.GameStart, OnGameStart));
_unRegisters.Add(EnumEventSystem.Global.Register(GameLoopEnum.GameQuit, OnGameQuit));
_unRegisters.Add(EnumEventSystem.Global.Register(GameLoopEnum.PauseGame, OnPauseGame));
_unRegisters.Add(EnumEventSystem.Global.Register(GameLoopEnum.UnPauseGame, OnUnPauseGame));
}
private void OnGameStart()
{
_isInGame = true;
}
private void OnUnPauseGame()
{
_curState = _stateCache;
_stateCache = CursorState.Default;
_isInGame = true;
}
private void OnPauseGame()
{
_stateCache = _curState;
_curState = CursorState.Default;
_isInGame = false;
}
private void OnGameQuit()
{
_curCursor = defaultCursor;
_curState = CursorState.Default;
_stateCache = CursorState.Default;
_isInGame = false;
}
private void RegisterDialogEvent()
{
// 对话相关
_unRegisters.Add(EnumEventSystem.Global.Register<DialogEventEnum, DialogText>(DialogEventEnum.LineStart,
OnLineStart));
_unRegisters.Add(EnumEventSystem.Global.Register(DialogEventEnum.LineShown, () => SwitchCursor(nextTalk)));
_unRegisters.Add(EnumEventSystem.Global.Register(DialogEventEnum.LineEnd, OnLineEnd));
_unRegisters.Add(EnumEventSystem.Global.Register(DialogEventEnum.OptionShow, OnOptionShow));
_unRegisters.Add(
EnumEventSystem.Global.Register<DialogEventEnum, DialogText>(DialogEventEnum.OptionSelected,
OnOptionSelect));
}
private void RegisterTriggerEvent()
{
// 交互相关
_unRegisters.Add(EnumEventSystem.Global.Register(InteractionEventEnum.Start, OnInteractiveStart));
_unRegisters.Add(EnumEventSystem.Global.Register(InteractionEventEnum.End, OnInteractiveEnd));
_unRegisters.Add(
EnumEventSystem.Global.Register<TriggerEnum, IInteraction>(TriggerEnum.PointerEnter, OnPointerEnter));
_unRegisters.Add(
EnumEventSystem.Global.Register<TriggerEnum, IInteraction>(TriggerEnum.PointerExit, OnPointerExit));
_unRegisters.Add(
EnumEventSystem.Global.Register<TriggerEnum, IInteraction>(TriggerEnum.PointerDown, OnPointerDown));
_unRegisters.Add(
EnumEventSystem.Global.Register<TriggerEnum, IInteraction>(TriggerEnum.PointerUp, OnPointerUp));
}
private void Update()
{
UpdateCursor();
HandleDialog();
}
private void UpdateCursor()
{
// 再判断是不是浮在可交互物上
_cursor.sprite = !_isInGame || IsOverSelected() ? defaultCursor : _curCursor;
}
private void HandleDialog()
{
if (!_isInGame) return;
if (!Input.GetMouseButtonDown(0) && !Input.GetKeyDown(KeyCode.Space)) return;
// 控制对话
if (_isTalking)
{
DialogController.Instance.JumpLine();
}
}
private bool IsOverSelected()
{
if (!EventSystem.current.IsPointerOverGameObject())
{
return false;
}
var eventData = new PointerEventData(EventSystem.current)
{
position = Input.mousePosition
};
var results = new List<RaycastResult>();
_raycaster.Raycast(eventData, results);
return results.Count > 0 && results.Any(result => result.gameObject.CompareTag("Selectable"));
}
private void LateUpdate()
@@ -197,134 +38,88 @@ namespace AibisDream
// RectTransformUtility.ScreenPointToLocalPointInRectangle(_cursorCanvas, Input.mousePosition,
// CameraKit.Instance.uiCamera, out var worldPos);
// 判断当前要用什么样的指针
_cursor.rectTransform.position = Input.mousePosition;
// 在输入状态,要单独处理
var cursorState = CheckCursorState();
_cursor.sprite = GetCursorSprite(cursorState);
}
#region
private void OnLineStart(DialogText line)
private CursorStateEnum CheckCursorState()
{
_isTalking = true;
SwitchCursor(talking);
}
var gameState = GameManager.Instance.state;
private void OnLineEnd()
{
StopDelayCursor();
_switchCoroutine = StartCoroutine(DelayAction(() =>
if (!gameState.isInGame || gameState.isInPause)
{
_isTalking = false;
_curCursor = defaultCursor;
}));
}
private void OnOptionShow()
{
_isTalking = true;
SwitchCursor(option);
}
private void OnOptionSelect(DialogText line)
{
StopDelayCursor();
_switchCoroutine = StartCoroutine(DelayAction(() =>
// 非游戏中显示默认指针
return CursorStateEnum.Default;
}
else if (UIManager.Instance.IsOverRegion("MainUI"))
{
_isTalking = false;
_curCursor = defaultCursor;
}));
}
#endregion
#region
private void OnInteractiveStart()
{
_curState = CursorState.Interactive;
if (EventSystemEx.Instance.pointerOverObj)
// 游戏中鼠标移至右上角Main Panel时显示默认指针
return CursorStateEnum.Default;
}
else if (gameState.isInDialog)
{
SwitchCursor(interactive);
// 处理对话中的指针
var dialogState = DialogController.Instance.GetDialogState();
return HandleDialogState(dialogState);
}
else
{
// 非对话处理指针交互
var triggerEnum = EventSystemEx.Instance.GetPointerState();
return HandleDraggingState(triggerEnum);
}
}
private void OnInteractiveEnd()
private CursorStateEnum HandleDialogState(LineSyncState dialogState)
{
_curState = CursorState.Default;
// 退出时把Cursor置为Default
SwitchCursor(defaultCursor);
}
private void OnPointerEnter(IInteraction target)
{
if (_curState == CursorState.Interactive && !_isTalking)
return dialogState switch
{
// 如果不可交互,就显示不可交互的指针
SwitchCursor(target.IsActive ? interactive : disable);
}
LineSyncState.Default => CursorStateEnum.Default,
LineSyncState.PlayText => CursorStateEnum.PlayText,
LineSyncState.AdvanceDelay => CursorStateEnum.PlayText,
LineSyncState.WaitForAdvance => CursorStateEnum.WaitForAdvance,
LineSyncState.WaitForAutoAdvance => CursorStateEnum.WaitForAdvance,
LineSyncState.Advanced => CursorStateEnum.Default,
LineSyncState.InOption => CursorStateEnum.InOption,
_ => CursorStateEnum.Default,
};
}
private void OnPointerExit(IInteraction target)
private CursorStateEnum HandleDraggingState(TriggerEnum triggerEnum)
{
if (_curState == CursorState.Interactive && !_isTalking)
return triggerEnum switch
{
SwitchCursor(defaultCursor);
}
TriggerEnum.Dragging => CursorStateEnum.Dragging,
TriggerEnum.PointerOver => CursorStateEnum.PointerOver,
_ => CursorStateEnum.Default,
};
}
private void OnPointerDown(IInteraction target)
private Sprite GetCursorSprite(CursorStateEnum cursorState)
{
if (_curState == CursorState.Interactive && !_isTalking)
return cursorState switch
{
SwitchCursor(target.IsActive ? holding : defaultCursor);
}
}
private void OnPointerUp(IInteraction target)
{
if (_curState == CursorState.Interactive && !_isTalking)
{
// 如果松手时还在物体之上
SwitchCursor(EventSystemEx.Instance.holdingObj == target.GetGameObject() ? interactive : defaultCursor);
}
}
#endregion
#region
/// <summary>
/// 直接切指针
/// </summary>
/// <param name="sprite">指针图片</param>
private void SwitchCursor(Sprite sprite)
{
StopDelayCursor();
_curCursor = sprite;
}
private void StopDelayCursor()
{
if (_switchCoroutine != null)
{
StopCoroutine(_switchCoroutine);
_switchCoroutine = null;
}
}
#endregion
private static IEnumerator DelayAction(Action action)
{
yield return new WaitForSeconds(DelayTime);
action.Invoke();
CursorStateEnum.Default => defaultCursor,
CursorStateEnum.PlayText => talking,
CursorStateEnum.WaitForAdvance => nextTalk,
CursorStateEnum.InOption => option,
CursorStateEnum.Dragging => holding,
CursorStateEnum.PointerOver => interactive,
_ => defaultCursor,
};
}
}
public enum CursorState
public enum CursorStateEnum
{
Default,
Interactive
PlayText,
WaitForAdvance,
InOption,
Dragging,
PointerOver
}
}
+49 -10
View File
@@ -1,5 +1,5 @@
using System;
using System.Text.RegularExpressions;
using System.Globalization;
using AibisDream.Framework;
using AibisDream.Kit;
using AibisDream.Utility;
@@ -10,7 +10,7 @@ using UnityEngine.UI;
namespace AibisDream
{
public class Bubble : MonoBehaviour
public class Bubble : MonoBehaviour, IBubble
{
private TypewriterCore _typewriter;
private TMP_Text _actorName;
@@ -24,16 +24,19 @@ namespace AibisDream
#region
[SerializeField] public ActorRole role;
[SerializeField] public int idx;
[Header("参数")]
[SerializeField] private ActorRole role;
[SerializeField] private int idx;
[SerializeField] private int maxWidth;
[SerializeField] private int minWidth;
public ActorRole Role => role;
public int Idx => idx;
#endregion
public event Action<Bubble> OnDisposed;
public bool IsShowingText => _typewriter.isShowingText;
public event Action OnLineShown;
public void LoadConfig(BubbleSlotData data)
{
@@ -47,6 +50,15 @@ namespace AibisDream
rect.localPosition = UIManager.GetDialogUIPos(data.slotPosition);
// 设置style
SetStyle(data.bubbleStyle, data.pivotType);
// 注册事件
_typewriter.onTextShowed.AddListener(InvokeLineShown);
EnumEventSystem.Global.Register<SettingChangeEvent, string>(SettingChangeEvent.TextSpeed, OnTextSpeedChanged);
}
private void InvokeLineShown()
{
OnLineShown?.Invoke();
OnLineShown = null;
}
private void SetStyle(BubbleStyle bubbleStyle, PivotType pivotType)
@@ -65,9 +77,19 @@ namespace AibisDream
_rect.pivot = CommonUtil.GetPivotByType(pivotType);
var spritePath = bubbleStyle.bubbleSpriteAddress.EndsWith("]")
? $"{bubbleStyle.bubbleSpriteAddress}"
: $"{bubbleStyle.bubbleSpriteAddress}[{pivotType.ToString()}]";
: $"{bubbleStyle.bubbleSpriteAddress}[{pivotType}]";
_bubbleImage.sprite = ResourceKit.LoadAssetSync<Sprite>(spritePath);
// 初始化文字速度
var speedStr = SettingLoader.Instance.TryRead("TextSpeed", out string textSpeed) ? textSpeed : "1";
OnTextSpeedChanged(speedStr);
}
private void OnTextSpeedChanged(string value)
{
float speed = float.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out float result) ? result : 1f;
_typewriter.SetTypewriterSpeed(speed);
}
private void InitRefs()
@@ -102,11 +124,16 @@ namespace AibisDream
_typewriter.ShowText(line);
}
public void SkipLine()
public bool SkipLine()
{
if (_typewriter.isShowingText)
{
_typewriter.SkipTypewriter();
return true;
}
else
{
return false;
}
}
@@ -118,6 +145,7 @@ namespace AibisDream
public void Dispose()
{
Hide();
_typewriter.onTextShowed.RemoveAllListeners();
OnDisposed?.Invoke(this);
OnDisposed = null;
}
@@ -125,8 +153,7 @@ namespace AibisDream
private void HandleLayout(string line)
{
// 先去除富文本标签
line = Regex.Replace(line.Replace("<br>", "\n"), "[<|{].*?[>|}]", string.Empty);
var width = DialogCanvasManager.Instance.EstimateTextWidth(line, _lineText.fontSize);
var width = BubbleGroup.Instance.EstimateTextWidth(line.RemoveRichTextTags(), _lineText.fontSize);
if (width > maxWidth)
{
_layoutElement.preferredWidth = maxWidth;
@@ -172,4 +199,16 @@ namespace AibisDream
}
#endif
}
public interface IBubble
{
public ActorRole Role { get; }
public int Idx { get; }
public event Action OnLineShown;
public void ShowActorName(CharacterVo characterVo);
public void ShowLine(string line);
public bool SkipLine();
public void Hide();
}
}
+58 -143
View File
@@ -1,59 +1,35 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using AibisDream.Framework;
using AibisDream.Kit;
using AibisDream.Utility;
using TMPro;
using UnityEngine;
namespace AibisDream
{
public class BubbleGroup : Singleton<BubbleGroup>, IDialogView
public class BubbleGroup : Singleton<BubbleGroup>, ILineView
{
private BubbleOption[] _options;
private Dictionary<ActorRole, Bubble[]> _bubbleDict;
public DialogViewType CurDialogType { get; private set; }
[SerializeField] private TMP_Text widthEstimation;
[SerializeField] private CenterBubble centerBubble;
private Dictionary<ActorRole, Bubble[]> _bubbleDict = new();
private BubbleFactory _bubbleFactory;
private SimpleObjectPool<Bubble> _bubblePool;
private SimpleObjectPool<BubbleOption> _optionPool;
#region
private Action _nextStep;
private Bubble _curBubble;
private IUnRegister _unRegister;
#endregion
private CancellationTokenSource _autoHideToken;
#region
public override void OnSingletonInit()
{
// 注册泡泡
_unRegister =
EnumEventSystem.Global.Register<DialogEventEnum, DialogText>(DialogEventEnum.OptionSelected,
_ => HideOptions());
// 工厂
_bubbleFactory = new BubbleFactory(transform.Find("Bubbles"));
// 加载选项
InitOptions();
}
private void Start()
{
HideDialog();
}
public override void OnSingletonDestroy()
{
_unRegister.UnRegister();
_bubbleFactory = new BubbleFactory(transform);
}
public void LoadBubbles(BubbleSlotGroupData groupData)
{
CurDialogType = groupData.dialogViewType;
// 回收旧泡泡
foreach (var oldBubble in _bubbleDict.Values.SelectMany(item => item))
{
@@ -63,79 +39,61 @@ namespace AibisDream
// 加载新泡泡
_bubbleDict = groupData.bubbleSlots
.Select(item => _bubbleFactory.Create(item))
.GroupBy(item => item.role)
.GroupBy(item => item.Role)
.ToDictionary(group => group.Key, group => group.ToArray());
// 更新选项的位置
if (groupData.bubbleOptionSlots is { Length: 0 })
{
return;
}
foreach (var optionSlotData in groupData.bubbleOptionSlots)
{
if (optionSlotData.optionIdx >= _options.Length) continue;
_options[optionSlotData.optionIdx].LoadData(optionSlotData);
}
}
private void InitOptions()
{
_options = transform.Find("Options")
.GetComponentsInChildren<BubbleOption>(true)
.OrderBy(item => item.optionIdx)
.ToArray();
_bubbleDict = new Dictionary<ActorRole, Bubble[]>();
}
#endregion
#region
#region
public void ShowLine(string dialogLine, CharacterVo character, Action nextStep, string lineId,
bool isAutoSkip = false)
public void RunLine(LineSyncToken syncToken)
{
Debug.Log($"[BubbleGroup] ShowLine - 开始显示对话: {lineId}");
Debug.Log($"[BubbleGroup] ShowLine - nextStep是否为null: {nextStep == null}");
// 先中断原来的事件
_autoHideToken?.Cancel();
_autoHideToken = null;
gameObject.SetActive(true);
var character = syncToken.lineInfo.character;
if (TryGetBubble(character.role, character.bubbleIdx, out var bubble))
{
// 注册事件
bubble.OnLineShown += syncToken.TextShown;
syncToken.SkipTextAnima += () => bubble.SkipLine();
syncToken.OnAdvance += AfterAdvance;
// 播放文字
bubble.ShowActorName(character);
bubble.ShowLine(dialogLine);
bubble.ShowLine(syncToken.lineInfo.lineText);
syncToken.TextStart();
// 将非选定的Bubble隐藏
HideDialog(bubble);
}
else
{
Debug.LogWarning($"{character.GetActorName()}的Role没有对应Bubble");
return;
Debug.LogWarning($"{character.GetActorName()}的Role {character.role}没有对应Bubble");
HideDialog();
}
// 保留信息
_nextStep = nextStep;
_curBubble = bubble;
Debug.Log($"[BubbleGroup] ShowLine - 设置完成,_nextStep是否为null: {_nextStep == null}");
}
public float EstimateTextWidth(string text, float fontSize)
{
widthEstimation.fontSize = fontSize;
widthEstimation.text = text;
widthEstimation.ForceMeshUpdate();
return widthEstimation.preferredWidth;
}
public void ShowOptions(DialogOption[] dialogueOptions)
private async void AfterAdvance()
{
HideDialog();
var availableOptions = dialogueOptions.Where(item => item.IsAvailable).ToArray();
// 如果仅由一个选项
if (availableOptions.Length == 1)
_autoHideToken = new CancellationTokenSource();
try
{
_options[0].ShowOption(availableOptions[0]);
await Task.Delay(ConstRef.AutoHideDelay, _autoHideToken.Token);
HideDialog();
}
else
catch (TaskCanceledException)
{
for (var i = 0; i < availableOptions.Length; i++)
{
_options[i + 1].ShowOption(availableOptions[i]);
}
// 忽略取消
}
}
@@ -146,73 +104,36 @@ namespace AibisDream
textBubble.Hide();
}
HideOptions();
centerBubble.Hide();
}
public bool TrySkipLine(bool isForceSkip = false)
{
if (!_curBubble)
{
return true;
}
if (_curBubble && _curBubble.IsShowingText)
{
_curBubble.SkipLine();
return true;
}
return false;
}
public void NextStep()
{
Debug.Log($"[BubbleGroup] NextStep - _nextStep是否为null: {_nextStep == null}");
if (_nextStep == null)
{
Debug.Log("[BubbleGroup] NextStep - _nextStep为null,提前返回");
return;
}
Debug.Log("[BubbleGroup] NextStep - 发送LineEnd事件");
EnumEventSystem.Global.Send(DialogEventEnum.LineEnd);
var next = _nextStep;
_nextStep = null;
_curBubble?.Hide();
_curBubble = null;
Debug.Log("[BubbleGroup] NextStep - 调用回调");
next?.Invoke();
Debug.Log("[BubbleGroup] NextStep - 回调调用完成");
}
public void OnLocalizationChanged(string value)
{
}
#endregion
private void HideDialog(Bubble activeBubble)
private void HideDialog(IBubble activeBubble)
{
foreach (var textBubble in _bubbleDict.Values.SelectMany(inner => inner))
{
if (activeBubble != textBubble)
if (activeBubble != (IBubble)textBubble)
{
textBubble.Hide();
}
}
HideOptions();
if (activeBubble != (IBubble)centerBubble)
{
centerBubble.Hide();
}
}
private bool TryGetBubble(ActorRole role, int idx, out Bubble bubble)
private bool TryGetBubble(ActorRole role, int idx, out IBubble bubble)
{
if (role == ActorRole.Center)
{
bubble = centerBubble;
return true;
}
if (_bubbleDict.TryGetValue(role, out var bubbles))
{
bubble = bubbles.FirstOrDefault(item => item.idx == idx);
bubble = bubbles.FirstOrDefault(item => item.Idx == idx);
return bubble != null;
}
@@ -220,12 +141,6 @@ namespace AibisDream
return false;
}
private void HideOptions()
{
foreach (var option in _options)
{
option.Hide();
}
}
#endregion
}
}
@@ -1,4 +1,5 @@
using TMPro;
using System;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
@@ -17,12 +18,7 @@ namespace AibisDream
_button = GetComponent<Button>();
}
public void LoadData(BubbleOptionSlotData data)
{
((RectTransform)transform).localPosition = UIManager.GetDialogUIPos(data.slotPosition);
}
public void ShowOption(DialogOption dialogOption)
public void ShowOption(DialogOption dialogOption, Action hide)
{
gameObject.SetActive(true);
_button.onClick.RemoveAllListeners();
@@ -32,6 +28,7 @@ namespace AibisDream
_text.text = dialogOption.Line;
_button.onClick.AddListener(() =>
{
hide?.Invoke();
dialogOption.Select();
});
}
@@ -0,0 +1,62 @@
using System;
using AibisDream.Kit;
using Febucci.UI;
using UnityEngine;
namespace AibisDream
{
public class CenterBubble : MonoBehaviour, IBubble
{
[SerializeField] private TypewriterByCharacter dialogText;
public ActorRole Role => ActorRole.Center;
public int Idx => 0;
public event Action OnLineShown;
private void OnEnable()
{
dialogText.onTextShowed.AddListener(InvokeLineShown);
}
private void OnDisable()
{
dialogText.onTextShowed.RemoveAllListeners();
}
private void InvokeLineShown()
{
OnLineShown?.Invoke();
OnLineShown = null;
}
public void ShowActorName(CharacterVo characterVo)
{
// 不显示名称
}
public void ShowLine(string line)
{
dialogText.TextAnimator.SetText("");
gameObject.SetActive(true);
dialogText.ShowText(line);
}
public bool SkipLine()
{
if (dialogText.isShowingText)
{
dialogText.SkipTypewriter();
return true;
}
else
{
return false;
}
}
public void Hide()
{
gameObject.SetActive(false);
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 67e53e476f874efd9d847b50dc16d6c8
timeCreated: 1761206826
@@ -1,80 +0,0 @@
using System;
using AibisDream.Framework;
using AibisDream.Kit;
using AibisDream.Utility;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
namespace AibisDream
{
public class CenterOption : MonoBehaviour, IDialogView
{
#region
public GameObject choiceButtonPrefab;
#endregion
private TextParam _textParam;
private void Awake()
{
EnumEventSystem.Global.Register<DialogEventEnum, DialogText>(DialogEventEnum.OptionSelected,
_ => HideDialog());
}
public void ShowLine(string dialogLine, CharacterVo character, Action nextStep, string lineId, bool isAutoSkip = false)
{
Debug.Log("CenterOption只显示选项");
}
public void ShowOptions(DialogOption[] dialogueOptions)
{
gameObject.SetActive(true);
// 销毁原来的按钮
foreach (Transform child in transform)
{
Destroy(child.gameObject);
}
// 生成新按钮
foreach (var option in dialogueOptions)
{
if (!option.IsAvailable) continue;
var choiceInstance = Instantiate(choiceButtonPrefab, transform);
var optionText = choiceInstance.GetComponentInChildren<TextMeshProUGUI>();
optionText.text = option.Line;
optionText.characterSpacing = _textParam.charSpace;
choiceInstance.GetComponent<Button>().onClick.AddListener(() =>
{
HideDialog();
option.Select();
});
}
}
public void HideDialog()
{
gameObject.SetActive(false);
}
public bool TrySkipLine(bool isForceSkip)
{
// 无法跳过
return true;
}
public void NextStep()
{
// 无法继续
}
public void OnLocalizationChanged(string value)
{
_textParam = JsonUtil.ReadBeanByText<TextParam>(value);
}
}
}
@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 144fae82f06c3c248b4fb76f6823baba
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,42 @@
using TMPro;
using UnityEngine;
using UnityEngine.UI;
namespace AibisDream
{
public class CenterOptions : MonoBehaviour
{
public GameObject choiceButtonPrefab;
public void ShowOptions(DialogOption[] dialogOptions)
{
gameObject.SetActive(true);
// 销毁原来的按钮
foreach (Transform child in transform)
{
Destroy(child.gameObject);
}
// 生成新按钮
foreach (var option in dialogOptions)
{
if (!option.IsAvailable) continue;
var choiceInstance = Instantiate(choiceButtonPrefab, transform);
var optionText = choiceInstance.GetComponentInChildren<TextMeshProUGUI>();
optionText.text = option.Line;
choiceInstance.GetComponent<Button>().onClick.AddListener(() =>
{
HideOptions();
option.Select();
});
}
}
public void HideOptions()
{
gameObject.SetActive(false);
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 8b56b42b68f74c719dd5f36a4696d61b
timeCreated: 1761218547
-97
View File
@@ -1,97 +0,0 @@
using System;
using AibisDream.Framework;
using AibisDream.Kit;
using AibisDream.Utility;
using Febucci.UI;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
namespace AibisDream
{
public class CenterText : MonoBehaviour, IDialogView
{
#region
private TypewriterByCharacter _dialogText;
private Image _panel;
private Action _nextStep;
#endregion
private TextParam _textParam;
private void Awake()
{
InitComponents();
}
private void InitComponents()
{
_dialogText = transform.Find("Dialog Text")?.gameObject.GetComponent<TypewriterByCharacter>();
}
public void ShowLine(string dialogLine, CharacterVo character, Action nextStep, string lineId, bool isAutoSkip = false)
{
// 把原有对话清掉
ClearBox();
_dialogText.gameObject.SetActive(true);
// 显示内容
_dialogText.ShowText(dialogLine);
// 自动跳过的回调很难独立Remove,只能全部清空再注册,下策
_dialogText.onTextShowed.RemoveAllListeners();
_dialogText.onTextShowed.AddListener(() => EnumEventSystem.Global.Send(DialogEventEnum.LineShown));
_nextStep = nextStep;
}
public void ShowOptions(DialogOption[] dialogueOptions)
{
// 不能出选项
}
public void HideDialog()
{
gameObject.SetActive(false);
}
public bool TrySkipLine(bool isForceSkip)
{
if (_dialogText.isShowingText)
{
_dialogText.SkipTypewriter();
return true;
}
return false;
}
public void NextStep()
{
if (_nextStep == null) return;
ClearBox();
EnumEventSystem.Global.Send(DialogEventEnum.LineEnd);
var next = _nextStep;
_nextStep = null;
next.Invoke();
}
public void OnLocalizationChanged(string value)
{
_textParam = JsonUtil.ReadBeanByText<TextParam>(value);
var tmp = _dialogText.GetComponent<TMP_Text>();
// 修改对话文本
tmp.characterSpacing = _textParam.charSpace;
}
private void ClearBox()
{
gameObject.SetActive(true);
_dialogText?.TextAnimator.SetText("");
}
}
}
@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: d6722100b986b0f42994441d3c0aa9e7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,48 @@
using System.Linq;
using AibisDream.Framework;
using UnityEngine;
namespace AibisDream
{
public class DefaultOptions : MonoBehaviour
{
private BubbleOption[] _options;
private void Awake()
{
_options = transform.GetComponentsInChildren<BubbleOption>(true)
.OrderBy(item => item.optionIdx)
.ToArray();
HideOptions();
EnumEventSystem.Global.Register<DialogEventEnum, LineInfo>(DialogEventEnum.OptionSelected,
_ => HideOptions());
}
public void ShowOptions(DialogOption[] dialogueOptions)
{
HideOptions();
var availableOptions = dialogueOptions.Where(item => item.IsAvailable).ToArray();
// 如果仅由一个选项
if (availableOptions.Length == 1)
{
_options[0].ShowOption(availableOptions[0], HideOptions);
}
else
{
for (var i = 0; i < availableOptions.Length; i++)
{
_options[i + 1].ShowOption(availableOptions[i], HideOptions);
}
}
}
public void HideOptions()
{
foreach (var option in _options)
{
option.Hide();
}
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 14d86fd6c1664941a0c693acb51c6b4b
timeCreated: 1761217326
-212
View File
@@ -1,212 +0,0 @@
using System;
using AibisDream.Framework;
using AibisDream.Kit;
using AibisDream.Utility;
using Febucci.UI;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
namespace AibisDream
{
public class DialogBox : MonoBehaviour, IDialogView
{
#region box组件名称
private const string ActorName = "Actor Name";
private const string DialogText = "Dialog Text";
private const string NextArray = "Next Array";
private const string ChoiceBox = "Choice Box";
#endregion
#region box组件
private TypewriterByCharacter _dialogText;
private TextMeshProUGUI _actorName;
private GameObject _nextArray;
private GameObject _choiceBox;
#endregion
private TextParam _textParam;
private Action _nextStep;
[SerializeReference] private GameObject choiceButtonPrefab;
private void Awake()
{
InitComponents();
RegisterEvents();
}
#region
private void InitComponents()
{
_actorName = transform.Find(ActorName)?.gameObject.GetComponentInChildren<TextMeshProUGUI>();
_dialogText = transform.Find(DialogText)?.gameObject.GetComponent<TypewriterByCharacter>();
_nextArray = transform.Find(NextArray)?.gameObject;
_choiceBox = transform.Find(ChoiceBox)?.gameObject;
}
private void RegisterEvents()
{
_dialogText.onTextShowed.AddListener(OnTextShowed);
}
#endregion
/// <summary>
/// 隐藏对话盒
/// </summary>
public void HideDialog()
{
gameObject.SetActive(false);
}
/// <summary>
/// 显示对话
/// </summary>
/// <param name="dialogLine">对话内容</param>
/// <param name="character">角色内容</param>
/// <param name="nextStep">下一步</param>
/// <param name="lineId">行号</param>
/// <param name="isAutoSkip">是否自动跳过,默认为false</param>
public void ShowLine(string dialogLine, CharacterVo character, Action nextStep, string lineId,
bool isAutoSkip = false)
{
gameObject.SetActive(true);
// 把原有对话清掉
ClearBox();
_dialogText.gameObject.SetActive(true);
_choiceBox?.SetActive(false);
// 显示内容
ShowActorName(character);
_dialogText.ShowText(dialogLine);
_nextStep = nextStep;
}
private void OnTextShowed()
{
_nextArray.gameObject.SetActive(true);
EnumEventSystem.Global.Send(DialogEventEnum.LineShown);
}
public void NextStep()
{
if (_nextStep == null) return;
EnumEventSystem.Global.Send(DialogEventEnum.LineEnd);
// 关闭对话
var next = _nextStep;
_nextStep = null;
next.Invoke();
}
public void OnLocalizationChanged(string value)
{
_textParam = JsonUtil.ReadBeanByText<TextParam>(value);
var tmp = _dialogText.GetComponent<TMP_Text>();
// 修改对话文本
tmp.characterSpacing = _textParam.charSpace;
_actorName.characterSpacing = _textParam.charSpace;
}
/// <summary>
/// 展示选项
/// </summary>
/// <param name="dialogueOptions">对话选项</param>
public void ShowOptions(DialogOption[] dialogueOptions)
{
gameObject.SetActive(true);
// 没有选择框直接不显示选项
if (!_choiceBox)
{
return;
}
// 把原有对话清掉
ClearBox();
_choiceBox.SetActive(true);
_dialogText.gameObject.SetActive(false);
HideActorName();
// 销毁原来的按钮
foreach (Transform child in _choiceBox.transform)
{
Destroy(child.gameObject);
}
// 生成新按钮
foreach (var option in dialogueOptions)
{
if (!option.IsAvailable) continue;
var choiceInstance = Instantiate(choiceButtonPrefab, _choiceBox.transform);
var optionText = choiceInstance.GetComponentInChildren<TextMeshProUGUI>();
optionText.text = option.Line;
optionText.characterSpacing = _textParam.charSpace;
choiceInstance.GetComponent<Button>().onClick.AddListener(() =>
{
HideDialog();
option.Select();
});
}
}
/// <summary>
/// 尝试跳过对话
/// true说明成功快进了对话显示
/// false说明对话已经显示完成了,可以跳过
/// </summary>
/// <returns></returns>
public bool TrySkipLine(bool isForceSkip)
{
if (_dialogText.isShowingText)
{
_dialogText.SkipTypewriter();
return true;
}
_nextArray.gameObject.SetActive(false);
return false;
}
private void ClearBox()
{
gameObject.SetActive(true);
_dialogText?.ShowText("");
_nextArray?.SetActive(false);
if (!_actorName) _actorName.text = "";
}
private void ShowActorName(CharacterVo character)
{
if (!_actorName) return;
if (string.IsNullOrWhiteSpace(character.key))
{
_actorName.transform.parent.gameObject.SetActive(false);
}
else
{
_actorName.transform.parent.localPosition =
character.key == "me" ? new Vector3(310, 95, 0) : new Vector3(-458, 95, 0);
_actorName.transform.parent.gameObject.SetActive(true);
_actorName.text = character.GetActorName();
}
}
private void HideActorName()
{
_actorName.transform.parent.gameObject.SetActive(false);
}
}
}
@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 51f2233614aba944f9b2dab3d5af433b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -1,393 +0,0 @@
using System;
using System.Collections.Generic;
using AibisDream.Framework;
using AibisDream.Kit;
using AibisDream.UI;
using TMPro;
using UnityEngine;
namespace AibisDream
{
public class DialogCanvasManager : Singleton<DialogCanvasManager>, IDialogView
{
#region
private readonly Dictionary<DialogViewType, IDialogView> _dialogViewDict = new();
private IDialogView _defaultView;
private IDialogView _showingView;
private IActionController _autoNext;
private IActionController _block;
private IActionController _hideDialog;
public TMP_Text widthEstimation;
#endregion
#region
[SerializeField] private float blockDuration;
[SerializeField] private float autoSkipDelay;
[SerializeField] private float autoHideDuration;
private bool _isNextAutoSkip;
private bool _isNextBlocked;
#endregion
private readonly List<IUnRegister> _rmvList = new();
public override void OnSingletonInit()
{
InitEvent();
}
private void Start()
{
// 默认对话框直接加载
var centerText = transform.Find("Center Text").GetComponent<IDialogView>();
RegisterDialogView(DialogViewType.CenterText, centerText);
var centerOption = transform.Find("Center Option").GetComponent<IDialogView>();
RegisterDialogView(DialogViewType.CenterOption, centerOption);
var bubbleGroup = transform.Find("Bubble Group").GetComponent<IDialogView>();
RegisterDialogView(DialogViewType.StandardBubble, bubbleGroup);
_defaultView = _dialogViewDict[DialogViewType.StandardBubble];
}
private void InitEvent()
{
// 记录相关
_rmvList.Add(
EnumEventSystem.Global.Register<DialogEventEnum, DialogText>(DialogEventEnum.LineStart,
AddDialogueLine));
_rmvList.Add(
EnumEventSystem.Global.Register<DialogEventEnum, DialogText>(DialogEventEnum.OptionSelected,
AddDialogueLine));
_rmvList.Add(EnumEventSystem.Global.Register(EventEnum.NextYarn, CleanDialogHistory));
// 文本显示事件
_rmvList.Add(EnumEventSystem.Global.Register(DialogEventEnum.LineShown, OnTextShown));
_rmvList.Add(EnumEventSystem.Global.Register(DialogEventEnum.LineEnd, OnTextEnd));
}
private void OnTextShown()
{
Debug.Log("[事件处理] OnTextShown - 文本显示完成事件");
// 在快速模式下,不设置阻塞,因为快速模式会立即处理
if (DialogController.Instance.quickRunMode)
{
Debug.Log("[事件处理] OnTextShown - 快速模式,跳过阻塞设置");
return;
}
// 阻塞部分 - 只在非快速模式下阻塞,确保文本能够显示
_isNextBlocked = true;
_block = ActionKit.Delay(blockDuration, () =>
{
Debug.Log("[事件处理] OnTextShown - 阻塞时间结束");
_isNextBlocked = false;
_block = null;
}
).Start(this);
// 自动跳过部分 - 只在非快速模式下执行
if (DialogController.Instance.autoRunMode || _isNextAutoSkip)
{
Debug.Log("[事件处理] OnTextShown - 设置自动跳过定时器");
_autoNext = ActionKit.Delay(autoSkipDelay, () =>
{
Debug.Log("[事件处理] OnTextShown - 自动跳过定时器触发");
_autoNext = null;
NextStep();
}).Start(this);
_isNextAutoSkip = false;
}
}
private void OnTextEnd()
{
Debug.Log("[事件处理] OnTextEnd - 文本结束事件");
// 清理阻塞定时器
if (_block != null)
{
Debug.Log("[事件处理] OnTextEnd - 清理阻塞定时器");
_block.Deinit();
_block = null;
}
_isNextBlocked = false;
// 清理自动跳过定时器
if (_autoNext != null)
{
Debug.Log("[事件处理] OnTextEnd - 清理自动跳过定时器");
_autoNext.Deinit();
_autoNext = null;
}
Debug.Log("[事件处理] OnTextEnd - 清理完成");
}
public override void OnSingletonDestroy()
{
// 销毁前处理事件
_rmvList.ForEach(item => item.UnRegister());
}
#region
private void OnEnable()
{
DialogController.OnDialogueComplete += HideDialog;
}
private void OnDisable()
{
DialogController.OnDialogueComplete -= HideDialog;
}
#endregion
#region
/// <summary>
/// 注册对话框
/// </summary>
/// <param name="viewType"></param>
/// <param name="dialogView"></param>
public void RegisterDialogView(DialogViewType viewType, IDialogView dialogView)
{
_dialogViewDict.Add(viewType, dialogView);
}
/// <summary>
/// 注销对话框
/// </summary>
/// <param name="viewType"></param>
public void UnregisterDialogView(DialogViewType viewType)
{
_dialogViewDict.Remove(viewType);
}
#endregion
#region
public void ShowLine(string dialogLine, CharacterVo character, Action nextStep, string lineId,
bool isAutoSkip = false)
{
Debug.Log($"[DialogCanvasManager] ShowLine - 角色对话框类型: {character.dialogViewType}");
Debug.Log($"[DialogCanvasManager] ShowLine - nextStep是否为null: {nextStep == null}");
_isNextAutoSkip = isAutoSkip;
// 根据DialogViewType确定在哪个对话框显示
if (character.dialogViewType == DialogViewType.Default)
{
Debug.Log("[DialogCanvasManager] ShowLine - 使用默认对话框");
if (_showingView != _defaultView)
{
_showingView?.HideDialog();
}
else
{
_hideDialog?.Deinit();
_hideDialog = null;
}
_showingView = _defaultView;
_showingView.ShowLine(dialogLine, character, nextStep, lineId, isAutoSkip);
}
else if (_dialogViewDict.TryGetValue(character.dialogViewType, out var view))
{
Debug.Log($"[DialogCanvasManager] ShowLine - 使用指定对话框: {view.GetType().Name}");
if (_showingView != view)
{
_showingView?.HideDialog();
}
else
{
_hideDialog?.Deinit();
_hideDialog = null;
}
_showingView = view;
// 对于指定了对话框的,就在指定对话框显示
view.ShowLine(dialogLine, character, nextStep, lineId, isAutoSkip);
}
else
{
Debug.Log($"{character.dialogViewType.ToString()}类型对话框不存在");
}
Debug.Log($"[DialogCanvasManager] ShowLine - 当前_showingView类型: {_showingView?.GetType().Name}");
}
public void ShowOptions(DialogOption[] dialogueOptions)
{
var viewType = dialogueOptions[0].Character.dialogViewType;
// 根据状况选择不同的选择框
if (viewType == DialogViewType.Default)
{
if (_showingView != _defaultView)
{
_showingView?.HideDialog();
}
else
{
_hideDialog?.Deinit();
_hideDialog = null;
}
_showingView = _defaultView;
_showingView.ShowOptions(dialogueOptions);
}
else if(_dialogViewDict.TryGetValue(viewType, out var view))
{
if (_showingView != view)
{
_showingView?.HideDialog();
}
else
{
_hideDialog?.Deinit();
_hideDialog = null;
}
_showingView = view;
_showingView.ShowOptions(dialogueOptions);
}
}
public void HideDialog()
{
_showingView?.HideDialog();
}
public bool TrySkipLine(bool isForceSkip = false)
{
string skipType = isForceSkip ? "强制跳过" : "用户跳过";
Debug.Log($"[跳过操作] {skipType} - 阻塞状态: {_isNextBlocked}");
if (_isNextBlocked)
{
Debug.Log("[跳过操作] ❌ 被阻塞,返回true");
return true;
}
bool result = _showingView != null && _showingView.TrySkipLine(isForceSkip);
Debug.Log($"[跳过操作] {skipType} - 结果: {(result ? " " : " ")}");
return result;
}
public void NextStep()
{
Debug.Log("[对话继续] ===== NextStep开始 =====");
Debug.Log($"[对话继续] 当前显示的对话框类型: {_showingView?.GetType().Name}");
// 在快速模式下,不设置延迟隐藏,避免定时器冲突
if (!DialogController.Instance.quickRunMode)
{
var view = _showingView;
_hideDialog = ActionKit.Delay(autoHideDuration, () =>
{
Debug.Log("[对话继续] 延迟隐藏对话框");
_hideDialog = null;
view?.HideDialog();
}).Start(this);
}
else
{
Debug.Log("[对话继续] 快速模式,跳过延迟隐藏设置");
// 清理可能存在的延迟隐藏定时器
if (_hideDialog != null)
{
_hideDialog.Deinit();
_hideDialog = null;
}
}
Debug.Log("[对话继续] 调用对话框NextStep");
_showingView?.NextStep();
Debug.Log("[对话继续] ===== NextStep完成 =====");
}
public void OnLocalizationChanged(string value)
{
}
public void SwitchDialogView(DialogViewType dialogViewType)
{
if (_dialogViewDict.TryGetValue(dialogViewType, out var view))
{
_defaultView?.HideDialog();
_showingView?.HideDialog();
_defaultView = view;
}
else
{
Debug.Log($"{dialogViewType.ToString()}类型对话框不存在");
}
}
#endregion
#region
private RecordPanel RecordPanel => UIManager.Instance.GetPanel<RecordPanel>();
/// <summary>
/// 记录对话
/// </summary>
/// <param name="line">对话</param>
private void AddDialogueLine(DialogText line)
{
if (line.actor.dialogViewType == DialogViewType.Task)
{
return;
}
RecordPanel.AppendDialogLine(line);
}
private void CleanDialogHistory()
{
RecordPanel.ClearDialog();
}
public void CloseCanvas()
{
gameObject.SetActive(false);
}
public void OpenCanvas()
{
gameObject.SetActive(true);
}
#endregion
public float EstimateTextWidth(string text, float fontSize)
{
widthEstimation.fontSize = fontSize;
widthEstimation.text = text;
widthEstimation.ForceMeshUpdate();
return widthEstimation.preferredWidth;
}
}
public enum DialogViewType
{
Default,
Bubble,
OldBox,
Screen,
CenterText,
CenterOption,
Task,
StandardBubble
}
}
@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: c14c52217dac70244b02fe48d9462bae
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -8,21 +8,6 @@ using Yarn.Unity;
namespace AibisDream
{
public interface IDialogView
{
public void ShowLine(string dialogLine, CharacterVo character, Action nextStep, string lineId ,bool isAutoSkip = false);
public void ShowOptions(DialogOption[] dialogueOptions);
public void HideDialog();
public bool TrySkipLine(bool isForceSkip = false);
public void NextStep();
public void OnLocalizationChanged(string value);
}
public struct DialogOption
{
private Action<int> _onOptionSelected;
@@ -47,14 +32,15 @@ namespace AibisDream
_onOptionSelected.Invoke(_option.DialogueOptionID);
}
private DialogText TransToLine()
private LineInfo TransToLine()
{
return new DialogText
return new LineInfo
{
isOption = true,
lineId = _option.TextID,
line = _option.Line.TextWithoutCharacterName.Text,
actor = _option.Line.GetCharacterVo()
lineText = _option.Line.TextWithoutCharacterName.Text,
character = _option.Line.GetCharacterVo(),
isAutoSkip = false
};
}
@@ -0,0 +1,88 @@
using AibisDream.Framework;
using AibisDream.Kit;
using AibisDream.UI;
using UnityEngine;
namespace AibisDream
{
public class DialogUIManager : Singleton<DialogUIManager>
{
private CanvasGroup _canvasGroup;
[SerializeField] private LineRunner lineView;
[SerializeField] private OptionView optionView;
public override void OnSingletonInit()
{
_canvasGroup = GetComponent<CanvasGroup>();
EnumEventSystem.Global.Register<DialogEventEnum, LineInfo>(DialogEventEnum.LineStart, AddDialogueLine);
EnumEventSystem.Global.Register<DialogEventEnum, LineInfo>(DialogEventEnum.OptionSelected, AddDialogueLine);
EnumEventSystem.Global.Register(EventEnum.NextYarn, CleanDialogHistory);
}
public override void OnSingletonDestroy()
{
EnumEventSystem.Global.UnRegister<DialogEventEnum, LineInfo>(DialogEventEnum.LineStart, AddDialogueLine);
EnumEventSystem.Global.UnRegister<DialogEventEnum, LineInfo>(DialogEventEnum.OptionSelected, AddDialogueLine);
EnumEventSystem.Global.UnRegister(EventEnum.NextYarn, CleanDialogHistory);
}
private RecordPanel RecordPanel => UIManager.Instance.GetPanel<RecordPanel>();
/// <summary>
/// 记录对话
/// </summary>
/// <param name="line">对话</param>
private void AddDialogueLine(LineInfo line)
{
if (line.character.dialogViewType == DialogViewType.Task)
{
return;
}
RecordPanel.AppendDialogLine(line);
}
private void CleanDialogHistory()
{
RecordPanel.ClearDialog();
}
public void CloseCanvas()
{
gameObject.SetActive(false);
}
public void OpenCanvas()
{
gameObject.SetActive(true);
}
public void HideDialog()
{
// 关闭所有对话框
BubbleGroup.Instance.HideDialog();
}
public void RegisterScreenView(DialogViewType dialogViewType, ILineView screenView)
{
lineView.RegisterView(dialogViewType, screenView);
}
public void UnRegisterScreenView(DialogViewType dialogViewType)
{
lineView.UnRegisterView(dialogViewType);
}
}
public enum DialogViewType
{
Default,
Screen,
CenterText,
CenterOption,
Task,
StandardBubble
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: a38dd6a979b842b280fb73c921999a69
timeCreated: 1761295222
-117
View File
@@ -1,117 +0,0 @@
using System;
using AibisDream.Framework;
using AibisDream.Kit;
using AibisDream.Utility;
using Febucci.UI;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
namespace AibisDream
{
public class TempTextBox : MonoBehaviour, IDialogView
{
#region
private TypewriterByCharacter _dialogText;
private Image _panel;
private Action _nextStep;
#endregion
private bool _skipLineDelay;
private TextParam _textParam;
[Header("跳过阻塞延迟时间/ms")] [SerializeField]
private int delayTime = 300;
private void Awake()
{
InitComponents();
AddSomeListener();
}
private void InitComponents()
{
_dialogText = transform.Find("Dialog Text")?.gameObject.GetComponent<TypewriterByCharacter>();
}
private void AddSomeListener()
{
// 对话显示后有一段延时不可跳过
_dialogText.onTypewriterStart.AddListener(() =>
{
_skipLineDelay = true;
_ = CommonUtil.Delay(delayTime, () => { _skipLineDelay = false; });
});
}
public void ShowLine(string dialogLine, CharacterVo character, Action nextStep, string lineId, bool isAutoSkip = false)
{
// 把原有对话清掉
ClearBox();
_dialogText.gameObject.SetActive(true);
// 显示内容
_dialogText.ShowText(dialogLine);
// 自动跳过的回调很难独立Remove,只能全部清空再注册,下策
_dialogText.onTextShowed.RemoveAllListeners();
_dialogText.onTextShowed.AddListener(() => EnumEventSystem.Global.Send(DialogEventEnum.LineShown));
_nextStep = nextStep;
}
public void ShowOptions(DialogOption[] dialogueOptions)
{
// 不能出选项
}
public void HideDialog()
{
gameObject.SetActive(false);
}
public bool TrySkipLine(bool isForceSkip)
{
if (_skipLineDelay && !isForceSkip)
{
return true;
}
if (_dialogText.isShowingText)
{
_dialogText.SkipTypewriter();
return true;
}
return false;
}
public void NextStep()
{
if (_nextStep == null) return;
ClearBox();
EnumEventSystem.Global.Send(DialogEventEnum.LineEnd);
var next = _nextStep;
_nextStep = null;
next.Invoke();
}
public void OnLocalizationChanged(string value)
{
_textParam = JsonUtil.ReadBeanByText<TextParam>(value);
var tmp = _dialogText.GetComponent<TMP_Text>();
// 修改对话文本
tmp.characterSpacing = _textParam.charSpace;
}
private void ClearBox()
{
gameObject.SetActive(true);
_dialogText?.TextAnimator.SetText("");
}
}
}
@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 3bee0b70ea2946b8a6c59a4bceb04342
timeCreated: 1747292399
-64
View File
@@ -1,64 +0,0 @@
using System;
using AibisDream.Kit;
using AibisDream.Utility;
using Febucci.UI.Core;
using TMPro;
using Unity.VisualScripting;
using UnityEngine;
using Object = System.Object;
namespace AibisDream.Framework
{
public class TextBubble : MonoBehaviour
{
private TypewriterCore _typewriter;
#region
[SerializeField] public ActorRole role;
[SerializeField] public int idx;
[SerializeField] private int maxCharNum;
#endregion
public bool IsShowingText => _typewriter.isShowingText;
private void Awake()
{
_typewriter = GetComponentInChildren<TypewriterCore>();
}
public void ShowLine(string line, Action onTextEnd)
{
_typewriter.TextAnimator.SetText("");
gameObject.SetActive(true);
var formattedLine = CommonUtil.SplitString(line, maxCharNum);
_typewriter.ShowText(formattedLine);
// 对话结束回调
_typewriter.onTextShowed.RemoveAllListeners();
_typewriter.onTextShowed.AddListener(() => onTextEnd?.Invoke());
}
public void SkipLine()
{
if (_typewriter.isShowingText)
{
_typewriter.SkipTypewriter();
}
}
public void Hide()
{
gameObject.SetActive(false);
}
public void OnLocalizationChanged(string value)
{
var textParam = JsonUtil.ReadBeanByText<TextParam>(value);
var tmp = GetComponentInChildren<TMP_Text>();
tmp.characterSpacing = textParam.charSpace;
maxCharNum = textParam.maxCharNum;
}
}
}
@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: d97efe2567012354e9482f0774e66b76
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -1,146 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using AibisDream.Framework;
using AibisDream.Kit;
using Unity.VisualScripting;
using UnityEngine;
namespace AibisDream
{
public class TextBubbleGroup : MonoBehaviour, IDialogView
{
private Dictionary<ActorRole, TextBubble[]> _bubbleDict;
#region
private Action _nextStep;
private TextBubble _curBubble;
#endregion
#region
private void Awake()
{
InitBubbles();
// 注册泡泡
DialogCanvasManager.Instance.RegisterDialogView(DialogViewType.Bubble, this);
DialogCanvasManager.Instance.SwitchDialogView(DialogViewType.Bubble);
}
private void Start()
{
HideDialog();
}
private void OnDestroy()
{
DialogCanvasManager.Instance.SwitchDialogView(DialogViewType.OldBox);
DialogCanvasManager.Instance.UnregisterDialogView(DialogViewType.Bubble);
}
private void InitBubbles()
{
_bubbleDict = GetComponentsInChildren<TextBubble>().GroupBy(item => item.role)
.ToDictionary(group => group.Key, group => group.ToArray());
}
#endregion
public void ShowLine(string dialogLine, CharacterVo character, Action nextStep, string lineId, bool isAutoSkip = false)
{
gameObject.SetActive(true);
if (TryGetBubble(character.role, character.bubbleIdx ,out var bubble))
{
bubble.ShowLine(dialogLine, OnTextShowed);
// 将非选定的Bubble隐藏
HideDialog(bubble);
}
else
{
Debug.LogWarning($"{character.GetActorName()}的Role没有对应Bubble");
return;
}
// 保留信息
_nextStep = nextStep;
_curBubble = bubble;
}
public void ShowOptions(DialogOption[] dialogueOptions)
{
// 没有选项
}
public void HideDialog()
{
foreach (var textBubble in _bubbleDict.Values.SelectMany(inner => inner))
{
if (!textBubble.IsDestroyed())
{
textBubble.Hide();
}
}
}
public void HideDialog(TextBubble activeBubble)
{
foreach (var textBubble in _bubbleDict.Values.SelectMany(inner => inner))
{
if (activeBubble != textBubble)
{
textBubble?.Hide();
}
}
}
public bool TrySkipLine(bool isForceSkip)
{
if (_curBubble.IsShowingText)
{
_curBubble.SkipLine();
return true;
}
return false;
}
public void NextStep()
{
if (_nextStep == null) return;
EnumEventSystem.Global.Send(DialogEventEnum.LineEnd);
var next = _nextStep;
_nextStep = null;
_curBubble?.Hide();
next?.Invoke();
}
public void OnLocalizationChanged(string value)
{
}
private void OnTextShowed()
{
// 触发事件
EnumEventSystem.Global.Send(DialogEventEnum.LineShown);
}
private bool TryGetBubble(ActorRole role, int idx, out TextBubble textBubble)
{
if (_bubbleDict.TryGetValue(role, out var bubbles))
{
textBubble = bubbles.FirstOrDefault(item => item.idx == idx);
return textBubble != null;
}
textBubble = null;
return false;
}
}
}
@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 8341b0b94bf446d9b3b3c50a4428ee15
timeCreated: 1740146642
+16 -11
View File
@@ -8,6 +8,9 @@ namespace AibisDream.UI
public bool IsOpen => gameObject.activeSelf;
public bool IsCloseable => false;
private BoolButton _autoBtn;
private BoolButton _ffwdBtn;
#region
public void Show()
@@ -45,25 +48,27 @@ namespace AibisDream.UI
topBar.Find("Record").GetComponent<Button>().onClick.AddListener(OpenRecordPanel);
// 自动跳过和快进包括状态变换
var auto = topBar.Find("Auto Skip").GetComponent<BoolButton>();
auto.OnClick.AddListener(AutoSkip);
auto.getBool = () => DialogController.Instance.autoRunMode;
var ffwd = topBar.Find("Quick Forward").GetComponent<BoolButton>();
ffwd.OnClick.AddListener(QuickForward);
ffwd.getBool = () => DialogController.Instance.quickRunMode;
_autoBtn = topBar.Find("Auto Skip").GetComponent<BoolButton>();
_autoBtn.OnClick.AddListener(AutoSkip);
_autoBtn.getBool = () => DialogController.Instance.advanceMode.CurrentMode == AdvanceModeEnum.Auto;
_ffwdBtn = topBar.Find("Quick Forward").GetComponent<BoolButton>();
_ffwdBtn.OnClick.AddListener(QuickForward);
_ffwdBtn.getBool = () => DialogController.Instance.advanceMode.CurrentMode == AdvanceModeEnum.Quick;
}
private void AutoSkip()
{
DialogController.Instance.autoRunMode = !DialogController.Instance.autoRunMode;
DialogController.Instance.SwitchAutoMode();
_autoBtn.FreshState();
_ffwdBtn.FreshState();
}
private void QuickForward()
{
DialogController.Instance.quickRunMode = !DialogController.Instance.quickRunMode;
Time.timeScale = DialogController.Instance.quickRunMode ? 8f : 1f;
DialogController.Instance.SwitchQuickMode();
_ffwdBtn.FreshState();
_autoBtn.FreshState();
}
private void OpenSettingPanel()
+2 -2
View File
@@ -12,9 +12,9 @@ namespace AibisDream.UI
#endregion
public void Init(DialogText dialogText)
public void Init(LineInfo dialogText)
{
actorName.text = dialogText.actor.GetActorName();
actorName.text = dialogText.character.GetActorName();
dialogLine.text = dialogText.GetRecordLine();
gameObject.SetActive(true);
}
+3 -10
View File
@@ -22,7 +22,7 @@ namespace AibisDream.UI
#endregion
private readonly List<DialogText> _recordDataList = new();
private readonly List<LineInfo> _recordDataList = new();
public void Show()
{
@@ -65,9 +65,9 @@ namespace AibisDream.UI
popupBackground.CrossFadeAlpha(0.0f, 0.2f, false);
}
public void AppendDialogLine(DialogText dialogText)
public void AppendDialogLine(LineInfo lineInfo)
{
_recordDataList.Add(dialogText);
_recordDataList.Add(lineInfo);
}
public void ClearDialog()
@@ -77,13 +77,6 @@ namespace AibisDream.UI
private void ShowRecord()
{
// for (var i = _recordDataList.Count - 1; i >= 0; i--)
// {
// var dialogText = _recordDataList[i];
// var record = Instantiate(recordPrefab, recordRoot);
// record.GetComponent<RecordItem>().Init(dialogText);
// }
foreach (var recordData in _recordDataList)
{
var record = Instantiate(recordPrefab, recordRoot);
+37
View File
@@ -1,8 +1,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
using AibisDream.Framework;
using AibisDream.UI;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
namespace AibisDream
{
@@ -19,6 +22,8 @@ namespace AibisDream
public Camera UICamera { get; private set; }
public RectTransform DialogCanvas { get; private set; }
private GraphicRaycaster _raycaster;
#endregion
public override void OnSingletonInit()
@@ -60,6 +65,8 @@ namespace AibisDream
// 获取Canvas
Canvas = transform.Find("UI Canvas").GetComponent<RectTransform>();
DialogCanvas = transform.Find("Dialog Canvas").GetComponent<RectTransform>();
// 获取 GraphicRaycaster
_raycaster = Canvas.GetComponent<GraphicRaycaster>();
// 获取Panel
var panels = Canvas.GetComponentsInChildren<IUIPanel>(true);
_panelPool = new Dictionary<Type, IUIPanel>();
@@ -167,6 +174,36 @@ namespace AibisDream
return localPoint;
}
/// <summary>
/// 检查鼠标是否在指定标记的 UI 区域上
/// </summary>
/// <param name="regionTag">区域标识符,需要在 UIRegionMarker 组件中配置</param>
/// <returns>如果鼠标在指定区域上返回 true,否则返回 false</returns>
public bool IsOverRegion(string regionTag)
{
if (string.IsNullOrEmpty(regionTag))
{
return false;
}
// 如果鼠标不在 UI 上,直接返回 false
if (!EventSystem.current.IsPointerOverGameObject())
{
return false;
}
// 使用 GraphicRaycaster 检测鼠标下的 UI 元素
var eventData = new PointerEventData(EventSystem.current)
{
position = Input.mousePosition
};
var results = new List<RaycastResult>();
_raycaster.Raycast(eventData, results);
return results.Count > 0 && results.Any(result => result.gameObject.CompareTag(regionTag));
}
}
public interface IUIManager
+20 -59
View File
@@ -2,7 +2,6 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Unity.VisualScripting;
@@ -72,6 +71,21 @@ namespace AibisDream.Utility
return target;
}
public static int Limit(int target, int max, int min)
{
if (target <= min)
{
return min;
}
if (target >= max)
{
return max;
}
return target;
}
/// <summary>
/// 步进循环
/// </summary>
@@ -194,64 +208,6 @@ namespace AibisDream.Utility
return textArr.Length > 1 ? textArr[1].Trim() : lineText;
}
/// <summary>
/// 拆分字符串为若干行
/// </summary>
/// <param name="input"></param>
/// <param name="maxCharsPerLine"></param>
/// <returns></returns>
public static string SplitString(string input, int maxCharsPerLine)
{
if (string.IsNullOrEmpty(input) || maxCharsPerLine <= 0)
{
return input;
}
var result = new StringBuilder();
var lines = input.Replace("<br>", "\n").Split('\n');
foreach (var line in lines)
{
var currentIndex = 0;
while (currentIndex < line.Length)
{
var length = Math.Min(maxCharsPerLine, line.Length - currentIndex);
var substring = line.Substring(currentIndex, length);
// 检查是否需要调整长度以避免在单词中间断开
if (currentIndex + length < line.Length && !char.IsWhiteSpace(line[currentIndex + length]) &&
!char.IsPunctuation(line[currentIndex + length]))
{
var lastSpace = substring.LastIndexOf(' ');
if (lastSpace > 0)
{
length = lastSpace;
substring = line.Substring(currentIndex, length);
}
}
result.Append(substring.TrimStart());
currentIndex += length;
if (currentIndex < line.Length)
{
result.Append('\n');
}
}
result.Append('\n');
}
// Remove the last '\n' if needed
if (result.Length > 0)
{
result.Length--;
}
return result.ToString();
}
public static Vector2 GetPivotByType(PivotType pivotType)
{
return pivotType switch
@@ -282,5 +238,10 @@ namespace AibisDream.Utility
.Where(t => t.GetCustomAttributes(typeof(TAttribute), false).Length > 0)
.ToList();
}
public static string RemoveRichTextTags(this string str)
{
return Regex.Replace(str.Replace("<br>", "\n"), "[<|{].*?[>|}]", string.Empty);
}
}
}
+20 -14
View File
@@ -7,26 +7,26 @@ namespace AibisDream.Utility
public const string QQURL = "https://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=XQFpOqRb1_zqkCdR2bLT3kHb11XzZ54T" +
"&authKey=w8G8qxzecnATXDOec1Ybv8LA%2FTTN8gQkyegvbK%2FUZ9m90WxggTjXy2U6%2FJes" +
"WJF3&noverify=0&group_code=325268983";
public const string DiscordURL = "https://discord.gg/C7Xv8Z9NxG";
public const string BugSurveyURL = "https://jsj.top/f/F24cC6";
public const string SurveyURL_CN = "https://jsj.top/f/HkmCnH";
public const string SurveyURL_EN = "https://jsj.top/f/y501LX";
public const string WishlistURL = "https://store.steampowered.com/app/3473430/_All_Our_Broken_Parts?utm_source=playtest";
public static readonly string TestSaveFilePath = Application.streamingAssetsPath + "/TestSaveFiles";
#if UnityEditor
public static readonly string SaveFilePath = Application.persistentDataPath + "/SaveFiles/";
#else
public static readonly string SaveFilePath = Application.persistentDataPath + "/AllOurBrokenParts/saves/";
#endif
public static readonly string ChapterProgressPath = $"{Application.streamingAssetsPath}/Config/chapter.json";
#region
public const string UITextTable = "UIText";
@@ -38,15 +38,15 @@ namespace AibisDream.Utility
#region
public const string CutLinePrefabName = "CutLine";
public const string TaskItemName = "Task Item Temp";
public const string GearFollowerPrefabName = "GearFollower";
public const string ScreenTextName = "Screen Text";
public const string ActorPrefabName = "ActorAnima";
public const string SpriteActorPrefabName = "SpriteActor";
public const string MobileAnima = "AnimaMobileObject";
@@ -63,14 +63,20 @@ namespace AibisDream.Utility
#region
public const float TweenEndY = -10;
public const float FallSpeed = 10;
public const float TargetAspect = 16f / 9f;
public const float PanelDelayDuration = 0.4f;
#endregion
#region ()
public const int CharacterDelayTime = 70;
public const int LineMaxDelay = 2800;
public const int LineMinDelay = 600;
public const int AutoHideDelay = 300;
public const int FixedDelay = 400;
#endregion
}
}
+2 -1
View File
@@ -1,5 +1,6 @@
{
"Volume": "0.89",
"Language": "zh-Hans",
"WindowMode": "Windowed"
"WindowMode": "Windowed",
"TextSpeed": "2.0"
}
+1 -1
View File
@@ -12,9 +12,9 @@ TagManager:
- DialogueObject
- MoveableCharacter
- Vehicle
- Selectable
- UIcamera
- ViewCamera
- MainUI
layers:
- Default
- TransparentFX