加入很多新内容,这波一块交了

This commit is contained in:
FloatGaming
2026-04-08 20:53:41 +08:00
parent d9376833b6
commit 85dfff28dd
128 changed files with 14546 additions and 474 deletions
+7 -7
View File
@@ -1,5 +1,12 @@
fileFormatVersion: 2
guid: 17f3455809bcc5e4b8cb2398e1ca92a4
AssetOrigin:
serializedVersion: 1
productId: 225102
packageName: Simple Cartoon UI
packageVersion: 1.1
assetPath: Assets/Cartoon UI/Icons/Gift Grey.png
uploadId: 825882
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
@@ -128,10 +135,3 @@ TextureImporter:
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 225102
packageName: Simple Cartoon UI
packageVersion: 1.1
assetPath: Assets/Cartoon UI/Icons/Gift Grey.png
uploadId: 825882
+35
View File
@@ -346,6 +346,7 @@ MonoBehaviour:
- {fileID: -665122592112833258}
- {fileID: -5415734101822189328}
- {fileID: 8032282833275709512}
- {fileID: 564577042516712540}
--- !u!114 &446725181531353334
MonoBehaviour:
m_ObjectHideFlags: 3
@@ -380,6 +381,40 @@ MonoBehaviour:
highlightsEnd:
m_OverrideState: 1
m_Value: 1
--- !u!114 &564577042516712540
MonoBehaviour:
m_ObjectHideFlags: 3
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fcaf02ee66ed11d4d9c67508e0130935, type: 3}
m_Name: GlobalDistortionVolume
m_EditorClassIdentifier:
active: 1
intensity:
m_OverrideState: 1
m_Value: 0
noiseStrength:
m_OverrideState: 1
m_Value: 0.16
radialStrength:
m_OverrideState: 1
m_Value: 0.35
noiseScale:
m_OverrideState: 1
m_Value: 12
center:
m_OverrideState: 1
m_Value: {x: 0.5, y: 0.5}
edgeFade:
m_OverrideState: 1
m_Value: 1.25
affectSceneView:
m_OverrideState: 1
m_Value: 0
--- !u!114 &757156498526246967
MonoBehaviour:
m_ObjectHideFlags: 3
File diff suppressed because it is too large Load Diff
+7
View File
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: d8cad1f4047312243880d8f3e90872b7
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -1,4 +1,4 @@
%YAML 1.1
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
@@ -12,18 +12,19 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 27e379f45b1bb88449756219caee2f89, type: 3}
m_Name: playerData_uniqueData
m_EditorClassIdentifier:
player_currentEXP: 0
player_coins: 9999999
player_material: 0
commonExpBottle78001: 0
mediumExpBottle78002: 0
superiorExpBottle78003: 0
supremeExpBottle78004: 0
extraordinaryExpBottle78005: 0
player_currentEXP: 802
player_coins: 999988
player_material: 486
player_currentLevel: 0
commonExpBottle78001: 1
mediumExpBottle78002: 2
superiorExpBottle78003: 1
supremeExpBottle78004: 1
extraordinaryExpBottle78005: 3
celestialExpBottle78006: 0
uRankingScore: 0
dushMaterial78021: 0
dushMaterial78022: 0
uRankingScore: 0.6457693
dushMaterial78021: 1
dushMaterial78022: 1
dushMaterial78023: 0
dushMaterial78024: 0
firstLaunchDate: 2026-03-16
@@ -39,4 +39,4 @@ MonoBehaviour:
- currencyType: 0
amount: 3
unlockRequirements: []
purchasedCount: 1453
purchasedCount: 1454
@@ -39,4 +39,4 @@ MonoBehaviour:
- currencyType: 0
amount: 4
unlockRequirements: []
purchasedCount: 2316
purchasedCount: 2318
@@ -39,4 +39,4 @@ MonoBehaviour:
- currencyType: 0
amount: 5
unlockRequirements: []
purchasedCount: 400
purchasedCount: 401
@@ -39,4 +39,4 @@ MonoBehaviour:
- currencyType: 0
amount: 6
unlockRequirements: []
purchasedCount: 402
purchasedCount: 403
@@ -39,4 +39,4 @@ MonoBehaviour:
- currencyType: 0
amount: 7
unlockRequirements: []
purchasedCount: 300
purchasedCount: 303
@@ -39,4 +39,4 @@ MonoBehaviour:
- currencyType: 0
amount: 1
unlockRequirements: []
purchasedCount: 1308
purchasedCount: 1309
@@ -39,4 +39,4 @@ MonoBehaviour:
- currencyType: 0
amount: 2
unlockRequirements: []
purchasedCount: 1300
purchasedCount: 1301
@@ -39,4 +39,4 @@ MonoBehaviour:
- currencyType: 0
amount: 1
unlockRequirements: []
purchasedCount: 2
purchasedCount: 3
@@ -39,4 +39,4 @@ MonoBehaviour:
- currencyType: 1
amount: 40
unlockRequirements: []
purchasedCount: 0
purchasedCount: 1
@@ -39,4 +39,4 @@ MonoBehaviour:
- currencyType: 1
amount: 60
unlockRequirements: []
purchasedCount: 0
purchasedCount: 1
@@ -23,7 +23,7 @@ MonoBehaviour:
isOnShelf: 1
canbepurchased: 1
isHot: 0
user_has_read: 0
user_has_read: 1
itemType: 3
associatedAllyHero: {fileID: 0}
associatedSong: {fileID: 0}
@@ -39,4 +39,4 @@ MonoBehaviour:
- currencyType: 1
amount: 1000
unlockRequirements: []
purchasedCount: 0
purchasedCount: 1
@@ -16,42 +16,78 @@ MonoBehaviour:
level: 20
tierNameConfig: {fileID: 11400000, guid: dd40d174875037e439647e54cf81eab1, type: 2}
maxHp:
basicGain: 0.086
cultivationInterval: 0.005
basicGain: 0.1
cultivationInterval: 0.045
attack:
basicGain: 0
cultivationInterval: 0.005
basicGain: 0.1
cultivationInterval: 0.045
maxMana:
basicGain: 0
cultivationInterval: 0.005
basicGain: 0.1
cultivationInterval: 0.045
damageResistance:
basicGain: 0
cultivationInterval: 0.005
basicGain: 0.1
cultivationInterval: 0.045
scoreEfficiency:
basicGain: 0.082
cultivationInterval: 0.005
basicGain: 0.1
cultivationInterval: 0.045
specialEffects:
- effectType: 4
value: 0.03
- effectType: 0
value: 999999
- effectType: 1
value: 999999
- effectType: 2
value: 999999
- effectType: 3
value: 0.02
value: 0.9
- effectType: 4
value: 0.9
- effectType: 5
value: 999999
- effectType: 6
value: 999999
- effectType: 7
value: -9
- effectType: 8
value: 0
value: -9
enableTypeSameEffects: 0
typeSameEffects:
- effectType: 0
value: 0.05
value: 1
- effectType: 4
value: 0.05
value: 1
- effectType: 2
value: 1
- effectType: 3
value: 1
- effectType: 4
value: 1
- effectType: 5
value: 1
- effectType: 6
value: 1
illusionEffects:
- effectType: 0
value: 60
- effectType: 3
value: 0.03
- effectType: 4
value: 0.05
value: 999999
- effectType: 1
value: 999999
- effectType: 2
value: 999999
maxLevelEffects:
- effectType: 0
value: 0.01
value: 999999
- effectType: 1
value: 999999
- effectType: 2
value: 999999
- effectType: 3
value: 0.9
- effectType: 4
value: 0.9
- effectType: 5
value: 999999
- effectType: 6
value: 999999
- effectType: 7
value: -999999
sa_skillID: 30011005
ia_skillID: 30011006
+27 -84
View File
@@ -1451,7 +1451,7 @@ GameObject:
m_Component:
- component: {fileID: 159785774}
- component: {fileID: 159785776}
- component: {fileID: 159785775}
- component: {fileID: 159785777}
m_Layer: 5
m_Name: selected_song
m_TagString: Untagged
@@ -1475,10 +1475,18 @@ RectTransform:
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: 842, y: 266.1}
m_AnchoredPosition: {x: 848.8, y: 266.1}
m_SizeDelta: {x: 200, y: 50}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &159785775
--- !u!222 &159785776
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 159785773}
m_CullTransparentMesh: 1
--- !u!114 &159785777
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
@@ -1487,7 +1495,7 @@ MonoBehaviour:
m_GameObject: {fileID: 159785773}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3}
m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
@@ -1498,85 +1506,20 @@ MonoBehaviour:
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_text: SELECTED SONG
m_isRightToLeft: 0
m_fontAsset: {fileID: 11400000, guid: c95ab61f13e39254e8e3cbf4059d88c5, type: 2}
m_sharedMaterial: {fileID: 4492750392876140565, guid: c95ab61f13e39254e8e3cbf4059d88c5, type: 2}
m_fontSharedMaterials: []
m_fontMaterial: {fileID: 0}
m_fontMaterials: []
m_fontColor32:
serializedVersion: 2
rgba: 4294967295
m_fontColor: {r: 1, g: 1, b: 1, a: 1}
m_enableVertexGradient: 0
m_colorMode: 3
m_fontColorGradient:
topLeft: {r: 1, g: 1, b: 1, a: 1}
topRight: {r: 1, g: 1, b: 1, a: 1}
bottomLeft: {r: 1, g: 1, b: 1, a: 1}
bottomRight: {r: 1, g: 1, b: 1, a: 1}
m_fontColorGradientPreset: {fileID: 0}
m_spriteAsset: {fileID: 0}
m_tintAllSprites: 0
m_StyleSheet: {fileID: 0}
m_TextStyleHashCode: -1183493901
m_overrideHtmlColors: 0
m_faceColor:
serializedVersion: 2
rgba: 4294967295
m_fontSize: 18
m_fontSizeBase: 18
m_fontWeight: 400
m_enableAutoSizing: 0
m_fontSizeMin: 18
m_fontSizeMax: 72
m_fontStyle: 1
m_HorizontalAlignment: 4
m_VerticalAlignment: 512
m_textAlignment: 65535
m_characterSpacing: 0
m_wordSpacing: 0
m_lineSpacing: 0
m_lineSpacingMax: 0
m_paragraphSpacing: 0
m_charWidthMaxAdj: 0
m_TextWrappingMode: 1
m_wordWrappingRatios: 0.4
m_overflowMode: 0
m_linkedTextComponent: {fileID: 0}
parentLinkedComponent: {fileID: 0}
m_enableKerning: 1
m_ActiveFontFeatures: 6e72656b
m_enableExtraPadding: 0
checkPaddingRequired: 0
m_isRichText: 1
m_EmojiFallbackSupport: 1
m_parseCtrlCharacters: 1
m_isOrthographic: 1
m_isCullingEnabled: 0
m_horizontalMapping: 0
m_verticalMapping: 0
m_uvLineOffset: 0
m_geometrySortingOrder: 0
m_IsTextObjectScaleStatic: 0
m_VertexBufferAutoSizeReduction: 0
m_useMaxVisibleDescender: 1
m_pageToDisplay: 1
m_margin: {x: -304.58203, y: 0, z: 0, w: 0}
m_isUsingLegacyAnimationComponent: 0
m_isVolumetricText: 0
m_hasFontAssetChanged: 0
m_baseMaterial: {fileID: 0}
m_maskOffset: {x: 0, y: 0, z: 0, w: 0}
--- !u!222 &159785776
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 159785773}
m_CullTransparentMesh: 1
m_FontData:
m_Font: {fileID: 12800000, guid: 8b8373b0af11dca46b89be60dbe469f8, type: 3}
m_FontSize: 14
m_FontStyle: 0
m_BestFit: 0
m_MinSize: 10
m_MaxSize: 40
m_Alignment: 5
m_AlignByGeometry: 0
m_RichText: 1
m_HorizontalOverflow: 0
m_VerticalOverflow: 0
m_LineSpacing: 1
m_Text: S E L E C T E D S O N G
--- !u!1 &167571322
GameObject:
m_ObjectHideFlags: 0
@@ -20112,7 +20055,7 @@ RectTransform:
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: 800.98553, y: 297.84952}
m_AnchoredPosition: {x: 795.1, y: 297.84952}
m_SizeDelta: {x: 318.019, y: 50}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &2004358155
+696 -61
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+137 -14
View File
@@ -1,6 +1,6 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &-3594275912957905754
--- !u!114 &-4028999061945789234
MonoBehaviour:
m_ObjectHideFlags: 3
m_CorrespondingSourceObject: {fileID: 0}
@@ -9,22 +9,31 @@ MonoBehaviour:
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: ccf1aba9553839d41ae37dd52e9ebcce, type: 3}
m_Name: MotionBlur
m_Script: {fileID: 11500000, guid: 54a30677f5d2e4548881a79f4c3e3972, type: 3}
m_Name: GlobalGlitchVolume
m_EditorClassIdentifier:
active: 0
mode:
m_OverrideState: 1
m_Value: 1
quality:
m_OverrideState: 1
m_Value: 1
active: 1
intensity:
m_OverrideState: 1
m_Value: 0.476
clamp:
m_Value: 0
blockStrength:
m_OverrideState: 1
m_Value: 0.118
m_Value: 0.297
colorSplit:
m_OverrideState: 1
m_Value: 0.0128
jitterAmount:
m_OverrideState: 1
m_Value: 1
stripFrequency:
m_OverrideState: 1
m_Value: 213
scanlineStrength:
m_OverrideState: 1
m_Value: 0.527
affectSceneView:
m_OverrideState: 1
m_Value: 0
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
@@ -38,4 +47,118 @@ MonoBehaviour:
m_Name: gpGV
m_EditorClassIdentifier:
components:
- {fileID: -3594275912957905754}
- {fileID: 2046802184354103511}
- {fileID: 2590790448571127267}
- {fileID: -4028999061945789234}
- {fileID: 1487594879138804974}
- {fileID: 9136543105356401684}
- {fileID: 0}
--- !u!114 &1487594879138804974
MonoBehaviour:
m_ObjectHideFlags: 3
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 29fa0085f50d5e54f8144f766051a691, type: 3}
m_Name: FilmGrain
m_EditorClassIdentifier:
active: 1
type:
m_OverrideState: 1
m_Value: 0
intensity:
m_OverrideState: 1
m_Value: 0.547
response:
m_OverrideState: 1
m_Value: 0
texture:
m_OverrideState: 1
m_Value: {fileID: 0}
--- !u!114 &2046802184354103511
MonoBehaviour:
m_ObjectHideFlags: 3
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fcaf02ee66ed11d4d9c67508e0130935, type: 3}
m_Name: GlobalDistortionVolume
m_EditorClassIdentifier:
active: 1
intensity:
m_OverrideState: 1
m_Value: 0
noiseStrength:
m_OverrideState: 1
m_Value: 1
radialStrength:
m_OverrideState: 1
m_Value: 2
noiseScale:
m_OverrideState: 1
m_Value: 14.5
center:
m_OverrideState: 1
m_Value: {x: -11.47, y: 0.5}
edgeFade:
m_OverrideState: 1
m_Value: 3
affectSceneView:
m_OverrideState: 1
m_Value: 0
--- !u!114 &2590790448571127267
MonoBehaviour:
m_ObjectHideFlags: 3
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: c5e1dc532bcb41949b58bc4f2abfbb7e, type: 3}
m_Name: LensDistortion
m_EditorClassIdentifier:
active: 1
intensity:
m_OverrideState: 0
m_Value: 0
xMultiplier:
m_OverrideState: 0
m_Value: 0.532
yMultiplier:
m_OverrideState: 0
m_Value: 1
center:
m_OverrideState: 0
m_Value: {x: 0.5, y: 0.5}
scale:
m_OverrideState: 0
m_Value: 0.98
--- !u!114 &9136543105356401684
MonoBehaviour:
m_ObjectHideFlags: 3
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 2b5b0fcb28cb9254bbcd2a498e0fe228, type: 3}
m_Name: GlobalAfterimageVolume
m_EditorClassIdentifier:
active: 1
opacity:
m_OverrideState: 1
m_Value: 0
scale:
m_OverrideState: 1
m_Value: 1.05
affectSceneView:
m_OverrideState: 1
m_Value: 0
+62 -2
View File
@@ -1,5 +1,33 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &-7968524894476178354
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: d71f5b59ebb9a7640b177e16adf3d6c7, type: 3}
m_Name: Global Distortion Renderer Feature
m_EditorClassIdentifier:
m_Active: 1
renderPassEvent: 600
--- !u!114 &-82031990492403773
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 84ae0996c2f9f6c43a0d5b735af7f121, type: 3}
m_Name: Global Glitch Renderer Feature
m_EditorClassIdentifier:
m_Active: 1
renderPassEvent: 600
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
@@ -24,8 +52,12 @@ MonoBehaviour:
probeSamplingDebugMesh: {fileID: 0}
probeSamplingDebugTexture: {fileID: 0}
probeVolumeBlendStatesCS: {fileID: 0}
m_RendererFeatures: []
m_RendererFeatureMap:
m_RendererFeatures:
- {fileID: -7968524894476178354}
- {fileID: -82031990492403773}
- {fileID: 8810499459484542277}
- {fileID: 4089674193680255197}
m_RendererFeatureMap: 4eece3d8d31c6a91c3677bda5690dcfe45e55810942e457addc864d90271c138
m_UseNativeRenderPass: 0
m_LayerMask:
serializedVersion: 2
@@ -56,3 +88,31 @@ MonoBehaviour:
m_PostProcessData: {fileID: 11400000, guid: 41439944d30ece34e96484bdb6645b55, type: 2}
m_DefaultMaterialType: 0
m_DefaultCustomMaterial: {fileID: 2100000, guid: a97c105638bdf8b4a8650670310a4cd3, type: 2}
--- !u!114 &4089674193680255197
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: e30db065f184af241b78ce51edc50d96, type: 3}
m_Name: Global Monochrome Renderer Feature
m_EditorClassIdentifier:
m_Active: 1
renderPassEvent: 600
--- !u!114 &8810499459484542277
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: a28c239b9c2736e489a75bd286167cb9, type: 3}
m_Name: Global Afterimage Renderer Feature
m_EditorClassIdentifier:
m_Active: 1
renderPassEvent: 600
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 4cfb6d280c0131d45b93db3841bd7acf
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
+42
View File
@@ -0,0 +1,42 @@
Shader "Hidden/Bansonic/GlobalAfterimage"
{
SubShader
{
Tags { "RenderPipeline" = "UniversalPipeline" }
ZWrite Off
Cull Off
ZTest Always
Pass
{
Name "GlobalAfterimage"
HLSLPROGRAM
#pragma vertex Vert
#pragma fragment Frag
#pragma target 4.5
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.core/Runtime/Utilities/Blit.hlsl"
float _AfterimageOpacity;
float _AfterimageScale;
TEXTURE2D(_SnapshotTex);
SAMPLER(sampler_SnapshotTex);
half4 Frag(Varyings input) : SV_Target
{
float2 uv = input.texcoord;
half4 baseColor = SAMPLE_TEXTURE2D_X(_BlitTexture, sampler_LinearClamp, uv);
float safeScale = max(_AfterimageScale, 1.0);
float2 scaledUv = (uv - 0.5) / safeScale + 0.5;
float inside = step(0.0, scaledUv.x) * step(0.0, scaledUv.y) * step(scaledUv.x, 1.0) * step(scaledUv.y, 1.0);
half4 snapshot = SAMPLE_TEXTURE2D(_SnapshotTex, sampler_SnapshotTex, saturate(scaledUv));
float alpha = saturate(_AfterimageOpacity) * inside;
return lerp(baseColor, snapshot, alpha);
}
ENDHLSL
}
}
}
@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 08e184084ff672d4f8e6b649d27dc10d
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
userData:
assetBundleName:
assetBundleVariant:
+52
View File
@@ -0,0 +1,52 @@
Shader "Hidden/Bansonic/GlobalDistortion"
{
SubShader
{
Tags { "RenderPipeline" = "UniversalPipeline" }
ZWrite Off
Cull Off
ZTest Always
Pass
{
Name "GlobalDistortion"
HLSLPROGRAM
#pragma vertex Vert
#pragma fragment Frag
#pragma target 4.5
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.core/Runtime/Utilities/Blit.hlsl"
float _DistortionIntensity;
float _NoiseStrength;
float _RadialStrength;
float _NoiseScale;
float2 _DistortionCenter;
float _EdgeFade;
half4 Frag(Varyings input) : SV_Target
{
float2 uv = input.texcoord;
float2 centered = uv - _DistortionCenter;
float distanceFromCenter = length(centered);
float2 direction = distanceFromCenter > 0.0001 ? centered / distanceFromCenter : float2(0.0, 0.0);
float normalizedDistance = saturate(distanceFromCenter * 1.41421356);
float edgeMask = saturate(1.0 - pow(normalizedDistance, _EdgeFade));
float t = _Time.y;
float noiseA = sin((uv.x + t * 0.73) * _NoiseScale) * cos((uv.y - t * 1.13) * (_NoiseScale * 0.87));
float noiseB = cos((uv.x * 1.31 - t * 0.41) * (_NoiseScale * 0.63)) * sin((uv.y * 1.11 + t * 0.52) * (_NoiseScale * 1.21));
float2 radialOffset = direction * edgeMask * (_RadialStrength * 0.03) * _DistortionIntensity;
float2 noiseOffset = float2(noiseA, noiseB) * (_NoiseStrength * 0.015) * _DistortionIntensity;
float2 sampleUv = uv + radialOffset + noiseOffset;
sampleUv = clamp(sampleUv, 0.0, 1.0);
return SAMPLE_TEXTURE2D_X(_BlitTexture, sampler_LinearClamp, sampleUv);
}
ENDHLSL
}
}
}
@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: dc80b7dbbe782854c9f0c6ae053bfc70
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
userData:
assetBundleName:
assetBundleVariant:
+71
View File
@@ -0,0 +1,71 @@
Shader "Hidden/Bansonic/GlobalGlitch"
{
SubShader
{
Tags { "RenderPipeline" = "UniversalPipeline" }
ZWrite Off
Cull Off
ZTest Always
Pass
{
Name "GlobalGlitch"
HLSLPROGRAM
#pragma vertex Vert
#pragma fragment Frag
#pragma target 4.5
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.core/Runtime/Utilities/Blit.hlsl"
float _GlitchIntensity;
float _BlockStrength;
float _ColorSplit;
float _JitterAmount;
float _StripFrequency;
float _ScanlineStrength;
float Hash(float2 p)
{
p = frac(p * float2(123.34, 345.45));
p += dot(p, p + 34.345);
return frac(p.x * p.y);
}
half4 Frag(Varyings input) : SV_Target
{
float2 uv = input.texcoord;
float timeSlice = floor(_Time.y * 24.0);
float stripIndex = floor(uv.y * _StripFrequency);
float stripNoise = Hash(float2(stripIndex, timeSlice));
float blockMask = step(0.58, stripNoise);
float blockShift = (stripNoise - 0.5) * _BlockStrength * 0.12 * _GlitchIntensity * blockMask;
float lineJitter = sin((uv.y + _Time.y * 14.0) * 420.0) * _JitterAmount * 0.003 * _GlitchIntensity;
float combinedShift = blockShift + lineJitter;
float2 baseUv = uv;
baseUv.x = clamp(baseUv.x + combinedShift, 0.0, 1.0);
float colorSplit = _ColorSplit * _GlitchIntensity;
float2 redUv = float2(clamp(baseUv.x + colorSplit, 0.0, 1.0), baseUv.y);
float2 greenUv = baseUv;
float2 blueUv = float2(clamp(baseUv.x - colorSplit, 0.0, 1.0), baseUv.y);
half red = SAMPLE_TEXTURE2D_X(_BlitTexture, sampler_LinearClamp, redUv).r;
half green = SAMPLE_TEXTURE2D_X(_BlitTexture, sampler_LinearClamp, greenUv).g;
half blue = SAMPLE_TEXTURE2D_X(_BlitTexture, sampler_LinearClamp, blueUv).b;
half4 color = half4(red, green, blue, 1.0);
float scan = sin(uv.y * _ScreenParams.y * 1.15 + _Time.y * 12.0) * 0.5 + 0.5;
float scanMask = lerp(1.0, 1.0 - scan * 0.35, _ScanlineStrength * _GlitchIntensity);
color.rgb *= scanMask;
return color;
}
ENDHLSL
}
}
}
+9
View File
@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 32a0932fed2df844c8796df10247873b
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
userData:
assetBundleName:
assetBundleVariant:
+36
View File
@@ -0,0 +1,36 @@
Shader "Hidden/Bansonic/GlobalMonochrome"
{
SubShader
{
Tags { "RenderPipeline" = "UniversalPipeline" }
ZWrite Off
Cull Off
ZTest Always
Pass
{
Name "GlobalMonochrome"
HLSLPROGRAM
#pragma vertex Vert
#pragma fragment Frag
#pragma target 4.5
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.core/Runtime/Utilities/Blit.hlsl"
float _MonochromeIntensity;
half4 Frag(Varyings input) : SV_Target
{
float2 uv = input.texcoord;
half4 color = SAMPLE_TEXTURE2D_X(_BlitTexture, sampler_LinearClamp, uv);
half luminance = dot(color.rgb, half3(0.299h, 0.587h, 0.114h));
half3 grayscale = luminance.xxx;
color.rgb = lerp(color.rgb, grayscale, saturate(_MonochromeIntensity));
return color;
}
ENDHLSL
}
}
}
@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: adee8c544438ff3498bececba27c3c76
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
userData:
assetBundleName:
assetBundleVariant:
+2 -2
View File
@@ -29,8 +29,8 @@ Transform:
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 0.1, y: 6.49, z: 0.1}
m_ConstrainProportionsScale: 0
m_LocalScale: {x: 0.5, y: 0.5, z: 0.5}
m_ConstrainProportionsScale: 1
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
@@ -111,7 +111,7 @@
"length": 0.0,
"barNumber": 3,
"yPos": -268.5,
"noteFunction": "",
"noteFunction": "CameraWaveFX",
"noteid": "7ae79d1c-43ff-4115-b804-486befebef2c",
"newLocation": {
"bar": 3,
@@ -128,7 +128,7 @@
"length": 0.0,
"barNumber": 5,
"yPos": -268.5,
"noteFunction": "",
"noteFunction": "CameraScaleEvent",
"noteid": "ca34a006-3d0a-46da-b853-900d9fd32929",
"newLocation": {
"bar": 5,
@@ -145,7 +145,7 @@
"length": 0.0,
"barNumber": 5,
"yPos": 201.375,
"noteFunction": "",
"noteFunction": "CameraShakeEvent",
"noteid": "1ed274b6-3065-46df-b8ba-229a8ca90d81",
"newLocation": {
"bar": 5,
@@ -162,7 +162,7 @@
"length": 0.0,
"barNumber": 7,
"yPos": -268.5,
"noteFunction": "",
"noteFunction": "FlashBlinkEvent",
"noteid": "a62ce93e-8977-4ef7-874e-d2aafa2e0b46",
"newLocation": {
"bar": 7,
@@ -179,7 +179,7 @@
"length": 0.0,
"barNumber": 7,
"yPos": 201.375,
"noteFunction": "",
"noteFunction": "CameraGlitchFX",
"noteid": "7ab2727f-3234-4823-9053-9d803186728d",
"newLocation": {
"bar": 7,
@@ -196,7 +196,7 @@
"length": 0.6818181818181818,
"barNumber": 9,
"yPos": -268.5,
"noteFunction": "",
"noteFunction": "CameraGlitchFX",
"noteid": "6ca6c017-f1a1-45ce-b222-38174fbacaed",
"newLocation": {
"bar": 9,
@@ -213,7 +213,7 @@
"length": 0.6818181818181818,
"barNumber": 10,
"yPos": -268.5,
"noteFunction": "",
"noteFunction": "ScreenshotScale",
"noteid": "f3b85cc8-4287-4180-b831-97eef996c938",
"newLocation": {
"bar": 10,
@@ -230,7 +230,7 @@
"length": 0.0,
"barNumber": 10,
"yPos": 0.0,
"noteFunction": "",
"noteFunction": "CameraMonochromeFX",
"noteid": "b4a846b0-e857-450e-99b9-a092c9f33be8",
"newLocation": {
"bar": 10,
@@ -1,4 +1,4 @@
%YAML 1.1
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
@@ -92,7 +92,7 @@ MonoBehaviour:
- tierName: "\u6F84\u660E\u5883"
equipmentSprite: {fileID: 21300000, guid: 814f39e3a1e204c4586f75b514a06601, type: 3}
tierDescription:
- tierName: "\u5FC3\u517B\u5F52\u4E00"
- tierName: "\u5FC3\u517B\u5F52\u4E00\u5492"
equipmentSprite: {fileID: 21300000, guid: 4ce68bd00ecc6f64baefd01ce27f33f9, type: 3}
tierDescription:
- tierName: "\u68A6\u9192\xB7\u65E0\u5C18\u771F\u5883"
@@ -139,19 +139,27 @@ public class chooseSkillPrefab : MonoBehaviour, IPointerEnterHandler, IPointerEx
detailPinnedByButton = pinnedByButton;
detailOpenedFrame = Time.frameCount;
Transform parent = transform.root != null ? transform.root : transform;
Transform parent = ResolveDetailParent();
spawnedDetail = Instantiate(sskilldetialPrefab, parent);
spawnedDetail.transform.SetAsLastSibling();
RectTransform selfRect = transform as RectTransform;
RectTransform detailRect = spawnedDetail.transform as RectTransform;
RectTransform parentRect = parent as RectTransform;
if (selfRect != null && detailRect != null && parentRect != null)
{
Canvas canvas = parent.GetComponentInParent<Canvas>();
Camera eventCamera = null;
if (canvas != null && canvas.renderMode != RenderMode.ScreenSpaceOverlay)
{
eventCamera = canvas.worldCamera;
}
Vector3 worldPoint = selfRect.TransformPoint(new Vector3(selfRect.rect.xMax, selfRect.rect.center.y, 0f));
RectTransformUtility.ScreenPointToLocalPointInRectangle(
parentRect,
RectTransformUtility.WorldToScreenPoint(null, worldPoint),
null,
RectTransformUtility.WorldToScreenPoint(eventCamera, worldPoint),
eventCamera,
out Vector2 localPoint);
detailRect.anchoredPosition = localPoint + detailPrefabOffset;
}
@@ -163,6 +171,22 @@ public class chooseSkillPrefab : MonoBehaviour, IPointerEnterHandler, IPointerEx
}
}
private Transform ResolveDetailParent()
{
Canvas canvas = GetComponentInParent<Canvas>();
if (canvas != null && canvas.rootCanvas != null)
{
return canvas.rootCanvas.transform;
}
if (transform.root != null)
{
return transform.root;
}
return transform;
}
private bool IsPointerInside(Vector2 screenPoint)
{
if (IsScreenPointInside(transform as RectTransform, screenPoint))
@@ -195,6 +195,11 @@ public class equipSmelt : MonoBehaviour
SavePersistentState();
}
public void RefreshPlayerSkillAdjustedUi()
{
RefreshAllUi();
}
public void SetDragPreviewVisible(bool visible)
{
if (dragObj == null)
@@ -382,6 +387,7 @@ public class equipSmelt : MonoBehaviour
return;
}
int grantedFragments = Mathf.Max(0, pendingDirectFragmentsState);
if (pendingDirectFragmentsState > 0)
{
PlayerEconomyLedger.EnsureInstance().AddMaterial(pendingDirectFragmentsState);
@@ -398,6 +404,11 @@ public class equipSmelt : MonoBehaviour
SavePersistentState();
RefreshAllSmeltPools();
RefreshAllEquipBags();
if (grantedFragments > 0)
{
gItemGet.display(gItemGet.Create("记忆碎片", ResolveMemoryFragmentSprite(), grantedFragments, ItemRarity.Uncommon));
}
}
private void HandleGetRewardClicked()
@@ -530,10 +541,30 @@ public class equipSmelt : MonoBehaviour
ReinstateRewardEquipment(generated);
storedSmeltEnergyState = Mathf.Max(0, storedSmeltEnergyState - requiredAmount);
SavePersistentState();
gItemGet.display(gItemGet.FromEquipment(generated, 1));
RefreshAllUi();
RefreshAllEquipBags();
}
private static Sprite ResolveMemoryFragmentSprite()
{
equipSmelt[] instances = FindObjectsByType<equipSmelt>(FindObjectsInactive.Include, FindObjectsSortMode.None);
if (instances == null)
{
return null;
}
for (int i = 0; i < instances.Length; i++)
{
if (instances[i] != null && instances[i].memoryFragment != null)
{
return instances[i].memoryFragment;
}
}
return null;
}
private void HandleRewardSelectorClosed()
{
activeCtasInstance = null;
@@ -959,12 +990,14 @@ public class equipSmelt : MonoBehaviour
private int GetQuickFinishCost()
{
return ssrso != null ? Mathf.Max(0, ssrso.quickFinishCost) : 0;
int baseCost = ssrso != null ? Mathf.Max(0, ssrso.quickFinishCost) : 0;
return PlayerSkillService.ModifySmeltCoinCost(baseCost);
}
private int GetStartSmeltCost()
{
return ssrso != null ? Mathf.Max(0, ssrso.startSmeltCost) : 0;
int baseCost = ssrso != null ? Mathf.Max(0, ssrso.startSmeltCost) : 0;
return PlayerSkillService.ModifySmeltCoinCost(baseCost);
}
private smeltStageRewardSO.SmeltStageRewardRequirement GetSelectedRewardRequirement()
@@ -120,6 +120,10 @@ public class equipmentRandomTestButton : MonoBehaviour
GenerateSpecialEffects(generated);
GenerateIllusionEffects(generated);
lastGeneratedEquipment = PersistGeneratedEquipment(generated);
if (lastGeneratedEquipment != null)
{
gItemGet.display(gItemGet.FromEquipment(lastGeneratedEquipment, 1));
}
BuildSummary(generated);
RefreshEquipmentList();
MarkHostDirty();
+21
View File
@@ -41,4 +41,25 @@ public class esDesPrefab : MonoBehaviour
skill_story.gameObject.SetActive(!string.IsNullOrWhiteSpace(storyText));
}
}
public void Bind(string displayName, Sprite icon, string description, string story)
{
if (skillProfile != null)
{
skillProfile.sprite = icon;
skillProfile.enabled = icon != null;
}
if (skillName != null)
skillName.text = displayName ?? string.Empty;
if (skillDescription != null)
skillDescription.text = description ?? string.Empty;
if (skill_story != null)
{
skill_story.text = story ?? string.Empty;
skill_story.gameObject.SetActive(!string.IsNullOrWhiteSpace(skill_story.text));
}
}
}
+6 -6
View File
@@ -35,7 +35,7 @@ RectTransform:
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 124.06795, y: -57}
m_AnchoredPosition: {x: 124.06795, y: -80}
m_SizeDelta: {x: 208.1359, y: 0}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &2049021961984502307
@@ -68,7 +68,7 @@ MonoBehaviour:
m_Calls: []
m_FontData:
m_Font: {fileID: 12800000, guid: bd4be44636ad6c24a9b117a7108a75e9, type: 3}
m_FontSize: 10
m_FontSize: 14
m_FontStyle: 0
m_BestFit: 0
m_MinSize: 1
@@ -211,7 +211,7 @@ MonoBehaviour:
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 0, g: 0, b: 0, a: 0.88235295}
m_Color: {r: 0, g: 0, b: 0, a: 0.9411765}
m_RaycastTarget: 0
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 0
@@ -244,7 +244,7 @@ MonoBehaviour:
m_Left: 20
m_Right: 0
m_Top: 57
m_Bottom: 10
m_Bottom: 16
m_ChildAlignment: 0
m_Spacing: 0
m_ChildForceExpandWidth: 1
@@ -379,7 +379,7 @@ RectTransform:
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 124.06795, y: -57}
m_AnchoredPosition: {x: 124.06795, y: -93}
m_SizeDelta: {x: 208.1359, y: 0}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &2792857840598114499
@@ -473,7 +473,7 @@ RectTransform:
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 124.06795, y: -57}
m_AnchoredPosition: {x: 124.06795, y: -65}
m_SizeDelta: {x: 208.1359, y: 0}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &1487207466561665800
+253
View File
@@ -0,0 +1,253 @@
using System.Collections.Generic;
using UnityEngine;
namespace Bansonic
{
public static class gItemGet
{
private const string PrefabResourcePath = "itemGet";
private static readonly Color FallbackColor = Color.white;
private static GameObject currentInstance;
private static itemGetPrefab currentController;
private static ItemRarityColorConfigSO cachedRarityConfig;
public struct ItemEntry
{
public Sprite icon;
public string displayName;
public int amount;
public ItemRarity rarity;
public bool useCustomColor;
public Color customColor;
}
public static void display(params ItemEntry[] items)
{
display((IEnumerable<ItemEntry>)items);
}
public static void display(IEnumerable<ItemEntry> items)
{
EnsureInstance();
if (currentController == null)
{
Debug.LogWarning("[gItemGet] itemGet prefab missing itemGetPrefab component.");
return;
}
currentController.ClearItems();
if (items == null)
{
return;
}
foreach (ItemEntry entry in items)
{
get_item_prefab item = currentController.AddItem();
if (item == null)
{
continue;
}
Color qualityColor = entry.useCustomColor
? entry.customColor
: ResolveRarityColor(entry.rarity);
item.Bind(entry.icon, entry.displayName, entry.amount, qualityColor);
}
}
public static ItemEntry Create(string displayName, Sprite icon, int amount = 1, ItemRarity rarity = ItemRarity.None)
{
return new ItemEntry
{
displayName = displayName,
icon = icon,
amount = Mathf.Max(1, amount),
rarity = rarity,
useCustomColor = false,
customColor = default
};
}
public static ItemEntry Create(string displayName, Sprite icon, int amount, Color qualityColor)
{
return new ItemEntry
{
displayName = displayName,
icon = icon,
amount = Mathf.Max(1, amount),
rarity = ItemRarity.None,
useCustomColor = true,
customColor = qualityColor
};
}
public static ItemEntry FromStoreItem(storeItemSO item, int amount = 1)
{
if (item == null)
{
return Create("未知物品", null, amount, ItemRarity.None);
}
return Create(item.itemName, item.itemIcon, amount, item.itemRarity);
}
public static ItemEntry FromExpBottle(expBottlesSO item, int amount = 1)
{
if (item == null)
{
return Create("未知经验瓶", null, amount, ItemRarity.None);
}
return Create(item.expBottleName, item.expBottleSprite, amount, item.itemRarity);
}
public static ItemEntry FromGrowthMaterial(growthMaterialSO item, int amount = 1)
{
if (item == null)
{
return Create("未知培养材料", null, amount, ItemRarity.None);
}
return Create(item.growthMaterialName, item.growthMaterialSprite, amount, item.itemRarity);
}
public static ItemEntry FromEquipmentConsumable(equipmentConsumableSO item, int amount = 1)
{
if (item == null)
{
return Create("未知装备材料", null, amount, ItemRarity.None);
}
return Create(item.consumableName, item.consumableSprite, amount, item.itemRarity);
}
public static ItemEntry FromEquipment(equipmentSO equipment, int amount = 1)
{
if (equipment == null)
{
return Create("未知记忆", null, amount, ItemRarity.None);
}
return Create(
equipment.GetDisplayTierName(),
equipment.GetCurrentEquipmentSprite(),
amount,
ResolveEquipmentColor(equipment));
}
private static void EnsureInstance()
{
if (currentInstance != null && currentController != null)
{
if (!currentInstance.activeInHierarchy)
{
currentInstance.SetActive(true);
}
return;
}
GameObject prefab = Resources.Load<GameObject>(PrefabResourcePath);
if (prefab == null)
{
Debug.LogWarning("[gItemGet] Failed to load Resources/itemGet.prefab");
return;
}
Transform parent = ResolveParent();
currentInstance = parent != null
? Object.Instantiate(prefab, parent, false)
: Object.Instantiate(prefab);
currentInstance.name = prefab.name;
currentController = currentInstance.GetComponent<itemGetPrefab>();
}
private static Transform ResolveParent()
{
Canvas[] canvases = Object.FindObjectsByType<Canvas>(FindObjectsInactive.Exclude, FindObjectsSortMode.None);
Canvas best = null;
for (int i = 0; i < canvases.Length; i++)
{
Canvas canvas = canvases[i];
if (canvas == null || !canvas.gameObject.activeInHierarchy || !canvas.isRootCanvas)
{
continue;
}
if (best == null || canvas.sortingOrder >= best.sortingOrder)
{
best = canvas;
}
}
return best != null ? best.transform : null;
}
private static Color ResolveRarityColor(ItemRarity rarity)
{
if (cachedRarityConfig == null)
{
#if UNITY_EDITOR
cachedRarityConfig = UnityEditor.AssetDatabase.LoadAssetAtPath<ItemRarityColorConfigSO>(
"Assets/playerBagSystem/ItemRarityColorConfig.asset");
#endif
}
if (cachedRarityConfig != null)
{
return cachedRarityConfig.GetColor(rarity, FallbackColor);
}
switch (rarity)
{
case ItemRarity.Common:
return new Color32(95, 155, 107, 255);
case ItemRarity.Uncommon:
return new Color32(74, 134, 184, 255);
case ItemRarity.Rare:
return new Color32(106, 76, 156, 255);
case ItemRarity.Epic:
return new Color32(184, 134, 69, 255);
case ItemRarity.Legendary:
return new Color32(184, 76, 76, 255);
case ItemRarity.Mythic:
return new Color32(217, 108, 158, 255);
case ItemRarity.Supreme:
return new Color32(255, 103, 164, 255);
default:
return FallbackColor;
}
}
private static Color ResolveEquipmentColor(equipmentSO equipment)
{
if (equipment == null)
{
return FallbackColor;
}
int index = equipment.GetVisualQualityColorIndex();
switch (index)
{
case 1:
return new Color32(95, 155, 107, 255);
case 2:
return new Color32(74, 134, 184, 255);
case 3:
return new Color32(106, 76, 156, 255);
case 4:
return new Color32(184, 134, 69, 255);
case 5:
return new Color32(184, 76, 76, 255);
default:
return new Color32(255, 103, 164, 255);
}
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 82dd3d62659b6a64e88a02d137a400ac
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: f1ebfa8f32810ce4ea4f2576d8dadf66
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
+43
View File
@@ -0,0 +1,43 @@
using UnityEngine;
using UnityEngine.UI;
using TMPro;
public class get_item_prefab : MonoBehaviour
{
public Image item_btm;
public Image itemProfile;
public TextMeshProUGUI itemAmount;
public Text itemName;
public void Bind(Sprite icon, string displayName, int amount, Color qualityColor)
{
if (item_btm != null)
{
item_btm.color = qualityColor;
}
if (itemProfile != null)
{
itemProfile.sprite = icon;
itemProfile.enabled = icon != null;
itemProfile.color = icon != null ? Color.white : new Color(1f, 1f, 1f, 0f);
}
if (itemName != null)
{
itemName.text = displayName ?? string.Empty;
}
if (itemAmount != null)
{
if (amount <= 1)
{
itemAmount.text = string.Empty;
}
else
{
itemAmount.text = amount.ToString();
}
}
}
}
+2
View File
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: e7f5efecd257f70488d56bf0a767230c
+423
View File
@@ -0,0 +1,423 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &18974122146848510
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 3319628771906024608}
- component: {fileID: 4359877026299959118}
- component: {fileID: 7767232844961157683}
m_Layer: 5
m_Name: btmQuality
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &3319628771906024608
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 18974122146848510}
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: 4325416963031440304}
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: 130, y: 130}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &4359877026299959118
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 18974122146848510}
m_CullTransparentMesh: 1
--- !u!114 &7767232844961157683
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 18974122146848510}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_Sprite: {fileID: 0}
m_Type: 0
m_PreserveAspect: 0
m_FillCenter: 1
m_FillMethod: 4
m_FillAmount: 1
m_FillClockwise: 1
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1
--- !u!1 &339661534610086690
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 518968684966382619}
- component: {fileID: 4988922451899572295}
- component: {fileID: 514154942639368217}
m_Layer: 5
m_Name: itemProfile
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &518968684966382619
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 339661534610086690}
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: 4325416963031440304}
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: 120, y: 120}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &4988922451899572295
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 339661534610086690}
m_CullTransparentMesh: 1
--- !u!114 &514154942639368217
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 339661534610086690}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_Sprite: {fileID: 21300000, guid: 1a62adf36834dd04181a6dd61344f8b8, type: 3}
m_Type: 0
m_PreserveAspect: 0
m_FillCenter: 1
m_FillMethod: 4
m_FillAmount: 1
m_FillClockwise: 1
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1
--- !u!1 &913995668709144583
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 4325416963031440304}
- component: {fileID: 7456664981039242979}
m_Layer: 5
m_Name: get_item_prefab
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &4325416963031440304
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 913995668709144583}
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: 3319628771906024608}
- {fileID: 518968684966382619}
- {fileID: 2293333086341986953}
- {fileID: 6074961186985790639}
m_Father: {fileID: 0}
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: 130, y: 130}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &7456664981039242979
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 913995668709144583}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: e7f5efecd257f70488d56bf0a767230c, type: 3}
m_Name:
m_EditorClassIdentifier:
item_btm: {fileID: 7767232844961157683}
itemProfile: {fileID: 514154942639368217}
itemAmount: {fileID: 508704441844867492}
itemName: {fileID: 2482204293705619698}
--- !u!1 &2281945804967682548
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 2293333086341986953}
- component: {fileID: 6679092906817300735}
- component: {fileID: 508704441844867492}
m_Layer: 5
m_Name: amt
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &2293333086341986953
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2281945804967682548}
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: 4325416963031440304}
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: -17.9, y: -40}
m_SizeDelta: {x: 148.671, y: 50}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &6679092906817300735
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2281945804967682548}
m_CullTransparentMesh: 1
--- !u!114 &508704441844867492
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2281945804967682548}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_text: 2147483647
m_isRightToLeft: 0
m_fontAsset: {fileID: 11400000, guid: 452fa97492cae71479cf143f29930751, type: 2}
m_sharedMaterial: {fileID: -346136068272202111, guid: 452fa97492cae71479cf143f29930751, type: 2}
m_fontSharedMaterials: []
m_fontMaterial: {fileID: 0}
m_fontMaterials: []
m_fontColor32:
serializedVersion: 2
rgba: 4294967295
m_fontColor: {r: 1, g: 1, b: 1, a: 1}
m_enableVertexGradient: 0
m_colorMode: 3
m_fontColorGradient:
topLeft: {r: 1, g: 1, b: 1, a: 1}
topRight: {r: 1, g: 1, b: 1, a: 1}
bottomLeft: {r: 1, g: 1, b: 1, a: 1}
bottomRight: {r: 1, g: 1, b: 1, a: 1}
m_fontColorGradientPreset: {fileID: 0}
m_spriteAsset: {fileID: 0}
m_tintAllSprites: 0
m_StyleSheet: {fileID: 0}
m_TextStyleHashCode: -1183493901
m_overrideHtmlColors: 0
m_faceColor:
serializedVersion: 2
rgba: 4294967295
m_fontSize: 24
m_fontSizeBase: 24
m_fontWeight: 400
m_enableAutoSizing: 0
m_fontSizeMin: 18
m_fontSizeMax: 72
m_fontStyle: 0
m_HorizontalAlignment: 4
m_VerticalAlignment: 512
m_textAlignment: 65535
m_characterSpacing: 0
m_wordSpacing: 0
m_lineSpacing: 0
m_lineSpacingMax: 0
m_paragraphSpacing: 0
m_charWidthMaxAdj: 0
m_TextWrappingMode: 1
m_wordWrappingRatios: 0.4
m_overflowMode: 0
m_linkedTextComponent: {fileID: 0}
parentLinkedComponent: {fileID: 0}
m_enableKerning: 0
m_ActiveFontFeatures: 6e72656b
m_enableExtraPadding: 0
checkPaddingRequired: 0
m_isRichText: 1
m_EmojiFallbackSupport: 1
m_parseCtrlCharacters: 1
m_isOrthographic: 1
m_isCullingEnabled: 0
m_horizontalMapping: 0
m_verticalMapping: 0
m_uvLineOffset: 0
m_geometrySortingOrder: 0
m_IsTextObjectScaleStatic: 0
m_VertexBufferAutoSizeReduction: 0
m_useMaxVisibleDescender: 1
m_pageToDisplay: 1
m_margin: {x: 0, y: 0, z: 0, w: 0}
m_isUsingLegacyAnimationComponent: 0
m_isVolumetricText: 0
m_hasFontAssetChanged: 0
m_baseMaterial: {fileID: 0}
m_maskOffset: {x: 0, y: 0, z: 0, w: 0}
--- !u!1 &4937134612620184442
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 6074961186985790639}
- component: {fileID: 3728309417902643327}
- component: {fileID: 2482204293705619698}
m_Layer: 5
m_Name: name
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &6074961186985790639
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4937134612620184442}
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: 4325416963031440304}
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: -86.05}
m_SizeDelta: {x: 140, y: 30}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &3728309417902643327
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4937134612620184442}
m_CullTransparentMesh: 1
--- !u!114 &2482204293705619698
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4937134612620184442}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_FontData:
m_Font: {fileID: 12800000, guid: dfa10de3e2846524089b5073175cd151, type: 3}
m_FontSize: 14
m_FontStyle: 0
m_BestFit: 1
m_MinSize: 10
m_MaxSize: 20
m_Alignment: 4
m_AlignByGeometry: 0
m_RichText: 1
m_HorizontalOverflow: 0
m_VerticalOverflow: 0
m_LineSpacing: 1
m_Text: "\u4ED9\u54C1\u5076\u50CF\u590D\u6F14\u5355\u5143"
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: acdf60e42009ece499bb3c9187c7a120
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
+70
View File
@@ -0,0 +1,70 @@
using UnityEngine;
using UnityEngine.UI;
using System.Collections.Generic;
public class itemGetPrefab : MonoBehaviour
{
[Header("item prefab")]
public GameObject itemPrefab;
public Transform displayParent;
[Header("btn")]
public Button close;
private readonly List<GameObject> spawnedItems = new List<GameObject>();
private void Awake()
{
if (close != null)
{
close.onClick.RemoveListener(CloseSelf);
close.onClick.AddListener(CloseSelf);
}
}
private void OnDestroy()
{
if (close != null)
{
close.onClick.RemoveListener(CloseSelf);
}
}
public void ClearItems()
{
for (int i = 0; i < spawnedItems.Count; i++)
{
if (spawnedItems[i] != null)
{
Destroy(spawnedItems[i]);
}
}
spawnedItems.Clear();
if (displayParent != null)
{
for (int i = displayParent.childCount - 1; i >= 0; i--)
{
Destroy(displayParent.GetChild(i).gameObject);
}
}
}
public get_item_prefab AddItem()
{
if (itemPrefab == null || displayParent == null)
{
return null;
}
GameObject instance = Instantiate(itemPrefab, displayParent);
spawnedItems.Add(instance);
return instance.GetComponent<get_item_prefab>();
}
public void CloseSelf()
{
Destroy(gameObject);
}
}
+2
View File
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 39b86a94e0f9b43418207c0c1a25c044
+24 -18
View File
@@ -3043,7 +3043,7 @@ MonoBehaviour:
m_PressedTrigger: Pressed
m_SelectedTrigger: Selected
m_DisabledTrigger: Disabled
m_Interactable: 1
m_Interactable: 0
m_TargetGraphic: {fileID: 4599931531580898861}
m_OnClick:
m_PersistentCalls:
@@ -5868,7 +5868,7 @@ MonoBehaviour:
m_HorizontalOverflow: 0
m_VerticalOverflow: 0
m_LineSpacing: 1
m_Text: "\u8FD8\u5DEE2\u573A\u6BD4\u8D5B\u53EF\u63D0\u53D6\u5956\u52B1/\u878D\u5408\u5B8C\u6BD5\uFF0C\u53EF\u9886\u53D6\u5956\u52B1"
m_Text:
--- !u!1 &1496425020052927388
GameObject:
m_ObjectHideFlags: 0
@@ -8141,7 +8141,7 @@ MonoBehaviour:
m_PressedTrigger: Pressed
m_SelectedTrigger: Selected
m_DisabledTrigger: Disabled
m_Interactable: 1
m_Interactable: 0
m_TargetGraphic: {fileID: 8317396197396341973}
m_OnClick:
m_PersistentCalls:
@@ -10526,7 +10526,7 @@ MonoBehaviour:
m_HorizontalOverflow: 0
m_VerticalOverflow: 0
m_LineSpacing: 1
m_Text: 2000 / 2000
m_Text: 0/3000
--- !u!1 &3049892735558273088
GameObject:
m_ObjectHideFlags: 0
@@ -10857,7 +10857,7 @@ MonoBehaviour:
m_HorizontalOverflow: 0
m_VerticalOverflow: 0
m_LineSpacing: 1
m_Text: 2
m_Text: 0
--- !u!1 &3213626675873551214
GameObject:
m_ObjectHideFlags: 0
@@ -11214,7 +11214,7 @@ MonoBehaviour:
m_HorizontalOverflow: 0
m_VerticalOverflow: 0
m_LineSpacing: 1
m_Text: "\u878D\u5408\u8FDB\u5EA6"
m_Text: "\u878D\u5408\u8FDB\u5EA60/1"
--- !u!1 &3313849891983255375
GameObject:
m_ObjectHideFlags: 0
@@ -13152,7 +13152,7 @@ MonoBehaviour:
m_PreserveAspect: 0
m_FillCenter: 1
m_FillMethod: 4
m_FillAmount: 0.5
m_FillAmount: 0
m_FillClockwise: 1
m_FillOrigin: 0
m_UseSpriteMesh: 0
@@ -13310,7 +13310,7 @@ MonoBehaviour:
m_HorizontalOverflow: 0
m_VerticalOverflow: 0
m_LineSpacing: 1
m_Text: reason.why
m_Text: "\u9700\u8981\u6295\u5165\u8BB0\u5FC6"
--- !u!1 &3966248874610226284
GameObject:
m_ObjectHideFlags: 0
@@ -15311,7 +15311,7 @@ MonoBehaviour:
m_HorizontalOverflow: 0
m_VerticalOverflow: 0
m_LineSpacing: 1
m_Text: Option A
m_Text: "<color=#FF0000>40 \u968F\u673A\u8BB0\u5FC6</color>"
--- !u!1 &4635021010433457706
GameObject:
m_ObjectHideFlags: 0
@@ -16644,7 +16644,7 @@ MonoBehaviour:
m_HorizontalOverflow: 0
m_VerticalOverflow: 0
m_LineSpacing: 1
m_Text: "1000\u7B97\u529B\u5FEB\u901F\u5B8C\u6210"
m_Text: 0
--- !u!1 &5018197546540534172
GameObject:
m_ObjectHideFlags: 0
@@ -19386,11 +19386,17 @@ MonoBehaviour:
m_Value: 0
m_Options:
m_Options:
- m_Text: Option A
- m_Text: "<color=#FF0000>40 \u968F\u673A\u8BB0\u5FC6</color>"
m_Image: {fileID: 0}
- m_Text: Option B
- m_Text: "<color=#FF0000>60 \u81EA\u9009\u8BB0\u5FC6</color>"
m_Image: {fileID: 0}
- m_Text: Option C
- m_Text: "<color=#FF0000>200 \u81EA\u9009\u9AD8\u5929\u8D4B\u8BB0\u5FC6</color>"
m_Image: {fileID: 0}
- m_Text: "<color=#FF0000>500 \u81EA\u9009\u73CD\u85CF\u8BB0\u5FC6</color>"
m_Image: {fileID: 0}
- m_Text: "<color=#FF0000>1000 \u81EA\u9009\u81F3\u81FB\u8BB0\u5FC6</color>"
m_Image: {fileID: 0}
- m_Text: "<color=#FF0000>1500 \u81EA\u9009\u523B\u9AA8\u94ED\u5FC3\u8BB0\u5FC6</color>"
m_Image: {fileID: 0}
m_OnValueChanged:
m_PersistentCalls:
@@ -24893,7 +24899,7 @@ GameObject:
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
m_IsActive: 0
--- !u!224 &8851354205082234328
RectTransform:
m_ObjectHideFlags: 0
@@ -25110,7 +25116,7 @@ MonoBehaviour:
m_HorizontalOverflow: 0
m_VerticalOverflow: 0
m_LineSpacing: 1
m_Text: 2048
m_Text: 0
--- !u!1 &8192863506754736897
GameObject:
m_ObjectHideFlags: 0
@@ -25493,7 +25499,7 @@ MonoBehaviour:
m_PressedTrigger: Pressed
m_SelectedTrigger: Selected
m_DisabledTrigger: Disabled
m_Interactable: 1
m_Interactable: 0
m_TargetGraphic: {fileID: 4344585137749710138}
m_OnClick:
m_PersistentCalls:
@@ -26969,7 +26975,7 @@ MonoBehaviour:
m_MinValue: 0
m_MaxValue: 1
m_WholeNumbers: 0
m_Value: 0.5
m_Value: 0
m_OnValueChanged:
m_PersistentCalls:
m_Calls: []
@@ -28050,7 +28056,7 @@ MonoBehaviour:
m_HorizontalOverflow: 0
m_VerticalOverflow: 0
m_LineSpacing: 1
m_Text: 2048
m_Text: 0
--- !u!1 &9107132343803959900
GameObject:
m_ObjectHideFlags: 0
File diff suppressed because it is too large Load Diff
@@ -164,6 +164,7 @@ GameObject:
m_Component:
- component: {fileID: 6155334586977510247}
- component: {fileID: 4151510886845045432}
- component: {fileID: 7562484254110654814}
m_Layer: 5
m_Name: uAchievementPrefab
m_TagString: Untagged
@@ -208,6 +209,18 @@ MonoBehaviour:
aName: {fileID: 6612220277252403227}
aGetDate: {fileID: 8035948722274830026}
aDescription: {fileID: 1893507208843142754}
--- !u!114 &7562484254110654814
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3853073308254161695}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 76ce63b908338a84c8a3aa071b90c46b, type: 3}
m_Name:
m_EditorClassIdentifier:
--- !u!1 &4178773801772122773
GameObject:
m_ObjectHideFlags: 0
+50
View File
@@ -10,4 +10,54 @@ public class uLevel : MonoBehaviour
public Text uL_post;
public Button view_levelDetail;
public Button close_levelDetail;
[Header("uLevelPanel")]
public GameObject uLevelPanel;
public uLevel_skills uls;
[Header("so")]
public Player_SO pso;
private void Start()
{
if (pso == null)
pso = Resources.Load<Player_SO>("playerdata/playerData_uniqueData");
if (uLevelPanel != null)
uLevelPanel.SetActive(false);
if (uls != null && pso != null)
uls.SetPlayerSo(pso);
if (view_levelDetail != null)
{
view_levelDetail.onClick.RemoveListener(OpenLevelDetailPanel);
view_levelDetail.onClick.AddListener(OpenLevelDetailPanel);
}
if (close_levelDetail != null)
{
close_levelDetail.onClick.RemoveListener(CloseLevelDetailPanel);
close_levelDetail.onClick.AddListener(CloseLevelDetailPanel);
}
}
private void OpenLevelDetailPanel()
{
if (uLevelPanel == null)
return;
if (uls != null && pso != null)
uls.SetPlayerSo(pso);
uLevelPanel.SetActive(true);
}
private void CloseLevelDetailPanel()
{
if (uLevelPanel != null)
uLevelPanel.SetActive(false);
}
}
@@ -18,6 +18,7 @@ public class uBehaviourRaderController : MonoBehaviour
public URadarChartController radarChartController;
public UGUIChartBridge chartBridge;
public RankConfig rankConfig;
public bool hideWhenOverlayVisible = false;
[Header("Async")]
public bool reloadOnEnable = true;
@@ -175,10 +176,20 @@ public class uBehaviourRaderController : MonoBehaviour
child.gameObject.SetActive(child == target);
}
if (!uRaderObj.activeSelf)
{
uRaderObj.SetActive(true);
}
}
private void BindOverlayVisibility()
{
if (!hideWhenOverlayVisible)
{
return;
}
if (overlaySubscribed)
{
return;
@@ -218,7 +229,7 @@ public class uBehaviourRaderController : MonoBehaviour
return;
}
uRaderObj.SetActive(!overlayVisible);
uRaderObj.SetActive(!hideWhenOverlayVisible || !overlayVisible);
}
private void ApplySummary(BehaviourRadarSummary summary)
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 96251f1ca650d554f886d2e2ea7bde5b
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,296 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &2099462153568767799
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 665396819362690529}
- component: {fileID: 3192217589302937993}
- component: {fileID: 5556623676502886536}
m_Layer: 5
m_Name: levelID
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &665396819362690529
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2099462153568767799}
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: 9152270112823009895}
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: -107.33, y: 0}
m_SizeDelta: {x: 25.792, y: 30}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &3192217589302937993
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2099462153568767799}
m_CullTransparentMesh: 1
--- !u!114 &5556623676502886536
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2099462153568767799}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_FontData:
m_Font: {fileID: 12800000, guid: 8b8373b0af11dca46b89be60dbe469f8, type: 3}
m_FontSize: 20
m_FontStyle: 0
m_BestFit: 0
m_MinSize: 2
m_MaxSize: 40
m_Alignment: 4
m_AlignByGeometry: 0
m_RichText: 1
m_HorizontalOverflow: 0
m_VerticalOverflow: 0
m_LineSpacing: 1
m_Text: 10
--- !u!1 &2343926165364488871
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 9152270112823009895}
- component: {fileID: 4801688296739999581}
- component: {fileID: 4501378674247754304}
m_Layer: 5
m_Name: btm
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &9152270112823009895
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2343926165364488871}
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: 2290428063649654242}
- {fileID: 665396819362690529}
m_Father: {fileID: 2460305581810160109}
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: 250, y: 30}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &4801688296739999581
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2343926165364488871}
m_CullTransparentMesh: 1
--- !u!114 &4501378674247754304
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2343926165364488871}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_Sprite: {fileID: -52179173452712981, guid: be120bf969ae2c84fa997ecca6dd28e6, type: 3}
m_Type: 1
m_PreserveAspect: 0
m_FillCenter: 1
m_FillMethod: 4
m_FillAmount: 1
m_FillClockwise: 1
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 2
--- !u!1 &3339470438795980614
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 2290428063649654242}
- component: {fileID: 4129409205783608839}
- component: {fileID: 534678815217464394}
m_Layer: 5
m_Name: skillName
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &2290428063649654242
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3339470438795980614}
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: 9152270112823009895}
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: 1.4, y: 0}
m_SizeDelta: {x: 187.733, y: 30}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &4129409205783608839
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3339470438795980614}
m_CullTransparentMesh: 1
--- !u!114 &534678815217464394
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3339470438795980614}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_FontData:
m_Font: {fileID: 12800000, guid: dfa10de3e2846524089b5073175cd151, type: 3}
m_FontSize: 20
m_FontStyle: 0
m_BestFit: 0
m_MinSize: 2
m_MaxSize: 40
m_Alignment: 3
m_AlignByGeometry: 0
m_RichText: 1
m_HorizontalOverflow: 0
m_VerticalOverflow: 0
m_LineSpacing: 1
m_Text: "\u5076\u50CF\u5927\u5E08\uFF1A\u8D5B\u540E\u611F\u609F"
--- !u!1 &4419549278339915466
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 2460305581810160109}
- component: {fileID: 7517620086478948793}
m_Layer: 5
m_Name: levelRewardPrefab
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &2460305581810160109
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4419549278339915466}
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: 9152270112823009895}
m_Father: {fileID: 0}
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: 450, y: 30}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &7517620086478948793
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4419549278339915466}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 427d68583c7d9ab4588888b68dc7a8d2, type: 3}
m_Name:
m_EditorClassIdentifier:
enableSprite: {fileID: -52179173452712981, guid: be120bf969ae2c84fa997ecca6dd28e6, type: 3}
availableSprite: {fileID: 2561534620446350566, guid: 23a48ca1e983a4c47971fcf7eab26b89, type: 3}
lockedSprite: {fileID: -1936355827857895663, guid: fa360ec6245a3dd43bfbae1ac1093a6e, type: 3}
unknownSprite: {fileID: 21300000, guid: 931f6455943555649a61ed7f1c76cbf6, type: 3}
preSelectSprite: {fileID: 7919194353434859991, guid: b35fcaa46fa9f3e49b71c103f69df698, type: 3}
levelName: {fileID: 5556623676502886536}
statusImg: {fileID: 4501378674247754304}
thisSkillName: {fileID: 534678815217464394}
descriptionPrefab: {fileID: 2219571326304505587, guid: bde76837f913f3943836d4f83292618b, type: 3}
descriptionOffsetX: 150
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 26d681beab8631442ac57714a80f1f37
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
+184
View File
@@ -0,0 +1,184 @@
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using System.Collections;
public class lrPrefab : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler, IPointerClickHandler
{
[Header("sprite")]
public Sprite enableSprite;
public Sprite availableSprite;
public Sprite lockedSprite;
public Sprite unknownSprite;
public Sprite preSelectSprite;
[Header("uis")]
public Text levelName;
public Image statusImg;
public Text thisSkillName;
[Header("desOBJ")]
public GameObject descriptionPrefab;
public float descriptionOffsetX = 80f;
private uLevel_skills owner;
private userLevel_skills_SO ownerSo;
private userLevel_skills_SO.UserLevelSkillEntry boundEntry;
private int boundIndex = -1;
private bool isUnlocked = false;
private Coroutine hoverCoroutine;
private GameObject spawnedDescription;
public void Bind(uLevel_skills ownerController, userLevel_skills_SO sourceSo, int index, userLevel_skills_SO.UserLevelSkillEntry entry, bool unlocked)
{
owner = ownerController;
ownerSo = sourceSo;
boundIndex = index;
boundEntry = entry;
isUnlocked = unlocked;
if (levelName != null)
levelName.text = entry != null ? entry.userLevel.ToString() : string.Empty;
RefreshVisualState();
}
public void RefreshVisualState()
{
if (owner != null && boundEntry != null)
isUnlocked = owner.IsSkillUnlocked(boundEntry);
if (boundEntry == null)
return;
bool revealLockedSkills = PlayerSkillService.IsSkillEnabled(7);
bool shouldHideLockedSkillInfo = !isUnlocked && !revealLockedSkills;
if (thisSkillName != null)
{
thisSkillName.text = shouldHideLockedSkillInfo
? "?????"
: (boundEntry.skillName ?? string.Empty);
}
if (statusImg == null)
return;
if (owner != null && owner.IsSkillPreselected(boundIndex))
statusImg.sprite = preSelectSprite != null ? preSelectSprite : availableSprite;
else if (boundEntry.isEnabled)
statusImg.sprite = enableSprite;
else if (isUnlocked)
statusImg.sprite = availableSprite;
else if (shouldHideLockedSkillInfo)
statusImg.sprite = unknownSprite != null ? unknownSprite : lockedSprite;
else
statusImg.sprite = lockedSprite;
}
public void OnPointerEnter(PointerEventData eventData)
{
if (boundEntry == null || descriptionPrefab == null)
return;
if (!isUnlocked && !PlayerSkillService.IsSkillEnabled(7))
return;
if (hoverCoroutine != null)
StopCoroutine(hoverCoroutine);
hoverCoroutine = StartCoroutine(ShowDescriptionAfterDelay());
}
public void OnPointerExit(PointerEventData eventData)
{
if (hoverCoroutine != null)
{
StopCoroutine(hoverCoroutine);
hoverCoroutine = null;
}
HideDescription();
}
public void OnPointerClick(PointerEventData eventData)
{
if (owner == null || boundIndex < 0)
return;
owner.ToggleSkill(boundIndex);
}
private IEnumerator ShowDescriptionAfterDelay()
{
yield return new WaitForSeconds(0.5f);
hoverCoroutine = null;
ShowDescription();
}
private void ShowDescription()
{
if (spawnedDescription != null || descriptionPrefab == null || boundEntry == null)
return;
RectTransform root = ResolveDescriptionRoot();
if (root == null)
return;
spawnedDescription = Instantiate(descriptionPrefab, root);
spawnedDescription.SetActive(true);
spawnedDescription.transform.SetAsLastSibling();
esDesPrefab detail = spawnedDescription.GetComponent<esDesPrefab>();
if (detail != null)
detail.Bind(boundEntry.skillName, boundEntry.skillIcon, boundEntry.skillDescription, boundEntry.skillSummary);
RectTransform spawnedRect = spawnedDescription.GetComponent<RectTransform>();
if (spawnedRect == null)
return;
Canvas canvas = root.GetComponentInParent<Canvas>();
Camera eventCamera = null;
if (canvas != null && canvas.renderMode != RenderMode.ScreenSpaceOverlay)
eventCamera = canvas.worldCamera;
Vector2 localPoint;
RectTransformUtility.ScreenPointToLocalPointInRectangle(root, Input.mousePosition, eventCamera, out localPoint);
localPoint.x += descriptionOffsetX;
spawnedRect.anchoredPosition = localPoint;
}
private RectTransform ResolveDescriptionRoot()
{
Canvas canvas = GetComponentInParent<Canvas>();
if (canvas == null)
return null;
Canvas rootCanvas = canvas.rootCanvas != null ? canvas.rootCanvas : canvas;
return rootCanvas.transform as RectTransform;
}
private void HideDescription()
{
if (spawnedDescription == null)
return;
if (Application.isPlaying)
Destroy(spawnedDescription);
else
DestroyImmediate(spawnedDescription);
spawnedDescription = null;
}
private void OnDisable()
{
if (hoverCoroutine != null)
{
StopCoroutine(hoverCoroutine);
hoverCoroutine = null;
}
HideDescription();
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 427d68583c7d9ab4588888b68dc7a8d2
@@ -0,0 +1,415 @@
using UnityEngine;
using UnityEngine.UI;
public class uLevel_skills : MonoBehaviour
{
public userLevel_skills_SO ulsSO;
public Player_SO pso;
[Header("objs")]
public GameObject uSkillBarPrefab;
public Transform uSkillBarParent;
[Header("current selected skill details")]
public Image btm_skillImage;
public Image skillIcon_Profile;
public Text skill_thisSkillName;
public Text skill_thisSkillSummary;
[Header("change")]
public Slider need_progress;
public Text need_text;
public Text need_howmuchCoins;
public Button yesChangeButton;
public Button noCancelButton;
private readonly System.Collections.Generic.List<lrPrefab> spawnedBars = new System.Collections.Generic.List<lrPrefab>();
private bool hasStarted = false;
private int pendingSkillIndex = -1;
private Color defaultNeedCoinsColor = Color.white;
private const int SkillSwitchCooldownMatches = 3;
private const int SkillSwitchMinimumCost = 200;
private void Start()
{
hasStarted = true;
CacheUiDefaults();
RegisterButtons();
PlayerSkillService.RegisterSkillAsset(ulsSO);
RefreshSkillBars();
}
private void OnEnable()
{
CacheUiDefaults();
RegisterButtons();
PlayerSkillService.RegisterSkillAsset(ulsSO);
if (hasStarted)
{
RefreshSkillBars();
}
}
private void OnDestroy()
{
UnregisterButtons();
}
public void SetPlayerSo(Player_SO playerSo)
{
pso = playerSo;
}
public void RefreshSkillBars()
{
EnsurePlayerSo();
if (uSkillBarParent == null || uSkillBarPrefab == null || ulsSO == null)
return;
NormalizeSelectionState();
ClearExistingBars();
spawnedBars.Clear();
for (int i = 0; i < ulsSO.skills.Count; i++)
{
var entry = ulsSO.skills[i];
if (entry == null)
continue;
GameObject instance = Instantiate(uSkillBarPrefab, uSkillBarParent);
instance.SetActive(true);
lrPrefab bar = instance.GetComponent<lrPrefab>();
if (bar == null)
continue;
bar.Bind(this, ulsSO, i, entry, IsSkillUnlocked(entry));
spawnedBars.Add(bar);
}
RefreshDetailPanel();
RefreshChangeUi();
}
public void ToggleSkill(int index)
{
if (ulsSO == null || index < 0 || index >= ulsSO.skills.Count)
return;
var entry = ulsSO.skills[index];
if (entry == null || !IsSkillUnlocked(entry))
return;
int currentEnabledIndex = GetEnabledSkillIndex();
if (index == currentEnabledIndex)
{
pendingSkillIndex = -1;
RefreshDetailPanel();
RefreshChangeUi();
RefreshStatusesOnly();
return;
}
pendingSkillIndex = pendingSkillIndex == index ? -1 : index;
RefreshDetailPanel();
RefreshChangeUi();
RefreshStatusesOnly();
}
public bool IsSkillPreselected(int index)
{
return pendingSkillIndex >= 0 && pendingSkillIndex == index;
}
public bool IsSkillUnlocked(userLevel_skills_SO.UserLevelSkillEntry entry)
{
EnsurePlayerSo();
if (entry == null)
return false;
int currentExp = pso != null ? Mathf.Max(0, pso.player_currentEXP) : 0;
return currentExp >= Mathf.Max(0, entry.thisLevelNeedExps);
}
private void RefreshStatusesOnly()
{
for (int i = 0; i < spawnedBars.Count; i++)
{
if (spawnedBars[i] == null)
continue;
spawnedBars[i].RefreshVisualState();
}
}
private void RefreshDetailPanel()
{
if (ulsSO == null || ulsSO.skills == null || ulsSO.skills.Count == 0)
{
SetDetailPanel(null);
return;
}
int detailIndex = pendingSkillIndex >= 0 ? pendingSkillIndex : GetEnabledSkillIndex();
if (detailIndex < 0 || detailIndex >= ulsSO.skills.Count)
{
SetDetailPanel(null);
return;
}
SetDetailPanel(ulsSO.skills[detailIndex]);
}
private void SetDetailPanel(userLevel_skills_SO.UserLevelSkillEntry entry)
{
if (btm_skillImage != null)
{
btm_skillImage.sprite = entry != null ? entry.skillIcon : null;
}
if (skillIcon_Profile != null)
{
skillIcon_Profile.sprite = entry != null ? entry.skillIcon : null;
}
if (skill_thisSkillName != null)
{
skill_thisSkillName.text = entry != null ? (entry.skillName ?? string.Empty) : string.Empty;
}
if (skill_thisSkillSummary != null)
{
skill_thisSkillSummary.text = entry != null ? (entry.skillDescription ?? string.Empty) : string.Empty;
}
}
private void RefreshChangeUi()
{
int cooldownRemaining = PlayerSkillService.GetSkillSwitchCooldownRemainingMatches();
int currentEnabledIndex = GetEnabledSkillIndex();
bool hasPendingSelection = pendingSkillIndex >= 0 && pendingSkillIndex != currentEnabledIndex;
if (need_text != null)
{
need_text.text = cooldownRemaining > 0
? $"还需要{cooldownRemaining}场比赛"
: "可以切换技能";
}
if (need_progress != null)
{
need_progress.minValue = 0f;
need_progress.maxValue = 1f;
need_progress.value = cooldownRemaining > 0
? Mathf.Clamp01((float)(SkillSwitchCooldownMatches - cooldownRemaining) / SkillSwitchCooldownMatches)
: 1f;
}
int switchCost = GetSkillSwitchCost();
bool hasEnoughCoins = HasEnoughCoinsForSwitch(switchCost);
if (need_howmuchCoins != null)
{
need_howmuchCoins.text = switchCost.ToString();
need_howmuchCoins.color = hasEnoughCoins ? defaultNeedCoinsColor : Color.red;
}
if (yesChangeButton != null)
{
yesChangeButton.interactable = hasPendingSelection && cooldownRemaining <= 0 && hasEnoughCoins;
}
if (noCancelButton != null)
{
noCancelButton.interactable = pendingSkillIndex >= 0;
}
}
private int GetSkillSwitchCost()
{
int currentCoins = Application.isPlaying
? PlayerEconomyLedger.EnsureInstance().GetCoins()
: (pso != null ? Mathf.Max(0, pso.Coins) : 0);
int percentCost = Mathf.CeilToInt(currentCoins * 0.01f);
return Mathf.Max(SkillSwitchMinimumCost, percentCost);
}
private bool HasEnoughCoinsForSwitch(int amount)
{
if (amount <= 0)
return true;
return Application.isPlaying
? PlayerEconomyLedger.EnsureInstance().HasEnoughCoins(amount)
: (pso != null && pso.Coins >= amount);
}
private void HandleConfirmSwitchClicked()
{
int currentEnabledIndex = GetEnabledSkillIndex();
if (pendingSkillIndex < 0 || pendingSkillIndex == currentEnabledIndex || ulsSO == null)
{
return;
}
if (PlayerSkillService.GetSkillSwitchCooldownRemainingMatches() > 0)
{
RefreshChangeUi();
return;
}
int switchCost = GetSkillSwitchCost();
bool spent = Application.isPlaying
? PlayerEconomyLedger.EnsureInstance().TrySpendCoins(switchCost)
: (pso != null && pso.TrySpendCoins(switchCost));
if (!spent)
{
RefreshChangeUi();
return;
}
PlayerSkillService.ConfirmSkillSelection(ulsSO, pendingSkillIndex);
pendingSkillIndex = -1;
MarkSkillsDirty();
RefreshStatusesOnly();
RefreshDetailPanel();
RefreshChangeUi();
}
private void HandleCancelPreselectClicked()
{
pendingSkillIndex = -1;
RefreshStatusesOnly();
RefreshDetailPanel();
RefreshChangeUi();
}
private void ClearExistingBars()
{
for (int i = uSkillBarParent.childCount - 1; i >= 0; i--)
{
Transform child = uSkillBarParent.GetChild(i);
if (Application.isPlaying)
Destroy(child.gameObject);
else
DestroyImmediate(child.gameObject);
}
}
private void MarkSkillsDirty()
{
#if UNITY_EDITOR
if (!Application.isPlaying && ulsSO != null)
UnityEditor.EditorUtility.SetDirty(ulsSO);
#endif
}
private void EnsurePlayerSo()
{
if (pso == null)
pso = Resources.Load<Player_SO>("playerdata/playerData_uniqueData");
}
private void CacheUiDefaults()
{
if (need_howmuchCoins != null)
{
defaultNeedCoinsColor = need_howmuchCoins.color;
}
}
private void RegisterButtons()
{
if (yesChangeButton != null)
{
yesChangeButton.onClick.RemoveListener(HandleConfirmSwitchClicked);
yesChangeButton.onClick.AddListener(HandleConfirmSwitchClicked);
}
if (noCancelButton != null)
{
noCancelButton.onClick.RemoveListener(HandleCancelPreselectClicked);
noCancelButton.onClick.AddListener(HandleCancelPreselectClicked);
}
}
private void UnregisterButtons()
{
if (yesChangeButton != null)
{
yesChangeButton.onClick.RemoveListener(HandleConfirmSwitchClicked);
}
if (noCancelButton != null)
{
noCancelButton.onClick.RemoveListener(HandleCancelPreselectClicked);
}
}
private int GetEnabledSkillIndex()
{
if (ulsSO == null || ulsSO.skills == null)
return -1;
for (int i = 0; i < ulsSO.skills.Count; i++)
{
var entry = ulsSO.skills[i];
if (entry != null && entry.isEnabled)
return i;
}
return -1;
}
private void NormalizeSelectionState()
{
if (ulsSO == null || ulsSO.skills == null || ulsSO.skills.Count == 0)
return;
int selectedIndex = -1;
for (int i = 0; i < ulsSO.skills.Count; i++)
{
var entry = ulsSO.skills[i];
if (entry == null || !entry.isEnabled)
continue;
if (selectedIndex < 0)
{
selectedIndex = i;
}
else
{
entry.isEnabled = false;
}
}
if (selectedIndex < 0)
{
for (int i = 0; i < ulsSO.skills.Count; i++)
{
var entry = ulsSO.skills[i];
if (entry == null)
continue;
selectedIndex = i;
entry.isEnabled = true;
break;
}
}
for (int i = 0; i < ulsSO.skills.Count; i++)
{
var entry = ulsSO.skills[i];
if (entry == null)
continue;
entry.isEnabled = (i == selectedIndex);
}
MarkSkillsDirty();
PlayerSkillService.RegisterSkillAsset(ulsSO);
pendingSkillIndex = -1;
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 522d48b038e44bd4289b57ea155ae0b9
+92
View File
@@ -0,0 +1,92 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 19a25568f1e1a8b4093dce8a6753be0e, type: 3}
m_Name: ulsSO
m_EditorClassIdentifier:
skills:
- userLevel: 0
skillName: "\u8D5B\u524D\u51C6\u5907"
skillDescription: "\u4F60\u5DF2\u6765\u5230\u672C\u7D22\u5C3C\u514B\u4E16\u754C\u3002\u8D5B\u524D\u51C6\u5907\u65F6\uFF0C\u4F60\u53EF\u4EE5\u65E0\u9650\u5236\u5730\u8FDB\u5165\u65B0\u624B\u6559\u7A0B\u3002"
skillSummary: "\u5378\u4E0B\u5B83\u65F6\u4F60\u5DF2\u4E0D\u518D\u662F\u65B0\u624B"
isEnabled: 1
skillIcon: {fileID: 0}
thisLevelNeedExps: 0
- userLevel: 1
skillName: "\u8BB0\u5FC6\u8D2D\u4E70\u8BA1\u5212"
skillDescription: "\u5141\u8BB8\u4F60\u4EE510\u91D1\u5E01\u8D2D\u4E701\u4E2A\u8BB0\u5FC6\u788E\u7247\u3002\u88C5\u5907\u6B64\u6280\u80FD\u65F6\u53EF\u4E8E\u5546\u5E97\u89E3\u9501\u4E00\u4E2A\u8D2D\u4E70\u9009\u9879\u3002"
skillSummary: "\u4ECE\u8001\u5E08\u90A3\u91CC\u65B0\u5B66\u4E86\u4EC0\u4E48\uFF1F"
isEnabled: 0
skillIcon: {fileID: 0}
thisLevelNeedExps: 200
- userLevel: 2
skillName: "\u8BB0\u5FC6\u5F52\u8FD8\u8BA1\u5212"
skillDescription: "\u5141\u8BB8\u4F60\u5C061\u4E2A\u8BB0\u5FC6\u788E\u7247\u4EE54\u91D1\u5E01\u552E\u51FA\u3002\u88C5\u5907\u6B64\u6280\u80FD\u65F6\u53EF\u4E8E\u5546\u5E97\u89E3\u9501\u4E00\u4E2A\u8D2D\u4E70\u9009\u9879\u3002"
skillSummary: "\u8001\u5E08\u6559\u7ED9\u4F60\u7684\u53C8\u8FD8\u56DE\u53BB\u4E86\u5417\uFF1F"
isEnabled: 0
skillIcon: {fileID: 0}
thisLevelNeedExps: 300
- userLevel: 3
skillName: "\u6311\u6218\u8005\u6A21\u578B"
skillDescription: "\u5141\u8BB8\u8BBE\u7F6E\u4E00\u4E2A\u81EA\u5B9A\u7684\u767E\u5206\u6BD4\u9ED1\u5E55\u6765\u906E\u4F4F\u8F68\u9053\u3002\u6700\u5C11\u906E\u632120%\uFF0C\u6700\u591A\u906E\u632190%\u3002\u6BCF\u906E\u63211%\uFF0C\u63D0\u4F9B1.5%\u7ED3\u7B97\u5956\u52B1\u52A0\u6210\u3002"
skillSummary: "\u9AD8\u98CE\u9669\u9AD8\u56DE\u62A5\uFF0C\u597D\u5947\u5FC3\u5BB3\u6B7B\u732B\u3002"
isEnabled: 0
skillIcon: {fileID: 0}
thisLevelNeedExps: 400
- userLevel: 4
skillName: "\u8D5B\u540E\u611F\u609F"
skillDescription: "\u6BCF\u8FDB\u884C10\u573A\u6BD4\u8D5B\u53EF\u83B7\u5F97\u4E00\u4EF6\u968F\u673A\u7C7B\u578B\u968F\u673A\u5C5E\u6027\u7684\u8BB0\u5FC6\u3002\u5728\u66F4\u6362\u6280\u80FD\u65F6\u6E05\u96F6\u8BA1\u6570\u5668\u3002"
skillSummary:
isEnabled: 0
skillIcon: {fileID: 0}
thisLevelNeedExps: 500
- userLevel: 5
skillName: "\u6211\u7231\u53D1\u660E"
skillDescription: "\u4F60\u7684\u8BB0\u5FC6\u878D\u5408\u548C\u52A0\u901F\u6240\u9700\u7684\u8D27\u5E01\u51CF\u534A\u3002"
skillSummary:
isEnabled: 0
skillIcon: {fileID: 0}
thisLevelNeedExps: 600
- userLevel: 6
skillName: "\u8FFD\u68A6\u4E4B\u8DEF"
skillDescription: "\u7ED3\u7B97\u65F6\uFF0C\u83B7\u5F97\u5076\u50CF\u5206\u65701\u2030\u7684\u8BB0\u5FC6\u788E\u7247\u3002"
skillSummary:
isEnabled: 0
skillIcon: {fileID: 0}
thisLevelNeedExps: 700
- userLevel: 7
skillName: "\u6D1E\u5BDF"
skillDescription: "\u4F60\u53EF\u4EE5\u770B\u5230\u89D2\u8272\u672A\u89E3\u9501\u7684\u6280\u80FD\u53CA\u5176\u4ECB\u7ECD\u3002"
skillSummary: "\u4F60\u7684\u76EE\u5149\u6781\u5177\u6218\u7565\u524D\u77BB\u6027\u3002"
isEnabled: 0
skillIcon: {fileID: 0}
thisLevelNeedExps: 800
- userLevel: 8
skillName: "95\u6298"
skillDescription: "\u6D88\u8D39\u8BB0\u5FC6\u788E\u7247\u548Ccoins\u65F6\u767E\u5206\u6BD4\u8FD4\u8FD8\u3002\u4F60\u6BCF\u62E5\u6709\u4E00\u4E2A\u5076\u50CF\uFF0C\u589E\u52A0\u6D88\u8D39\u8FD4\u8FD8\u7684\u6BD4\u4F8B0.5%\u3002\u6700\u591A\u5408\u8BA1\u8FD4\u8FD85%\u3002"
skillSummary:
isEnabled: 0
skillIcon: {fileID: 0}
thisLevelNeedExps: 900
- userLevel: 9
skillName: "\u5229\u6DA6\u63D0\u53D6\u5668"
skillDescription: "\u7ED3\u7B97\u65F6\uFF0C\u83B7\u5F97\u5076\u50CF\u5206\u65702\u2030\u7684\u91D1\u5E01\u3002"
skillSummary: "\u6B7B\u4E0E\u7A0E"
isEnabled: 0
skillIcon: {fileID: 0}
thisLevelNeedExps: 1100
- userLevel: 10
skillName: "\u9876\u5CF0\u76F8\u89C1"
skillDescription: "\u6E38\u620F\u4E2D\u4F60\u7684\u89C6\u89D2\u9AD8\u5EA6\u63D0\u9AD810%\u3002"
skillSummary: "\u611F\u6069\u6559\u7EC3\u3002"
isEnabled: 0
skillIcon: {fileID: 0}
thisLevelNeedExps: 1500
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: acf1a85d46975694aba2cdc12b9b3dfb
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,20 @@
using UnityEngine;
using System.Collections.Generic;
[CreateAssetMenu(fileName = "userLevel_skills", menuName = "Player/UserLevel Skills SO")]
public class userLevel_skills_SO : ScriptableObject
{
[System.Serializable]
public class UserLevelSkillEntry
{
public int userLevel;
public string skillName;
[TextArea(3, 10)] public string skillDescription;
public string skillSummary;
public bool isEnabled;
public Sprite skillIcon;
public int thisLevelNeedExps;
}
public List<UserLevelSkillEntry> skills = new List<UserLevelSkillEntry>();
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 19a25568f1e1a8b4093dce8a6753be0e
+9 -2
View File
@@ -15,6 +15,7 @@ using TMPro;
/// </summary>
public class AllyCombatant : MonoBehaviour, ICombatant
{
private static AllyHero_SO[] cachedAllAllyHeroes;
public int slotIndex = 0; // Documentation text normalized.
// runtime stats
@@ -989,8 +990,8 @@ public class AllyCombatant : MonoBehaviour, ICombatant
if (id > 0)
{
var all = Resources.LoadAll<AllyHero_SO>("");
foreach (var a in all)
EnsureAllyHeroCache();
foreach (var a in cachedAllAllyHeroes)
{
if (a != null && a.ally_heroID == id)
{
@@ -1049,6 +1050,12 @@ public class AllyCombatant : MonoBehaviour, ICombatant
}
}
private static void EnsureAllyHeroCache()
{
if (cachedAllAllyHeroes != null) return;
cachedAllAllyHeroes = Resources.LoadAll<AllyHero_SO>("") ?? Array.Empty<AllyHero_SO>();
}
// Documentation text normalized.
private static AllyHero_SO.AllyLevelInfo GetEffectiveLevelForExp(AllyHero_SO so, int exp)
{
+58
View File
@@ -414,6 +414,8 @@ public class EnemyCombatant : MonoBehaviour, ICombatant
}
}
AwardBountyScoreToLivingAllies();
// Finally mark dead
isDead = true;
@@ -510,6 +512,62 @@ public class EnemyCombatant : MonoBehaviour, ICombatant
public bool IsDead => isDead;
// New: allow EffectSystem/SkillBuilder to adjust enemy max HP safely
private void AwardBountyScoreToLivingAllies()
{
if (sourceData == null)
return;
float difficultyLevel = ResolveCurrentDifficultyLevel();
var stats = sourceData.GetStatsByDifficultyID(_currentDifficultyID);
int calculatedMaxHp = Mathf.Max(0, stats.enemy_maxHP);
float totalBounty = calculatedMaxHp * 0.05f * difficultyLevel + sourceData.enemyBountyBonus;
if (totalBounty <= 0f)
return;
AllyCombatant[] allies = UnityEngine.Object.FindObjectsByType<AllyCombatant>(FindObjectsInactive.Include, FindObjectsSortMode.None);
List<AllyCombatant> livingAllies = new List<AllyCombatant>();
for (int i = 0; i < allies.Length; i++)
{
AllyCombatant ally = allies[i];
if (ally == null)
continue;
if (ally.IsDead || ally.maxHP <= 0 || !ally.gameObject.activeInHierarchy)
continue;
livingAllies.Add(ally);
}
if (livingAllies.Count == 0)
return;
int awardPerAlly = Mathf.CeilToInt(totalBounty / livingAllies.Count);
if (awardPerAlly <= 0)
return;
for (int i = 0; i < livingAllies.Count; i++)
{
livingAllies[i].AddScoreDirect(awardPerAlly);
}
}
private float ResolveCurrentDifficultyLevel()
{
BeatmapManager beatmapManager = BeatmapManager.Instance;
if (beatmapManager == null || beatmapManager.assignedSongData == null || beatmapManager.assignedSongData.chartFiles == null)
return 1f;
List<ChartFileEntry> chartFiles = beatmapManager.assignedSongData.chartFiles;
for (int i = 0; i < chartFiles.Count; i++)
{
ChartFileEntry entry = chartFiles[i];
if (entry == null || entry.difficulty != _currentDifficultyID)
continue;
return Mathf.Max(0f, entry.difficultyLEVEL);
}
return 1f;
}
public void SetMaxHP(int newMax, bool keepCurrentRatio = true)
{
if (newMax < 1) newMax = 1;
+5 -1
View File
@@ -1,4 +1,4 @@
using UnityEngine;
using UnityEngine;
using System.Collections.Generic;
using Spine.Unity;
@@ -45,6 +45,9 @@ public class EnemyData_SO : ScriptableObject
[Header("Inspector")]
public EnemyType enemyType = EnemyType.Simple;
[Header("Reward")]
[Tooltip("Flat bounty score bonus added on top of the HP-based bounty formula.")]
public int enemyBountyBonus = 0;
public enum EnemyType
{
@@ -132,3 +135,4 @@ public class EnemyData_SO : ScriptableObject
[Range(0f, 1f)]
public float manaGainOnDamagePercent = 0.2f; // default 20%
}
@@ -69,6 +69,10 @@ public sealed class PlayerEconomyLedger : MonoBehaviour
PlayerEconomyPayload loadedPayload;
loadedFromSave = PlayerEconomyStorage.TryLoad(out loadedPayload);
payload = loadedPayload;
if (payload == null)
{
payload = PlayerEconomyStorage.CreateDefaultPayload();
}
initialized = true;
SaveNow();
}
@@ -165,6 +169,11 @@ public sealed class PlayerEconomyLedger : MonoBehaviour
payload.coins -= amount;
SaveNow();
DailyTaskEventHub.ReportSpendCoins(amount);
int refundAmount = PlayerSkillService.GetCoinRefundAmount(amount);
if (refundAmount > 0)
{
AddCoins(refundAmount);
}
return true;
}
@@ -183,6 +192,11 @@ public sealed class PlayerEconomyLedger : MonoBehaviour
payload.material -= amount;
SaveNow();
int refundAmount = PlayerSkillService.GetMaterialRefundAmount(amount);
if (refundAmount > 0)
{
AddMaterial(refundAmount);
}
return true;
}
@@ -85,7 +85,7 @@ public static class PlayerEconomyStorage
{
version = 1,
lastUpdatedUtcTicks = DateTime.UtcNow.Ticks,
coins = 0,
coins = 999999,
material = 0
};
}
@@ -0,0 +1,652 @@
using System;
using System.Collections.Generic;
using Bansonic;
using UnityEngine;
using UnityEngine.SceneManagement;
[Serializable]
public class PlayerSkillSaveData
{
public int selectedSkillIndex = -1;
public int postMatchRewardCounter = 0;
public int skillSwitchCooldownRemainingMatches = 0;
}
public sealed class PlayerSkillService : MonoBehaviour
{
private const string SaveCategory = "player_skills";
private const string SaveKey = "runtime";
private const string SkillAssetEditorPath = "Assets/playerInfoDisplay/uls/ulsSO.asset";
private const int MemoryBuySkillIndex = 1;
private const int MemorySellSkillIndex = 2;
private const int PostMatchEquipmentSkillIndex = 4;
private const int SmeltDiscountSkillIndex = 5;
private const int ScoreToMaterialSkillIndex = 6;
private const int RevealLockedIdolSkillsSkillIndex = 7;
private const int SpendRefundSkillIndex = 8;
private const int ScoreToCoinsSkillIndex = 9;
private const int CameraAngleSkillIndex = 10;
private const int MemoryBuyStoreItemId = 799001;
private const int MemorySellStoreItemId = 799002;
private const int RandomMemoryStoreItemId = 78141;
private const float SpendRefundPerOwnedHero = 0.005f;
private const float MaxSpendRefundRate = 0.05f;
public static PlayerSkillService Instance { get; private set; }
private bool initialized;
private PlayerSkillSaveData saveData;
private userLevel_skills_SO registeredSkillAsset;
private storeItemSO cachedRandomMemoryRewardItem;
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
private static void Bootstrap()
{
EnsureInstance();
}
public static PlayerSkillService EnsureInstance()
{
if (Instance != null)
{
return Instance;
}
GameObject host = new GameObject("__runtime_player_skill_bridge");
host.hideFlags = HideFlags.HideInHierarchy | HideFlags.HideInInspector;
DontDestroyOnLoad(host);
Instance = host.AddComponent<PlayerSkillService>();
return Instance;
}
public static void RegisterSkillAsset(userLevel_skills_SO skillAsset)
{
EnsureInstance().RegisterAssetInternal(skillAsset);
}
public static bool IsSkillEnabled(int skillIndex)
{
return EnsureInstance().IsSkillEnabledInternal(skillIndex);
}
public static int GetSelectedSkillIndex()
{
return EnsureInstance().GetSelectedSkillIndexInternal();
}
public static int GetSkillSwitchCooldownRemainingMatches()
{
return EnsureInstance().GetSkillSwitchCooldownRemainingMatchesInternal();
}
public static void ConfirmSkillSelection(userLevel_skills_SO skillAsset, int selectedIndex)
{
EnsureInstance().ConfirmSkillSelectionInternal(skillAsset, selectedIndex);
}
public static int ModifySmeltCoinCost(int baseCost)
{
if (!IsSkillEnabled(SmeltDiscountSkillIndex))
{
return Mathf.Max(0, baseCost);
}
return Mathf.CeilToInt(Mathf.Max(0, baseCost) * 0.5f);
}
public static int GetCoinRefundAmount(int spentCoins)
{
return EnsureInstance().GetRefundAmount(spentCoins);
}
public static int GetMaterialRefundAmount(int spentMaterial)
{
return EnsureInstance().GetRefundAmount(spentMaterial);
}
public static void NotifySettlementCompleted(int idolScore)
{
EnsureInstance().HandleSettlementCompletedInternal(idolScore);
}
public static void AppendDynamicStoreItems(List<storeItemSO> target, Sprite coinSprite, Sprite materialSprite)
{
EnsureInstance().AppendDynamicStoreItemsInternal(target, coinSprite, materialSprite);
}
public static bool IsPlayerSkillStoreItem(storeItemSO item)
{
return item != null && (item.itemID == MemoryBuyStoreItemId || item.itemID == MemorySellStoreItemId);
}
public static bool TryPurchasePlayerSkillStoreItem(storeItemSO item, int amount, out string failureMessage, out gItemGet.ItemEntry rewardEntry)
{
return EnsureInstance().TryPurchasePlayerSkillStoreItemInternal(item, amount, out failureMessage, out rewardEntry);
}
public static void ClearPersistentState()
{
EnsureInstance().ClearPersistentStateInternal();
}
private void Awake()
{
if (Instance != null && Instance != this)
{
Destroy(gameObject);
return;
}
Instance = this;
DontDestroyOnLoad(gameObject);
InitializeIfNeeded();
}
private void OnEnable()
{
SceneManager.sceneLoaded += HandleSceneLoaded;
}
private void OnDisable()
{
SceneManager.sceneLoaded -= HandleSceneLoaded;
}
private void OnApplicationPause(bool pauseStatus)
{
if (pauseStatus)
{
SaveNow();
}
}
private void OnApplicationQuit()
{
SaveNow();
}
private void InitializeIfNeeded()
{
if (initialized)
{
return;
}
initialized = true;
if (!SecureSaveVault.TryLoadJson(SaveCategory, SaveKey, out saveData) || saveData == null)
{
saveData = new PlayerSkillSaveData();
}
ResolveSkillAssetIfNeeded();
SyncSelectionFromAsset();
ApplySceneBindings();
}
private void RegisterAssetInternal(userLevel_skills_SO skillAsset)
{
InitializeIfNeeded();
if (skillAsset == null)
{
return;
}
registeredSkillAsset = skillAsset;
SyncSelectionFromAsset();
ApplySceneBindings();
}
private bool IsSkillEnabledInternal(int skillIndex)
{
InitializeIfNeeded();
ResolveSkillAssetIfNeeded();
SyncSelectionFromAsset();
return saveData != null && saveData.selectedSkillIndex == skillIndex;
}
private int GetSelectedSkillIndexInternal()
{
InitializeIfNeeded();
ResolveSkillAssetIfNeeded();
SyncSelectionFromAsset();
return saveData != null ? saveData.selectedSkillIndex : -1;
}
private int GetSkillSwitchCooldownRemainingMatchesInternal()
{
InitializeIfNeeded();
return saveData != null ? Mathf.Max(0, saveData.skillSwitchCooldownRemainingMatches) : 0;
}
private int GetRefundAmount(int spendAmount)
{
if (spendAmount <= 0 || !IsSkillEnabledInternal(SpendRefundSkillIndex))
{
return 0;
}
float refundRate = Mathf.Min(GetOwnedHeroCount() * SpendRefundPerOwnedHero, MaxSpendRefundRate);
if (refundRate <= 0f)
{
return 0;
}
return Mathf.FloorToInt(spendAmount * refundRate);
}
private void HandleSettlementCompletedInternal(int idolScore)
{
InitializeIfNeeded();
ResolveSkillAssetIfNeeded();
SyncSelectionFromAsset();
if (saveData.skillSwitchCooldownRemainingMatches > 0)
{
saveData.skillSwitchCooldownRemainingMatches = Mathf.Max(0, saveData.skillSwitchCooldownRemainingMatches - 1);
}
List<gItemGet.ItemEntry> grantedEntries = new List<gItemGet.ItemEntry>();
if (IsSkillEnabledInternal(PostMatchEquipmentSkillIndex))
{
saveData.postMatchRewardCounter = Mathf.Max(0, saveData.postMatchRewardCounter) + 1;
if (saveData.postMatchRewardCounter >= 10)
{
saveData.postMatchRewardCounter = 0;
equipmentSO generated = GrantRandomMemoryFromConfiguredSource();
if (generated != null)
{
grantedEntries.Add(gItemGet.FromEquipment(generated, 1));
}
}
}
if (idolScore > 0 && IsSkillEnabledInternal(ScoreToMaterialSkillIndex))
{
int grantedMaterial = Mathf.FloorToInt(idolScore * 0.001f);
if (grantedMaterial > 0)
{
PlayerEconomyLedger.EnsureInstance().AddMaterial(grantedMaterial);
grantedEntries.Add(gItemGet.Create("\u8bb0\u5fc6\u788e\u7247", null, grantedMaterial, ItemRarity.Uncommon));
}
}
if (idolScore > 0 && IsSkillEnabledInternal(ScoreToCoinsSkillIndex))
{
int grantedCoins = Mathf.FloorToInt(idolScore * 0.002f);
if (grantedCoins > 0)
{
PlayerEconomyLedger.EnsureInstance().AddCoins(grantedCoins);
grantedEntries.Add(gItemGet.Create("\u91d1\u5e01", null, grantedCoins, new Color32(240, 196, 74, 255)));
}
}
SaveNow();
if (grantedEntries.Count > 0)
{
gItemGet.display(grantedEntries);
}
}
private void AppendDynamicStoreItemsInternal(List<storeItemSO> target, Sprite coinSprite, Sprite materialSprite)
{
InitializeIfNeeded();
ResolveSkillAssetIfNeeded();
SyncSelectionFromAsset();
if (target == null)
{
return;
}
if (IsSkillEnabledInternal(MemoryBuySkillIndex))
{
target.Add(CreateMemoryBuyStoreItem(materialSprite));
}
if (IsSkillEnabledInternal(MemorySellSkillIndex))
{
target.Add(CreateMemorySellStoreItem(coinSprite));
}
}
private bool TryPurchasePlayerSkillStoreItemInternal(storeItemSO item, int amount, out string failureMessage, out gItemGet.ItemEntry rewardEntry)
{
failureMessage = string.Empty;
rewardEntry = default;
if (item == null)
{
failureMessage = "\u5546\u54c1\u6570\u636e\u4e22\u5931";
return false;
}
int purchaseAmount = Mathf.Max(1, amount);
if (item.itemID == MemoryBuyStoreItemId)
{
int totalCost = purchaseAmount * 10;
if (!PlayerEconomyLedger.EnsureInstance().TrySpendCoins(totalCost))
{
failureMessage = "\u8d27\u5e01\u4e0d\u8db3";
return false;
}
PlayerEconomyLedger.EnsureInstance().AddMaterial(purchaseAmount);
rewardEntry = gItemGet.Create("\u8bb0\u5fc6\u788e\u7247", item.itemIcon, purchaseAmount, ItemRarity.Uncommon);
return true;
}
if (item.itemID == MemorySellStoreItemId)
{
if (!PlayerEconomyLedger.EnsureInstance().TrySpendMaterial(purchaseAmount))
{
failureMessage = "\u8bb0\u5fc6\u788e\u7247\u4e0d\u8db3";
return false;
}
int grantedCoins = purchaseAmount * 4;
PlayerEconomyLedger.EnsureInstance().AddCoins(grantedCoins);
rewardEntry = gItemGet.Create("\u91d1\u5e01", item.itemIcon, grantedCoins, new Color32(240, 196, 74, 255));
return true;
}
failureMessage = "\u5f53\u524d\u672a\u914d\u7f6e\u53d1\u653e\u903b\u8f91";
return false;
}
private void ConfirmSkillSelectionInternal(userLevel_skills_SO skillAsset, int selectedIndex)
{
InitializeIfNeeded();
if (skillAsset == null || skillAsset.skills == null || selectedIndex < 0 || selectedIndex >= skillAsset.skills.Count)
{
return;
}
registeredSkillAsset = skillAsset;
for (int i = 0; i < skillAsset.skills.Count; i++)
{
userLevel_skills_SO.UserLevelSkillEntry entry = skillAsset.skills[i];
if (entry == null)
{
continue;
}
entry.isEnabled = (i == selectedIndex);
}
if (saveData.selectedSkillIndex != selectedIndex)
{
saveData.postMatchRewardCounter = 0;
saveData.skillSwitchCooldownRemainingMatches = 3;
}
saveData.selectedSkillIndex = selectedIndex;
#if UNITY_EDITOR
if (!Application.isPlaying)
{
UnityEditor.EditorUtility.SetDirty(skillAsset);
}
#endif
SaveNow();
ApplySceneBindings();
}
private void ClearPersistentStateInternal()
{
saveData = new PlayerSkillSaveData();
SecureSaveVault.Delete(SaveCategory, SaveKey);
ApplySceneBindings();
}
private void HandleSceneLoaded(Scene scene, LoadSceneMode mode)
{
ApplySceneBindings();
}
private void ApplySceneBindings()
{
bool revealLockedSkills = IsSkillEnabledInternal(RevealLockedIdolSkillsSkillIndex);
idolSkillsHub[] hubs = Resources.FindObjectsOfTypeAll<idolSkillsHub>();
for (int i = 0; i < hubs.Length; i++)
{
idolSkillsHub hub = hubs[i];
if (hub == null || !IsSceneInstance(hub))
{
continue;
}
if (hub.display_ungotten != revealLockedSkills)
{
hub.display_ungotten = revealLockedSkills;
if (hub.gameObject.activeInHierarchy)
{
hub.Rebuild();
}
}
}
storeSystem[] stores = Resources.FindObjectsOfTypeAll<storeSystem>();
for (int i = 0; i < stores.Length; i++)
{
if (stores[i] != null && IsSceneInstance(stores[i]))
{
stores[i].RefreshPlayerSkillItems();
}
}
equipSmelt[] smelters = Resources.FindObjectsOfTypeAll<equipSmelt>();
for (int i = 0; i < smelters.Length; i++)
{
if (smelters[i] != null && IsSceneInstance(smelters[i]))
{
smelters[i].RefreshPlayerSkillAdjustedUi();
}
}
effectEventController.RefreshPlayerSkillCameraOffset();
}
private void ResolveSkillAssetIfNeeded()
{
if (registeredSkillAsset != null)
{
return;
}
uLevel_skills[] skillPanels = Resources.FindObjectsOfTypeAll<uLevel_skills>();
for (int i = 0; i < skillPanels.Length; i++)
{
if (skillPanels[i] != null && skillPanels[i].ulsSO != null)
{
registeredSkillAsset = skillPanels[i].ulsSO;
return;
}
}
userLevel_skills_SO[] loadedAssets = Resources.FindObjectsOfTypeAll<userLevel_skills_SO>();
for (int i = 0; i < loadedAssets.Length; i++)
{
if (loadedAssets[i] != null)
{
registeredSkillAsset = loadedAssets[i];
return;
}
}
#if UNITY_EDITOR
registeredSkillAsset = UnityEditor.AssetDatabase.LoadAssetAtPath<userLevel_skills_SO>(SkillAssetEditorPath);
#endif
}
private void SyncSelectionFromAsset()
{
if (saveData == null || registeredSkillAsset == null || registeredSkillAsset.skills == null || registeredSkillAsset.skills.Count == 0)
{
return;
}
int enabledIndex = -1;
for (int i = 0; i < registeredSkillAsset.skills.Count; i++)
{
userLevel_skills_SO.UserLevelSkillEntry entry = registeredSkillAsset.skills[i];
if (entry != null && entry.isEnabled)
{
enabledIndex = i;
break;
}
}
if (enabledIndex == saveData.selectedSkillIndex)
{
return;
}
if (saveData.selectedSkillIndex >= 0)
{
saveData.postMatchRewardCounter = 0;
}
saveData.selectedSkillIndex = enabledIndex;
SaveNow();
}
private storeItemSO CreateMemoryBuyStoreItem(Sprite materialSprite)
{
storeItemSO item = ScriptableObject.CreateInstance<storeItemSO>();
item.hideFlags = HideFlags.DontSave;
item.itemID = MemoryBuyStoreItemId;
item.itemName = "1\u8bb0\u5fc6\u788e\u7247";
item.itemIcon = materialSprite;
item.itemRarity = ItemRarity.Uncommon;
item.itemSinglePurchaseQty = 1;
item.itemPurchaseQuota = -1;
item.itemDescription = "\u82b1\u8d3910\u91d1\u5e01\u8d2d\u4e701\u4e2a\u8bb0\u5fc6\u788e\u7247\u3002";
item.itemDetailedDescription = "\u73a9\u5bb6\u6280\u80fd\u201c\u8bb0\u5fc6\u8d2d\u4e70\u8ba1\u5212\u201d\u751f\u6548\u4e2d\u3002\u82b1\u8d3910\u91d1\u5e01\u8d2d\u4e701\u4e2a\u8bb0\u5fc6\u788e\u7247\u3002";
item.isOnShelf = true;
item.canbepurchased = true;
item.itemType = storeItemSO.ItemType.consumable;
item.costRequirements = new List<storeItemSO.CostRequirement>
{
new storeItemSO.CostRequirement
{
currencyType = storeItemSO.CurrencyType.coins,
amount = 10
}
};
item.unlockRequirements = new List<storeItemSO.UnlockRequirement>();
return item;
}
private storeItemSO CreateMemorySellStoreItem(Sprite coinSprite)
{
storeItemSO item = ScriptableObject.CreateInstance<storeItemSO>();
item.hideFlags = HideFlags.DontSave;
item.itemID = MemorySellStoreItemId;
item.itemName = "4\u91d1\u5e01";
item.itemIcon = coinSprite;
item.itemRarity = ItemRarity.Common;
item.itemSinglePurchaseQty = 1;
item.itemPurchaseQuota = -1;
item.itemDescription = "\u6d88\u80171\u4e2a\u8bb0\u5fc6\u788e\u7247\uff0c\u6362\u53d64\u91d1\u5e01\u3002";
item.itemDetailedDescription = "\u73a9\u5bb6\u6280\u80fd\u201c\u8bb0\u5fc6\u5f52\u8fd8\u8ba1\u5212\u201d\u751f\u6548\u4e2d\u3002\u6d88\u80171\u4e2a\u8bb0\u5fc6\u788e\u7247\uff0c\u6362\u53d64\u91d1\u5e01\u3002";
item.isOnShelf = true;
item.canbepurchased = true;
item.itemType = storeItemSO.ItemType.consumable;
item.costRequirements = new List<storeItemSO.CostRequirement>
{
new storeItemSO.CostRequirement
{
currencyType = storeItemSO.CurrencyType.material,
amount = 1
}
};
item.unlockRequirements = new List<storeItemSO.UnlockRequirement>();
return item;
}
private equipmentSO GrantRandomMemoryFromConfiguredSource()
{
storeItemSO randomMemoryItem = ResolveRandomMemoryRewardItem();
if (randomMemoryItem == null || randomMemoryItem.associatedSelectableEquipmentRewardSource == null)
{
return null;
}
smeltStageRewardSO rewardSource = randomMemoryItem.associatedSelectableEquipmentRewardSource;
int rewardIndex = Mathf.Max(0, randomMemoryItem.associatedSelectableEquipmentRewardIndex);
if (rewardSource.rewardRequirements == null || rewardIndex >= rewardSource.rewardRequirements.Length)
{
return null;
}
return equipmentGenerator.GenerateFromSmeltReward(rewardSource, rewardSource.rewardRequirements[rewardIndex]);
}
private storeItemSO ResolveRandomMemoryRewardItem()
{
if (cachedRandomMemoryRewardItem != null)
{
return cachedRandomMemoryRewardItem;
}
storeItemSO[] items = Resources.LoadAll<storeItemSO>("so/storeSO");
for (int i = 0; i < items.Length; i++)
{
if (items[i] != null && items[i].itemID == RandomMemoryStoreItemId)
{
cachedRandomMemoryRewardItem = items[i];
break;
}
}
return cachedRandomMemoryRewardItem;
}
private int GetOwnedHeroCount()
{
HashSet<int> heroIds = new HashSet<int>();
AllyHero_SO[] heroes = Resources.LoadAll<AllyHero_SO>(string.Empty);
if (heroes == null)
{
return 0;
}
for (int i = 0; i < heroes.Length; i++)
{
AllyHero_SO hero = heroes[i];
if (hero != null && hero.isUnlocked)
{
heroIds.Add(hero.ally_heroID);
}
}
return heroIds.Count;
}
private bool IsSceneInstance(Component component)
{
if (component == null || component.gameObject == null)
{
return false;
}
Scene scene = component.gameObject.scene;
return scene.IsValid() && scene.isLoaded;
}
private void SaveNow()
{
if (!initialized)
{
return;
}
SecureSaveVault.SaveJson(SaveCategory, SaveKey, saveData);
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 3fc9125cbd0b7134ea8ac541779cb715
+132 -3
View File
@@ -38,6 +38,7 @@ public class dailyTaskManager : MonoBehaviour
private readonly List<GameObject> spawnedTaskItems = new List<GameObject>();
private readonly Dictionary<int, Sprite> rewardSpriteByItemId = new Dictionary<int, Sprite>();
private readonly Dictionary<int, storeItemSO> rewardStoreItemByItemId = new Dictionary<int, storeItemSO>();
private void Start()
{
@@ -157,6 +158,7 @@ public class dailyTaskManager : MonoBehaviour
private void OnSingleRewardClicked(string taskID)
{
var rewardEntry = BuildRewardEntryForTask(taskID);
string failureMessage;
if (!DailyTaskService.EnsureInstance().TryClaimReward(taskID, playerData, out failureMessage))
{
@@ -168,15 +170,57 @@ public class dailyTaskManager : MonoBehaviour
return;
}
if (rewardEntry.HasValue)
{
gItemGet.display(rewardEntry.Value);
}
RefreshTaskUi();
}
private void OnOneKeyRewardClicked()
{
string failureMessage;
int claimedCount = DailyTaskService.EnsureInstance().ClaimAllAvailableRewards(playerData, out failureMessage);
var taskService = DailyTaskService.EnsureInstance();
var tasks = taskService.GetActiveTaskViews();
var grantedEntries = new List<gItemGet.ItemEntry>();
string failureMessage = string.Empty;
int claimedCount = 0;
for (int i = 0; i < tasks.Count; i++)
{
var taskView = tasks[i];
if (taskView == null || taskView.runtimeEntry == null || taskView.definition == null)
{
continue;
}
if (!taskView.runtimeEntry.isCompleted || taskView.runtimeEntry.isClaimed)
{
continue;
}
string claimError;
if (!taskService.TryClaimReward(taskView.runtimeEntry.taskID, playerData, out claimError))
{
if (claimedCount <= 0 && string.IsNullOrEmpty(failureMessage))
{
failureMessage = claimError;
}
continue;
}
claimedCount += 1;
grantedEntries.Add(BuildRewardEntry(taskView.definition));
}
if (claimedCount <= 0)
{
if (string.IsNullOrEmpty(failureMessage))
{
failureMessage = "暂无可领取奖励";
}
if (!string.IsNullOrEmpty(failureMessage))
{
gNotice.warning.display(failureMessage);
@@ -185,6 +229,11 @@ public class dailyTaskManager : MonoBehaviour
return;
}
if (grantedEntries.Count > 0)
{
gItemGet.display(grantedEntries);
}
RefreshTaskUi();
}
@@ -274,18 +323,24 @@ public class dailyTaskManager : MonoBehaviour
private void CacheRewardSpritesFromStoreItems()
{
rewardSpriteByItemId.Clear();
rewardStoreItemByItemId.Clear();
var rewardStoreItems = Resources.LoadAll<storeItemSO>("so/storeSO");
for (int i = 0; i < rewardStoreItems.Length; i++)
{
var itemSO = rewardStoreItems[i];
if (itemSO == null || itemSO.itemIcon == null)
if (itemSO == null)
{
continue;
}
if (itemSO.itemIcon != null)
{
rewardSpriteByItemId[itemSO.itemID] = itemSO.itemIcon;
}
rewardStoreItemByItemId[itemSO.itemID] = itemSO;
}
}
private Sprite GetRewardSpriteByItemId(int itemId)
@@ -299,6 +354,80 @@ public class dailyTaskManager : MonoBehaviour
return rewardSpriteByItemId.TryGetValue(itemId, out sprite) ? sprite : null;
}
private gItemGet.ItemEntry? BuildRewardEntryForTask(string taskID)
{
if (string.IsNullOrWhiteSpace(taskID))
{
return null;
}
var tasks = DailyTaskService.EnsureInstance().GetActiveTaskViews();
for (int i = 0; i < tasks.Count; i++)
{
var taskView = tasks[i];
if (taskView == null || taskView.runtimeEntry == null || taskView.definition == null)
{
continue;
}
if (string.Equals(taskView.runtimeEntry.taskID, taskID, System.StringComparison.Ordinal))
{
return BuildRewardEntry(taskView.definition);
}
}
return null;
}
private gItemGet.ItemEntry BuildRewardEntry(userTasksPool.TaskDefinition definition)
{
if (definition == null)
{
return gItemGet.Create("未知奖励", null, 1, ItemRarity.None);
}
switch (definition.rewardType)
{
case userTasksPool.RewardType.coins:
return gItemGet.Create("Coins", coinRewardSprite, Mathf.Max(1, definition.rewardAmount), ItemRarity.Common);
case userTasksPool.RewardType.expBottle:
{
int itemId = GetExpBottleRewardItemId(definition.rewardExpBottleKind);
storeItemSO itemSO;
if (rewardStoreItemByItemId.TryGetValue(itemId, out itemSO) && itemSO != null)
{
return gItemGet.FromStoreItem(itemSO, Mathf.Max(1, definition.rewardAmount));
}
return gItemGet.Create(
ExpBottleCatalog.GetDisplayName(definition.rewardExpBottleKind),
GetRewardSpriteByItemId(itemId),
Mathf.Max(1, definition.rewardAmount),
ItemRarity.None);
}
case userTasksPool.RewardType.dushMaterial:
{
int itemId = GetDushMaterialRewardItemId(definition.rewardDushMaterialKind);
storeItemSO itemSO;
if (rewardStoreItemByItemId.TryGetValue(itemId, out itemSO) && itemSO != null)
{
return gItemGet.FromStoreItem(itemSO, Mathf.Max(1, definition.rewardAmount));
}
return gItemGet.Create(
DushMaterialCatalog.GetDisplayName(definition.rewardDushMaterialKind),
GetRewardSpriteByItemId(itemId),
Mathf.Max(1, definition.rewardAmount),
ItemRarity.None);
}
default:
return gItemGet.Create("未知奖励", null, Mathf.Max(1, definition.rewardAmount), ItemRarity.None);
}
}
private static int GetExpBottleRewardItemId(ExpBottleKind kind)
{
switch (kind)
@@ -3,6 +3,11 @@ using System.Collections;
public class Animation_GenerateJudgementSituationPrefab : MonoBehaviour
{
private sealed class PooledJudgeTag : MonoBehaviour
{
public GameObject prefabSource;
}
public static Animation_GenerateJudgementSituationPrefab Instance;
[Header("Inspector")]
@@ -42,6 +47,9 @@ public class Animation_GenerateJudgementSituationPrefab : MonoBehaviour
// Track last scene to detect scene changes
private int lastSceneIndex = -1;
private Coroutine prewarmJudgeCoroutine;
private readonly System.Collections.Generic.Dictionary<GameObject, System.Collections.Generic.Stack<GameObject>> judgePools
= new System.Collections.Generic.Dictionary<GameObject, System.Collections.Generic.Stack<GameObject>>();
private void Awake()
{
@@ -147,7 +155,10 @@ public class Animation_GenerateJudgementSituationPrefab : MonoBehaviour
if (JudgeManager.IsDebugEnabled) Debug.Log($"[Animation_Generate] Spawning judge prefab: color={color}, result={judgeResult}, prefab={prefabToUse.name}");
GameObject instance = Instantiate(prefabToUse, spawnPoint);
GameObject instance = GetPooledJudge(prefabToUse, spawnPoint);
if (instance == null)
return;
instance.transform.localPosition = Vector3.zero;
// Documentation text normalized.
@@ -159,6 +170,52 @@ public class Animation_GenerateJudgementSituationPrefab : MonoBehaviour
StartCoroutine(AnimateSprite(instance));
}
public void PrewarmJudgePrefabs(int perPrefab = 1)
{
if (!Application.isPlaying)
return;
if (prewarmJudgeCoroutine != null)
{
StopCoroutine(prewarmJudgeCoroutine);
}
prewarmJudgeCoroutine = StartCoroutine(PrewarmJudgePrefabsRoutine(Mathf.Max(1, perPrefab)));
}
public IEnumerator PrewarmJudgePrefabsRoutine(int perPrefab = 1)
{
GameObject[] prefabs =
{
perfect_judge_prefab,
great_judge_prefab,
good_judge_prefab,
miss_judge_prefab
};
int count = Mathf.Max(1, perPrefab);
foreach (GameObject prefab in prefabs)
{
if (prefab == null)
continue;
for (int i = 0; i < count; i++)
{
GameObject instance = null;
try
{
instance = CreatePooledJudge(prefab);
ReturnJudgeToPool(instance);
}
catch { }
yield return null;
}
}
prewarmJudgeCoroutine = null;
}
private IEnumerator AnimateSprite(GameObject obj)
{
if (obj == null) yield break;
@@ -232,7 +289,76 @@ public class Animation_GenerateJudgementSituationPrefab : MonoBehaviour
// Documentation text normalized.
if (obj != null) Destroy(obj);
if (obj != null) ReturnJudgeToPool(obj);
}
private GameObject GetPooledJudge(GameObject prefab, Transform parent)
{
if (prefab == null || parent == null)
return null;
if (!judgePools.TryGetValue(prefab, out var pool))
{
pool = new System.Collections.Generic.Stack<GameObject>();
judgePools[prefab] = pool;
}
GameObject instance = null;
while (pool.Count > 0 && instance == null)
{
instance = pool.Pop();
}
if (instance == null)
{
instance = CreatePooledJudge(prefab);
}
if (instance == null)
return null;
instance.transform.SetParent(parent, false);
instance.SetActive(true);
return instance;
}
private GameObject CreatePooledJudge(GameObject prefab)
{
if (prefab == null)
return null;
GameObject instance = Instantiate(prefab, transform);
var tag = instance.GetComponent<PooledJudgeTag>();
if (tag == null)
tag = instance.AddComponent<PooledJudgeTag>();
tag.prefabSource = prefab;
instance.SetActive(false);
return instance;
}
private void ReturnJudgeToPool(GameObject instance)
{
if (instance == null)
return;
var tag = instance.GetComponent<PooledJudgeTag>();
if (tag == null || tag.prefabSource == null)
{
Destroy(instance);
return;
}
if (!judgePools.TryGetValue(tag.prefabSource, out var pool))
{
pool = new System.Collections.Generic.Stack<GameObject>();
judgePools[tag.prefabSource] = pool;
}
instance.transform.SetParent(transform, false);
instance.transform.localPosition = new Vector3(99999f, 99999f, 0f);
instance.transform.localRotation = Quaternion.identity;
instance.SetActive(false);
pool.Push(instance);
}
private Transform GetSpawnPoint(string color)
@@ -9,6 +9,7 @@ public class NoteData
public string color; // Documentation text normalized.
public string type; // Documentation text normalized.
public float length; // Documentation text normalized.
public string noteFunction;
// New fields for judgement recording
// judgeOffsetMs: signed offset in milliseconds recorded at judgement time
@@ -326,6 +326,9 @@ public class GameManager : MonoBehaviour
{
Debug.Log("GameManager Start() initialized");
// Move first-hit one-time setup cost into scene load instead of the first judged note.
StartCoroutine(PrewarmGameplayFirstHitPath());
// --- Initialize Statistics ---
currentSong = BeatmapManager.pendingSongData ?? SongDataHolder.SelectedSongData;
if (currentSong != null && !GameConfig.autoPlayEnabled)
@@ -489,6 +492,34 @@ public class GameManager : MonoBehaviour
}
}
private IEnumerator PrewarmGameplayFirstHitPath()
{
yield return null;
try
{
Note.PrewarmRuntimeCaches();
HoldNote.PrewarmRuntimeCaches();
var judgeFx = Animation_GenerateJudgementSituationPrefab.Instance
?? FindAnyObjectByType<Animation_GenerateJudgementSituationPrefab>();
judgeFx?.PrewarmJudgePrefabs(1);
var fxEvent = effectEventController.Instance ?? FindAnyObjectByType<effectEventController>();
if (fxEvent != null && fxEvent.isActiveAndEnabled)
{
// Cache target and pre-create SmoothShake via OnEnable/Awake path already present.
}
var globalFx = globalNoteEffect.Instance ?? FindAnyObjectByType<globalNoteEffect>();
globalFx?.PrewarmRuntime();
}
catch (System.Exception ex)
{
Debug.LogWarning($"[GameManager] Gameplay prewarm failed: {ex}");
}
}
private void Update()
{
// Detect Space or yellow note key to request start (only before gameplay starts)
+32 -1
View File
@@ -99,6 +99,18 @@ public class HoldNote : BaseNote
return beatmapManagerCache;
}
public static void PrewarmRuntimeCaches()
{
GetBeatmapManagerCached();
if (allyCache == null || allyCache.Length < 10)
allyCache = new AllyCombatant[10];
for (int i = 0; i < 5; i++)
{
GetAllyForTrackCached(i);
}
}
private static float JudgeToPmMultiplier(string judgeResult)
{
switch (judgeResult)
@@ -326,9 +338,10 @@ public class HoldNote : BaseNote
}
private float cachedTravelTime = 1.0f; // Cached travel time for distance optimization
private bool isSyncNote;
public void Setup(int id, int trackIndex, float speed, float time, float delay,
bool isEnd, float scheduledEnd, string color, KeyCode key, string type, float travelTimeSeconds, NoteJudgeConfig judgeConfig, NoteData noteData)
bool isEnd, float scheduledEnd, string color, KeyCode key, string type, float travelTimeSeconds, NoteJudgeConfig judgeConfig, NoteData noteData, bool isSync = false)
{
this.id = id;
// Ensure singletons are up to date if they were re-initialized (e.g. on scene reload)
@@ -347,6 +360,7 @@ public class HoldNote : BaseNote
this.key = key;
this.type = type;
this.judgeConfig = judgeConfig;
this.isSyncNote = isSync;
this.noteID = id.ToString();
this.keyToPress = key;
@@ -659,6 +673,13 @@ public class HoldNote : BaseNote
InputManager.Instance?.ShowJudgeResult(trackIndex, result);
teamUIController.Instance?.OnJudgeResult(result);
JudgeSoundManager.Instance?.PlayJudgeSound(result);
if (isSyncNote)
{
effectEventController.TryTriggerMultiNoteShake();
}
globalNoteEffect.TryTrigger(noteData != null ? noteData.noteFunction : null);
}
private void OnTriggerEnter2D(Collider2D collision)
@@ -975,6 +996,16 @@ public class HoldNote : BaseNote
{
ScheduleReturnToPool(0.2f);
}
if (segment == NoteSegment.Start && isSyncNote && result != "Miss")
{
effectEventController.TryTriggerMultiNoteShake();
}
if (segment == NoteSegment.Start && result != "Miss")
{
globalNoteEffect.TryTrigger(noteData != null ? noteData.noteFunction : null);
}
}
private IEnumerator DelayedReturn()
+29 -1
View File
@@ -11,6 +11,7 @@ public class Note : BaseNote
private bool hasLock = false; // track whether we hold the track lock
private NoteData noteData;
private bool isSyncNote;
[Header("Inspector")]
public NoteJudgeConfig judgeConfig; // Documentation text normalized.
@@ -42,6 +43,18 @@ public class Note : BaseNote
return beatmapManagerCache;
}
public static void PrewarmRuntimeCaches()
{
GetBeatmapManagerCached();
if (allyCache == null || allyCache.Length < 10)
allyCache = new AllyCombatant[10];
for (int i = 0; i < 5; i++)
{
GetAllyForTrackCached(i);
}
}
private static float JudgeToPmMultiplier(string judgeResult)
{
switch (judgeResult)
@@ -150,7 +163,7 @@ public class Note : BaseNote
controller = GetComponent<NoteController>();
}
public void Setup(KeyCode key, int trackIndex, float speed, float hitTime, string color, NoteJudgeConfig judgeConfig, NoteData data)
public void Setup(KeyCode key, int trackIndex, float speed, float hitTime, string color, NoteJudgeConfig judgeConfig, NoteData data, bool isSync = false)
{
keyToPress = key;
noteColor = color;
@@ -161,6 +174,7 @@ public class Note : BaseNote
hasLock = false;
this.judgeConfig = judgeConfig;
this.noteData = data;
this.isSyncNote = isSync;
// Set miss deadline: hitTime + missRange (the latest time to judge before auto-miss)
float missRange = (judgeConfig?.missRange ?? 0.5f);
@@ -279,6 +293,13 @@ public class Note : BaseNote
try { SkillBuilder.Instance?.NotifyNoteHit(TrackIndex, judgeResult, SkillDefinition.NoteTypeTrigger.Tap); } catch { }
LogTapJudge(judgeResult, 0f, false, true, pressTime);
if (isSyncNote)
{
effectEventController.TryTriggerMultiNoteShake();
}
globalNoteEffect.TryTrigger(noteData != null ? noteData.noteFunction : null);
Judge();
}
@@ -437,6 +458,13 @@ public class Note : BaseNote
try { SkillBuilder.Instance?.NotifyNoteHit(TrackIndex, judgeResult, SkillDefinition.NoteTypeTrigger.Tap); } catch { }
LogTapJudge(judgeResult, rawOffsetMs, rewrittenToPerfect, false, pressTime);
if (isSyncNote && judgeResult != "Miss")
{
effectEventController.TryTriggerMultiNoteShake();
}
globalNoteEffect.TryTrigger(noteData != null ? noteData.noteFunction : null);
}
Judge();
@@ -390,7 +390,7 @@ public class NoteSpawner : MonoBehaviour
if (noteScript != null)
{
// Setup note script with timing parameters
noteScript.Setup(key, noteData.trackIndex, noteSpeed, realtimeHit, noteData.color, judgeConfig, noteData);
noteScript.Setup(key, noteData.trackIndex, noteSpeed, realtimeHit, noteData.color, judgeConfig, noteData, isSync);
// Configure controller for absolute positioning (replaces relative Translate)
if (noteController != null)
@@ -476,7 +476,7 @@ public class NoteSpawner : MonoBehaviour
if (holdNote != null)
{
// pass realtime hit time (startTime + note.time) and delay 0, include globalHitDelay
holdNote.Setup(holdNoteId, noteData.trackIndex, noteSpeed, baseHit, 0f, false, scheduledEndTime, noteData.color, key, "start", travelTime, judgeConfig, noteData);
holdNote.Setup(holdNoteId, noteData.trackIndex, noteSpeed, baseHit, 0f, false, scheduledEndTime, noteData.color, key, "start", travelTime, judgeConfig, noteData, isSync);
// 使用流速倍率 sm 直接进行缩放,确保长条音符在 0.5-2.0 范围内依然能完美衔接
float visualScale = sm;
@@ -508,7 +508,7 @@ public class NoteSpawner : MonoBehaviour
if (holdSeg != null)
{
// Documentation text normalized.
holdSeg.Setup(holdNoteId, noteData.trackIndex, noteSpeed, baseHit, segmentDelay, false, scheduledEndTime, noteData.color, key, "middle", travelTime, judgeConfig, noteData);
holdSeg.Setup(holdNoteId, noteData.trackIndex, noteSpeed, baseHit, segmentDelay, false, scheduledEndTime, noteData.color, key, "middle", travelTime, judgeConfig, noteData, false);
// 应用与开始段一致的流速缩放
float visualScaleMid = sm;
@@ -540,7 +540,7 @@ public class NoteSpawner : MonoBehaviour
HoldNote holdEnd = endObj.GetComponent<HoldNote>();
if (holdEnd != null)
{
holdEnd.Setup(holdNoteId, noteData.trackIndex, noteSpeed, baseHit, endDelay, true, scheduledEndTime, noteData.color, key, "end", travelTime, judgeConfig, noteData);
holdEnd.Setup(holdNoteId, noteData.trackIndex, noteSpeed, baseHit, endDelay, true, scheduledEndTime, noteData.color, key, "end", travelTime, judgeConfig, noteData, false);
// 同样应用流速缩放
float visualScaleEnd = sm;
@@ -0,0 +1,314 @@
using SmoothShakeFree;
using UnityEngine;
public class effectEventController : MonoBehaviour
{
public enum CameraOffsetAxis
{
X,
Y,
Z
}
public static effectEventController Instance { get; private set; }
[Header("Multi Note Screen Shake")]
public bool enableMultiNoteScreenShake = true;
public float multiNoteScreenShakeAmplitude = 0.08f;
[Header("Camera Drift")]
public bool enableCameraDrift = false;
public Vector2 cameraDriftRange = new Vector2(0.15f, 0.08f);
public float cameraDriftSpeed = 0.3f;
[Header("Player Skill 10 Camera Offset")]
public float playerSkillCameraOffsetAmount = 0.6f;
public CameraOffsetAxis playerSkillCameraOffsetAxis = CameraOffsetAxis.Y;
private Transform cachedShakeTarget;
private Transform cachedCameraDriftPivot;
private Transform cachedCameraSkillPivot;
private Vector3 cameraDriftBaseLocalPosition;
private Vector3 cameraSkillBaseLocalPosition;
private float cameraDriftSeedX;
private float cameraDriftSeedY;
private void Awake()
{
if (Instance == null)
{
Instance = this;
cameraDriftSeedX = Random.Range(0f, 1000f);
cameraDriftSeedY = Random.Range(1000f, 2000f);
CacheShakeTarget();
return;
}
if (Instance != this)
{
Destroy(gameObject);
}
}
private void OnEnable()
{
CacheShakeTarget();
ResetCameraDriftIfNeeded();
}
private void Update()
{
UpdateCameraDrift();
UpdatePlayerSkillCameraOffset();
}
private void CacheShakeTarget()
{
if (Camera.main != null)
{
cachedShakeTarget = Camera.main.transform;
PrewarmShakeComponent();
EnsureCameraDriftPivot();
EnsureCameraSkillPivot();
}
}
private void PrewarmShakeComponent()
{
if (cachedShakeTarget == null)
return;
SmoothShake shake = cachedShakeTarget.GetComponent<SmoothShake>();
if (shake == null)
{
shake = cachedShakeTarget.gameObject.AddComponent<SmoothShake>();
}
if (shake.positionShake == null) shake.positionShake = new Shaker();
if (shake.rotationShake == null) shake.rotationShake = new Shaker();
if (shake.shakers == null || shake.shakers.Length != 2)
shake.shakers = new[] { shake.positionShake, shake.rotationShake };
if (shake.sum == null || shake.sum.Length != 2)
shake.sum = new Vector3[2];
}
private void EnsureCameraDriftPivot()
{
if (cachedShakeTarget == null)
return;
if (cachedCameraDriftPivot != null)
return;
Transform currentParent = cachedShakeTarget.parent;
if (currentParent != null && currentParent.name == "__effect_event_camera_drift_pivot")
{
cachedCameraDriftPivot = currentParent;
cameraDriftBaseLocalPosition = cachedCameraDriftPivot.localPosition;
return;
}
GameObject pivotObject = new GameObject("__effect_event_camera_drift_pivot");
Transform pivot = pivotObject.transform;
if (currentParent != null)
{
pivot.SetParent(currentParent, false);
pivot.localPosition = cachedShakeTarget.localPosition;
pivot.localRotation = cachedShakeTarget.localRotation;
pivot.localScale = Vector3.one;
}
else
{
pivot.position = cachedShakeTarget.position;
pivot.rotation = cachedShakeTarget.rotation;
}
cachedShakeTarget.SetParent(pivot, true);
cachedShakeTarget.localRotation = Quaternion.identity;
cachedCameraDriftPivot = pivot;
cameraDriftBaseLocalPosition = cachedCameraDriftPivot.localPosition;
}
private void EnsureCameraSkillPivot()
{
if (cachedShakeTarget == null)
return;
if (cachedCameraSkillPivot != null)
return;
Transform currentParent = cachedShakeTarget.parent;
if (currentParent != null && currentParent.name == "__effect_event_camera_skill_pivot")
{
cachedCameraSkillPivot = currentParent;
cameraSkillBaseLocalPosition = cachedCameraSkillPivot.localPosition;
return;
}
GameObject pivotObject = new GameObject("__effect_event_camera_skill_pivot");
Transform pivot = pivotObject.transform;
if (currentParent != null)
{
pivot.SetParent(currentParent, false);
pivot.localPosition = cachedShakeTarget.localPosition;
pivot.localRotation = cachedShakeTarget.localRotation;
pivot.localScale = Vector3.one;
}
else
{
pivot.position = cachedShakeTarget.position;
pivot.rotation = cachedShakeTarget.rotation;
pivot.localScale = Vector3.one;
}
cachedShakeTarget.SetParent(pivot, true);
cachedShakeTarget.localPosition = Vector3.zero;
cachedShakeTarget.localRotation = Quaternion.identity;
cachedCameraSkillPivot = pivot;
cameraSkillBaseLocalPosition = cachedCameraSkillPivot.localPosition;
}
private void UpdateCameraDrift()
{
if (cachedShakeTarget == null)
{
CacheShakeTarget();
}
if (cachedShakeTarget == null)
return;
EnsureCameraDriftPivot();
if (cachedCameraDriftPivot == null)
return;
if (!enableCameraDrift)
{
ResetCameraDriftIfNeeded();
return;
}
float speed = Mathf.Max(0f, cameraDriftSpeed);
float time = Time.time * speed;
float offsetX = (Mathf.PerlinNoise(cameraDriftSeedX, time) - 0.5f) * 2f * Mathf.Abs(cameraDriftRange.x);
float offsetY = (Mathf.PerlinNoise(cameraDriftSeedY, time) - 0.5f) * 2f * Mathf.Abs(cameraDriftRange.y);
cachedCameraDriftPivot.localPosition = cameraDriftBaseLocalPosition + new Vector3(offsetX, offsetY, 0f);
}
private void ResetCameraDriftIfNeeded()
{
if (cachedCameraDriftPivot == null)
return;
cachedCameraDriftPivot.localPosition = cameraDriftBaseLocalPosition;
}
private void UpdatePlayerSkillCameraOffset()
{
if (cachedShakeTarget == null)
{
CacheShakeTarget();
}
if (cachedShakeTarget == null)
return;
EnsureCameraSkillPivot();
if (cachedCameraSkillPivot == null)
return;
Vector3 targetLocalPosition = cameraSkillBaseLocalPosition;
if (PlayerSkillService.IsSkillEnabled(10))
{
float offset = playerSkillCameraOffsetAmount;
switch (playerSkillCameraOffsetAxis)
{
case CameraOffsetAxis.X:
targetLocalPosition.x += offset;
break;
case CameraOffsetAxis.Y:
targetLocalPosition.y += offset;
break;
case CameraOffsetAxis.Z:
targetLocalPosition.z += offset;
break;
}
}
if (cachedCameraSkillPivot.localPosition != targetLocalPosition)
{
cachedCameraSkillPivot.localPosition = targetLocalPosition;
}
}
public static void RefreshPlayerSkillCameraOffset()
{
effectEventController controller = Instance != null ? Instance : FindAnyObjectByType<effectEventController>();
if (controller == null)
return;
controller.CacheShakeTarget();
controller.UpdatePlayerSkillCameraOffset();
}
public static void TryTriggerMultiNoteShake()
{
effectEventController controller = Instance != null ? Instance : FindAnyObjectByType<effectEventController>();
if (controller == null)
return;
controller.TriggerMultiNoteShakeInternal();
}
private void TriggerMultiNoteShakeInternal()
{
if (!enableMultiNoteScreenShake)
return;
if (cachedShakeTarget == null)
{
CacheShakeTarget();
}
if (cachedShakeTarget == null)
return;
float amplitudeValue = Mathf.Max(0f, multiNoteScreenShakeAmplitude);
if (amplitudeValue <= 0f)
return;
SmoothShake shake = cachedShakeTarget.GetComponent<SmoothShake>();
if (shake == null)
{
shake = cachedShakeTarget.gameObject.AddComponent<SmoothShake>();
}
if (shake.positionShake == null) shake.positionShake = new Shaker();
if (shake.rotationShake == null) shake.rotationShake = new Shaker();
shake.positionShake.noiseType = Shaker.NoiseType.SineWave;
shake.positionShake.amplitude = new Vector3(amplitudeValue, amplitudeValue, 0f);
shake.positionShake.frequency = new Vector3(20f, 20f, 0f);
shake.rotationShake.amplitude = Vector3.zero;
shake.rotationShake.frequency = Vector3.zero;
shake.timeSettings.constantShake = false;
shake.timeSettings.fadeInDuration = 0.03f;
shake.timeSettings.holdDuration = 0.04f;
shake.timeSettings.fadeOutDuration = 0.05f;
if (shake.timeSettings.fadeInCurve == null || shake.timeSettings.fadeInCurve.length == 0)
shake.timeSettings.fadeInCurve = AnimationCurve.Linear(0f, 0f, 1f, 1f);
if (shake.timeSettings.fadeOutCurve == null || shake.timeSettings.fadeOutCurve.length == 0)
shake.timeSettings.fadeOutCurve = AnimationCurve.Linear(0f, 1f, 1f, 0f);
shake.shakers = new[] { shake.positionShake, shake.rotationShake };
shake.sum = new Vector3[2];
shake.StartShake();
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: f65edb710af433c479467d8c932e5d59
@@ -0,0 +1,361 @@
using SmoothShakeFree;
using System.Collections;
using UnityEngine;
using UnityEngine.UI;
public class globalNoteEffect : MonoBehaviour
{
public static globalNoteEffect Instance { get; private set; }
[Header("Camera Shake Event")]
public float cameraShakeAmplitude = 0.12f;
[Header("Flash Blink Event")]
public Image flashBlinkImage;
public float flashBlinkFadeDuration = 0.2f;
[Header("Camera Dash Event")]
public float targetCameraZPosition = -6.5f;
public AnimationCurve cameraDashCurve = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f);
public float cameraDashDuration = 0.12f;
[Header("Camera Wave FX")]
public float cameraWaveEnterDuration = 0.12f;
public float cameraWaveRecoverDuration = 0.12f;
[Header("Camera Glitch FX")]
public float cameraGlitchEnterDuration = 0.08f;
public float cameraGlitchRecoverDuration = 0.12f;
[Header("Camera Monochrome FX")]
public float cameraMonochromeEnterDuration = 0.1f;
public float cameraMonochromeRecoverDuration = 0.14f;
[Header("Screenshot Scale FX")]
public float screenshotScaleStartOpacity = 0.5f;
public float screenshotScaleFadeDuration = 0.22f;
public float screenshotScaleEndScale = 1.12f;
private Transform cachedCameraTransform;
private Coroutine flashBlinkCoroutine;
private Coroutine cameraDashCoroutine;
private float cameraBaseLocalZ;
private bool hasCameraBaseLocalZ;
private void Awake()
{
if (Instance == null)
{
Instance = this;
}
else if (Instance != this)
{
Destroy(gameObject);
return;
}
CacheCameraTransform();
PrewarmRuntime();
}
private void Start()
{
SetFlashImageAlpha(0f);
}
private void OnEnable()
{
CacheCameraTransform();
SetFlashImageAlpha(0f);
PrewarmRuntime();
}
private void LateUpdate()
{
if (cachedCameraTransform == null)
{
CacheCameraTransform();
}
if (cachedCameraTransform != null && cameraDashCoroutine == null)
{
cameraBaseLocalZ = cachedCameraTransform.localPosition.z;
hasCameraBaseLocalZ = true;
}
}
private void CacheCameraTransform()
{
if (Camera.main != null)
{
cachedCameraTransform = Camera.main.transform;
cameraBaseLocalZ = cachedCameraTransform.localPosition.z;
hasCameraBaseLocalZ = true;
}
}
public void PrewarmRuntime()
{
CacheCameraTransform();
if (cachedCameraTransform != null)
{
SmoothShake shake = cachedCameraTransform.GetComponent<SmoothShake>();
if (shake == null)
{
shake = cachedCameraTransform.gameObject.AddComponent<SmoothShake>();
}
if (shake.positionShake == null) shake.positionShake = new Shaker();
if (shake.rotationShake == null) shake.rotationShake = new Shaker();
if (shake.shakers == null || shake.shakers.Length != 2)
shake.shakers = new[] { shake.positionShake, shake.rotationShake };
if (shake.sum == null || shake.sum.Length != 2)
shake.sum = new Vector3[2];
}
GlobalDistortionRuntimeController.EnsureInstance();
GlobalGlitchRuntimeController.EnsureInstance();
GlobalMonochromeRuntimeController.EnsureInstance();
GlobalAfterimageRuntimeController.EnsureInstance();
}
public static void TryTrigger(string noteFunction)
{
if (string.IsNullOrWhiteSpace(noteFunction))
return;
globalNoteEffect controller = GetOrCreateInstance();
if (controller == null)
return;
controller.TriggerInternal(noteFunction.Trim());
}
private static globalNoteEffect GetOrCreateInstance()
{
if (Instance != null)
return Instance;
globalNoteEffect found = FindAnyObjectByType<globalNoteEffect>();
if (found != null)
{
Instance = found;
return found;
}
GameObject runtimeObject = new GameObject("__global_note_effect_runtime");
return runtimeObject.AddComponent<globalNoteEffect>();
}
private void TriggerInternal(string noteFunction)
{
switch (noteFunction)
{
case "CameraShakeEvent":
TriggerCameraShake();
break;
case "FlashBlinkEvent":
TriggerFlashBlink();
break;
case "CameraScaleEvent":
TriggerCameraDash();
break;
case "CameraWaveFX":
TriggerCameraWaveFx();
break;
case "CameraGlitchFX":
TriggerCameraGlitchFx();
break;
case "CameraMonochromeFX":
TriggerCameraMonochromeFx();
break;
case "ScreenshotScale":
TriggerScreenshotScaleFx();
break;
}
}
private void TriggerCameraShake()
{
CacheCameraTransform();
if (cachedCameraTransform == null)
return;
float amplitudeValue = Mathf.Max(0f, cameraShakeAmplitude);
if (amplitudeValue <= 0f)
return;
SmoothShake shake = cachedCameraTransform.GetComponent<SmoothShake>();
if (shake == null)
{
shake = cachedCameraTransform.gameObject.AddComponent<SmoothShake>();
}
if (shake.positionShake == null) shake.positionShake = new Shaker();
if (shake.rotationShake == null) shake.rotationShake = new Shaker();
shake.positionShake.noiseType = Shaker.NoiseType.SineWave;
shake.positionShake.amplitude = new Vector3(amplitudeValue, amplitudeValue, 0f);
shake.positionShake.frequency = new Vector3(18f, 18f, 0f);
shake.rotationShake.amplitude = Vector3.zero;
shake.rotationShake.frequency = Vector3.zero;
shake.timeSettings.constantShake = false;
shake.timeSettings.fadeInDuration = 0.02f;
shake.timeSettings.holdDuration = 0.04f;
shake.timeSettings.fadeOutDuration = 0.05f;
if (shake.timeSettings.fadeInCurve == null || shake.timeSettings.fadeInCurve.length == 0)
shake.timeSettings.fadeInCurve = AnimationCurve.Linear(0f, 0f, 1f, 1f);
if (shake.timeSettings.fadeOutCurve == null || shake.timeSettings.fadeOutCurve.length == 0)
shake.timeSettings.fadeOutCurve = AnimationCurve.Linear(0f, 1f, 1f, 0f);
shake.shakers = new[] { shake.positionShake, shake.rotationShake };
shake.sum = new Vector3[2];
shake.StartShake();
}
private void TriggerFlashBlink()
{
if (flashBlinkImage == null)
return;
if (flashBlinkCoroutine != null)
{
StopCoroutine(flashBlinkCoroutine);
}
flashBlinkCoroutine = StartCoroutine(FlashBlinkCoroutine());
}
private IEnumerator FlashBlinkCoroutine()
{
SetFlashImageAlpha(1f);
float duration = Mathf.Max(0.01f, flashBlinkFadeDuration);
float elapsed = 0f;
while (elapsed < duration)
{
elapsed += Time.deltaTime;
float t = Mathf.Clamp01(elapsed / duration);
SetFlashImageAlpha(1f - t);
yield return null;
}
SetFlashImageAlpha(0f);
flashBlinkCoroutine = null;
}
private void TriggerCameraDash()
{
CacheCameraTransform();
if (cachedCameraTransform == null)
return;
if (cameraDashCoroutine != null)
{
StopCoroutine(cameraDashCoroutine);
if (hasCameraBaseLocalZ)
{
Vector3 resetPosition = cachedCameraTransform.localPosition;
resetPosition.z = cameraBaseLocalZ;
cachedCameraTransform.localPosition = resetPosition;
}
}
cameraDashCoroutine = StartCoroutine(CameraDashCoroutine());
}
private IEnumerator CameraDashCoroutine()
{
if (!hasCameraBaseLocalZ)
{
cameraBaseLocalZ = cachedCameraTransform.localPosition.z;
hasCameraBaseLocalZ = true;
}
float baseLocalZ = cameraBaseLocalZ;
float targetZ = targetCameraZPosition;
if (Mathf.Approximately(targetZ, baseLocalZ))
{
targetZ = baseLocalZ + 1.5f;
}
float duration = Mathf.Max(0.01f, cameraDashDuration);
AnimationCurve curve = cameraDashCurve == null || cameraDashCurve.length == 0
? AnimationCurve.EaseInOut(0f, 0f, 1f, 1f)
: cameraDashCurve;
float elapsed = 0f;
while (elapsed < duration)
{
elapsed += Time.deltaTime;
float t = Mathf.Clamp01(elapsed / duration);
float curvedT = curve.Evaluate(t);
Vector3 position = cachedCameraTransform.localPosition;
position.z = Mathf.LerpUnclamped(baseLocalZ, targetZ, curvedT);
cachedCameraTransform.localPosition = position;
yield return null;
}
elapsed = 0f;
while (elapsed < duration)
{
elapsed += Time.deltaTime;
float t = Mathf.Clamp01(elapsed / duration);
float curvedT = curve.Evaluate(t);
Vector3 position = cachedCameraTransform.localPosition;
position.z = Mathf.LerpUnclamped(targetZ, baseLocalZ, curvedT);
cachedCameraTransform.localPosition = position;
yield return null;
}
Vector3 finalPosition = cachedCameraTransform.localPosition;
finalPosition.z = baseLocalZ;
cachedCameraTransform.localPosition = finalPosition;
cameraDashCoroutine = null;
}
private void TriggerCameraWaveFx()
{
GlobalDistortionRuntimeController.TriggerWaveEffect(
Mathf.Max(0.0001f, cameraWaveEnterDuration),
Mathf.Max(0.0001f, cameraWaveRecoverDuration)
);
}
private void TriggerCameraGlitchFx()
{
GlobalGlitchRuntimeController.TriggerWaveEffect(
Mathf.Max(0.0001f, cameraGlitchEnterDuration),
Mathf.Max(0.0001f, cameraGlitchRecoverDuration)
);
}
private void TriggerCameraMonochromeFx()
{
GlobalMonochromeRuntimeController.Trigger(
Mathf.Max(0.0001f, cameraMonochromeEnterDuration),
Mathf.Max(0.0001f, cameraMonochromeRecoverDuration)
);
}
private void TriggerScreenshotScaleFx()
{
GlobalAfterimageRuntimeController.Trigger(
Mathf.Clamp01(screenshotScaleStartOpacity),
Mathf.Max(0.0001f, screenshotScaleFadeDuration),
Mathf.Max(1f, screenshotScaleEndScale)
);
}
private void SetFlashImageAlpha(float alpha)
{
if (flashBlinkImage == null)
return;
Color color = flashBlinkImage.color;
color.a = Mathf.Clamp01(alpha);
flashBlinkImage.color = color;
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 7aad6dbb8ac9a574b832837614506af8
@@ -28,11 +28,19 @@ public class iNumberPrefabController : MonoBehaviour
private bool _warnedMissingPrefab;
private bool _warnedMissingParents;
private Transform pooledRoot;
private readonly System.Collections.Generic.Dictionary<GameObject, System.Collections.Generic.Stack<playerInstantNumbersPrefab>> pools
= new System.Collections.Generic.Dictionary<GameObject, System.Collections.Generic.Stack<playerInstantNumbersPrefab>>();
private readonly System.Collections.Generic.Dictionary<playerInstantNumbersPrefab, GameObject> sourcePrefabs
= new System.Collections.Generic.Dictionary<playerInstantNumbersPrefab, GameObject>();
private void Awake()
{
if (Instance == null) Instance = this;
else if (Instance != this) { Destroy(gameObject); return; }
pooledRoot = new GameObject("__instant_number_pool").transform;
pooledRoot.SetParent(transform, false);
}
private void Start()
@@ -150,19 +158,76 @@ public class iNumberPrefabController : MonoBehaviour
return;
}
var go = Instantiate(prefab, parent, false);
if (go == null) return;
if (prefab.scene.IsValid())
{
if (prefab.activeSelf) prefab.SetActive(false);
var view = GetPooledInstance(prefab, parent);
if (view != null) view.Play(type, signedValue);
}
// Ensure the newly created object is active before playing animation
if (!go.activeInHierarchy) go.SetActive(true);
private playerInstantNumbersPrefab GetPooledInstance(GameObject prefab, Transform parent)
{
if (prefab == null || parent == null)
return null;
var view = go.GetComponent<playerInstantNumbersPrefab>();
if (view != null) view.Play(type, signedValue);
if (!pools.TryGetValue(prefab, out var pool))
{
pool = new System.Collections.Generic.Stack<playerInstantNumbersPrefab>();
pools[prefab] = pool;
}
playerInstantNumbersPrefab view = null;
while (pool.Count > 0 && view == null)
{
view = pool.Pop();
}
if (view == null)
{
var go = Instantiate(prefab, parent, false);
if (go == null)
return null;
view = go.GetComponent<playerInstantNumbersPrefab>();
if (view == null)
return null;
sourcePrefabs[view] = prefab;
}
else
{
view.transform.SetParent(parent, false);
view.gameObject.SetActive(true);
}
view.ResetForReuse();
return view;
}
public static bool ReturnInstance(playerInstantNumbersPrefab view)
{
if (Instance == null || view == null)
return false;
return Instance.ReturnInstanceInternal(view);
}
private bool ReturnInstanceInternal(playerInstantNumbersPrefab view)
{
if (view == null)
return false;
if (!sourcePrefabs.TryGetValue(view, out var prefab) || prefab == null)
return false;
if (!pools.TryGetValue(prefab, out var pool))
{
pool = new System.Collections.Generic.Stack<playerInstantNumbersPrefab>();
pools[prefab] = pool;
}
view.transform.SetParent(pooledRoot, false);
view.ResetForReuse();
view.gameObject.SetActive(false);
pool.Push(view);
return true;
}
private void WarnMissingPrefabOnce()
@@ -51,14 +51,33 @@ public class playerInstantNumbersPrefab : MonoBehaviour
_canvasGroup.alpha = 1f;
}
private void OnDisable()
{
if (_animationCoroutine != null)
{
StopCoroutine(_animationCoroutine);
_animationCoroutine = null;
}
}
public void Play(iNumberPrefabController.InstantNumberType type, int signedValue)
{
ResetForReuse();
ApplyVisual(type, signedValue);
if (_animationCoroutine != null) StopCoroutine(_animationCoroutine);
_animationCoroutine = StartCoroutine(Animate());
}
public void ResetForReuse()
{
if (_canvasGroup != null) _canvasGroup.alpha = 1f;
transform.localRotation = Quaternion.identity;
transform.localScale = Vector3.one;
if (_rectTransform != null) _rectTransform.anchoredPosition = Vector2.zero;
else transform.localPosition = Vector3.zero;
}
private void ApplyVisual(iNumberPrefabController.InstantNumberType type, int signedValue)
{
if (numberText != null)
@@ -178,6 +197,10 @@ public class playerInstantNumbersPrefab : MonoBehaviour
yield return null;
}
_animationCoroutine = null;
if (!iNumberPrefabController.ReturnInstance(this))
{
Destroy(gameObject);
}
}
}
@@ -524,6 +524,8 @@ public class settlementController : MonoBehaviour
targetTotalScore = targetPmScore + targetIdolScore;
targetTotalPercent = (float)targetTotalScore / Mathf.Max(1, _1000000) * 100f;
PlayerSkillService.NotifySettlementCompleted(targetIdolScore);
finalScore_Text.text = targetTotalScore.ToString();
pmScoreSum_Text.text = targetPmScore.ToString();
@@ -370,45 +370,7 @@ public class teamUIController : MonoBehaviour
#else
// Runtime: prefer runtimeResourcesFolderPath, fallback to selectedProjectFolderPath
string resourcesPath = ResolveResourcesRelativePath(!string.IsNullOrEmpty(runtimeResourcesFolderPath) ? runtimeResourcesFolderPath : selectedProjectFolderPath);
List<Object> runtimeDiscovered = new List<Object>();
if (!string.IsNullOrEmpty(resourcesPath))
{
resourcesPath = resourcesPath.Trim('/');
try
{
var arr = Resources.LoadAll(resourcesPath);
if (arr != null && arr.Length > 0)
runtimeDiscovered.AddRange(arr);
// If nothing loaded from the specific folder, fallback to loading all and filter by name later
if (runtimeDiscovered.Count == 0)
{
var arrAll = Resources.LoadAll("");
if (arrAll != null && arrAll.Length > 0) // Fixed: changed arr.Length to arrAll.Length
{
runtimeDiscovered.AddRange(arrAll);
Debug.LogWarning($"[teamUIController] (Runtime) Resources.LoadAll returned 0 in '{resourcesPath}', fell back to loading all ScriptableObjects ({arrAll.Length})");
}
}
Debug.Log($"[teamUIcontroller] (Runtime) Loaded {runtimeDiscovered.Count} objects from Resources/{resourcesPath}");
}
catch (System.Exception ex)
{
Debug.LogWarning($"[teamUIController] (Runtime) Resources.LoadAll failed for '{resourcesPath}': {ex.Message}");
var arrAll = Resources.LoadAll("");
if (arrAll != null && arrAll.Length > 0) // Fixed: changed arr.Length to arrAll.Length
runtimeDiscovered.AddRange(arrAll);
}
}
else
{
var arr = Resources.LoadAll("");
if (arr != null && arr.Length > 0)
runtimeDiscovered.AddRange(arr);
Debug.Log($"[teamUIController] (Runtime) Loaded {arr?.Length ?? 0} objects from Resources (project-wide)");
}
List<Object> runtimeDiscovered = GetOrBuildRuntimeAllyDiscovered(resourcesPath);
TeamCharacterList globalList = null;
if (teamSettingPanel.Instance != null)
@@ -549,9 +511,7 @@ public class teamUIController : MonoBehaviour
// attempt to set teammate image from underlying AllyHero_SO if possible
try
{
var ahList = Resources.LoadAll<AllyHero_SO>("");
AllyHero_SO matched = null;
foreach (var a in ahList) if (a != null && a.ally_heroID == id) { matched = a; break; }
AllyHero_SO matched = GetCachedRuntimeAllyHero(id);
if (matched != null)
{
var sprite = matched.ally_heroProfile != null ? matched.ally_heroProfile : matched.ally_heroImage;
@@ -570,6 +530,77 @@ public class teamUIController : MonoBehaviour
#endif
}
private List<Object> GetOrBuildRuntimeAllyDiscovered(string resourcesPath)
{
resourcesPath = (resourcesPath ?? string.Empty).Trim('/');
if (_runtimeAllyDiscovered != null && _runtimeAllyResourcesPath == resourcesPath)
return _runtimeAllyDiscovered;
var runtimeDiscovered = new List<Object>();
if (!string.IsNullOrEmpty(resourcesPath))
{
try
{
var arr = Resources.LoadAll(resourcesPath);
if (arr != null && arr.Length > 0)
runtimeDiscovered.AddRange(arr);
if (runtimeDiscovered.Count == 0)
{
var arrAll = Resources.LoadAll("");
if (arrAll != null && arrAll.Length > 0)
{
runtimeDiscovered.AddRange(arrAll);
Debug.LogWarning($"[teamUIController] (Runtime) Resources.LoadAll returned 0 in '{resourcesPath}', fell back to loading all ScriptableObjects ({arrAll.Length})");
}
}
Debug.Log($"[teamUIcontroller] (Runtime) Loaded {runtimeDiscovered.Count} objects from Resources/{resourcesPath}");
}
catch (System.Exception ex)
{
Debug.LogWarning($"[teamUIController] (Runtime) Resources.LoadAll failed for '{resourcesPath}': {ex.Message}");
var arrAll = Resources.LoadAll("");
if (arrAll != null && arrAll.Length > 0)
runtimeDiscovered.AddRange(arrAll);
}
}
else
{
var arr = Resources.LoadAll("");
if (arr != null && arr.Length > 0)
runtimeDiscovered.AddRange(arr);
Debug.Log($"[teamUIController] (Runtime) Loaded {arr?.Length ?? 0} objects from Resources (project-wide)");
}
_runtimeAllyResourcesPath = resourcesPath;
_runtimeAllyDiscovered = runtimeDiscovered;
_cachedRuntimeAllyHeroes = null;
_runtimeAllyHeroById = null;
return runtimeDiscovered;
}
private AllyHero_SO GetCachedRuntimeAllyHero(int id)
{
if (id <= 0) return null;
if (_runtimeAllyHeroById != null && _runtimeAllyHeroById.TryGetValue(id, out var cached))
return cached;
if (_cachedRuntimeAllyHeroes == null)
{
_cachedRuntimeAllyHeroes = Resources.LoadAll<AllyHero_SO>("") ?? System.Array.Empty<AllyHero_SO>();
_runtimeAllyHeroById = new Dictionary<int, AllyHero_SO>();
foreach (var hero in _cachedRuntimeAllyHeroes)
{
if (hero == null) continue;
_runtimeAllyHeroById[hero.ally_heroID] = hero;
}
}
return _runtimeAllyHeroById.TryGetValue(id, out var heroFound) ? heroFound : null;
}
// ResolveResourcesRelativePath helper method is missing, assuming it exists externally or is part of a base class / extension.
// Since the user is providing the full class, I will assume it's either defined outside this snippet or is implicitly handled,
// but the code within #if UNITY_EDITOR is what matters for the file content.
@@ -815,6 +846,10 @@ public class teamUIController : MonoBehaviour
private const string EnemyDieAnimationName = "die";
private string _runtimeEnemyResourcesPath;
private List<Object> _runtimeEnemyDiscovered;
private string _runtimeAllyResourcesPath;
private List<Object> _runtimeAllyDiscovered;
private AllyHero_SO[] _cachedRuntimeAllyHeroes;
private Dictionary<int, AllyHero_SO> _runtimeAllyHeroById;
// For total enemy health bar
private int totalMaxHP = 0; // Documentation text normalized.
@@ -1031,6 +1066,8 @@ public class teamUIController : MonoBehaviour
public bool isEnemy_active = true;
[Tooltip("Documentation text normalized.")]
public Image currentEnemy_characterImage;
[Tooltip("Shown on currentEnemy_characterImage after the last enemy is defeated. If empty, falls back to the last enemy SO sprite.")]
public Sprite allEnemiesDefeatedSprite;
[Tooltip("Documentation text normalized.")]
public Image currentEnemy_healthImage;
[Tooltip("Documentation text normalized.")]
@@ -1055,6 +1092,10 @@ public class teamUIController : MonoBehaviour
public TextMeshProUGUI currentEnemy_manaRate;
[Tooltip("Documentation text normalized.")]
public TextMeshProUGUI currentEnemy_current_scoreText; // rate : now score / max score
[Tooltip("Hidden after all enemies are defeated.")]
public GameObject currentEnemy_bountyObject;
[Tooltip("Displays the current enemy bounty score.")]
public Text currentEnemy_bountyText;
[Tooltip("Documentation text normalized.")]
[SerializeField] private int enemy_id;
[Tooltip("Documentation text normalized.")]
@@ -1067,6 +1108,9 @@ public class teamUIController : MonoBehaviour
[SerializeField] private Image spine_to_put_referenceImage;
[SerializeField] private Color spineHurtFlashColor = new Color(1f, 0.2f, 0.2f, 1f);
[SerializeField] private float spineUniformHeight = 0f;
private Coroutine enemyBountyTextCoroutine;
private bool enemyBountyTransitionActive = false;
private int currentDisplayedEnemyBounty = 0;
public float SpineUniformHeight
{
get => spineUniformHeight;
@@ -1598,8 +1642,10 @@ public class teamUIController : MonoBehaviour
}
if (currentEnemy_characterImage != null)
{
// Set the sprite from SO
var sprite = so.enemy_Image != null ? so.enemy_Image : (so.enemy_Profile != null ? so.enemy_Profile : null);
// Use the configured victory sprite first, otherwise fall back to the defeated enemy sprite.
var sprite = allEnemiesDefeatedSprite != null
? allEnemiesDefeatedSprite
: (so.enemy_Image != null ? so.enemy_Image : (so.enemy_Profile != null ? so.enemy_Profile : null));
currentEnemy_characterImage.sprite = sprite;
// Apply grayscale material
@@ -1716,6 +1762,7 @@ public class teamUIController : MonoBehaviour
if (currentEnemy_manaImage != null) currentEnemy_manaImage.fillAmount = 0f;
if (currentEnemy_fademanaImage != null) currentEnemy_fademanaImage.fillAmount = 0f;
if (currentEnemy_typeText != null) currentEnemy_typeText.text = "(普通敌人)";
HideEnemyBountyUiImmediate();
UpdateEnemyListText();
// Documentation text normalized.
UpdateAllEnemyTotalHealthUIImmediate();
@@ -1756,6 +1803,8 @@ public class teamUIController : MonoBehaviour
if (currentEnemy_manaImage != null) currentEnemy_manaImage.fillAmount = 0f;
if (currentEnemy_fademanaImage != null) currentEnemy_fademanaImage.fillAmount = 0f;
if (currentEnemy_typeText != null) currentEnemy_typeText.text = "(普通敌人)";
if (!enemyBountyTransitionActive)
HideEnemyBountyUiImmediate();
UpdateEnemyListText();
// Update total health bar to 0
UpdateAllEnemyTotalHealthUIImmediate();
@@ -1834,6 +1883,23 @@ public class teamUIController : MonoBehaviour
// ensure UI parent is visible
if (objectFather_enemy != null) objectFather_enemy.SetActive(true);
int currentEnemyBounty = CalculateEnemyBountyScore(so);
if (currentEnemy_bountyObject != null)
currentEnemy_bountyObject.SetActive(true);
if (enemyCurrentCount == 0 && currentDisplayedEnemyBounty == 0 && !enemyBountyTransitionActive)
{
if (enemyBountyTextCoroutine != null)
{
StopCoroutine(enemyBountyTextCoroutine);
enemyBountyTextCoroutine = null;
}
SetEnemyBountyDisplayImmediate(currentEnemyBounty);
}
else
{
AnimateEnemyBountyRise(currentEnemyBounty);
}
// reset previous values so Update picks up initial state
prevEnemyHP = enemyCombatantInstance.currentHP;
prevEnemyMana = enemyCombatantInstance.currentMana;
@@ -1992,6 +2058,16 @@ public class teamUIController : MonoBehaviour
}
if (delay > 0f)
{
int nextIndex = enemyCurrentCount + 1;
if (nextIndex >= recognizedEnemySOs.Length)
{
AnimateEnemyBountyToZero(true);
}
else
{
AnimateEnemyBountyToZero(false);
}
if (_enemySpineDeathCoroutine != null)
{
StopCoroutine(_enemySpineDeathCoroutine);
@@ -2004,6 +2080,16 @@ public class teamUIController : MonoBehaviour
}
}
int nextEnemyIndex = enemyCurrentCount + 1;
if (nextEnemyIndex >= recognizedEnemySOs.Length)
{
AnimateEnemyBountyToZero(true);
}
else
{
AnimateEnemyBountyToZero(false);
}
enemyCurrentCount++;
SpawnNextEnemy();
}
@@ -2014,6 +2100,113 @@ public class teamUIController : MonoBehaviour
UpdateEnemyUIImmediate();
}
private int CalculateEnemyBountyScore(EnemyData_SO so)
{
if (so == null)
return 0;
int difficultyID = BeatmapManager.Instance != null ? BeatmapManager.Instance.assignedDifficulty : 0;
EnemyData_SO.EnemyDifficultyStats stats = so.GetStatsByDifficultyID(difficultyID);
int calculatedMaxHp = Mathf.Max(0, stats.enemy_maxHP);
float difficultyLevel = ResolveCurrentDifficultyLevel(difficultyID);
float totalBounty = calculatedMaxHp * 0.05f * difficultyLevel + so.enemyBountyBonus;
return Mathf.Max(0, Mathf.CeilToInt(totalBounty));
}
private float ResolveCurrentDifficultyLevel(int difficultyID)
{
BeatmapManager beatmapManager = BeatmapManager.Instance;
if (beatmapManager == null || beatmapManager.assignedSongData == null || beatmapManager.assignedSongData.chartFiles == null)
return 1f;
List<ChartFileEntry> chartFiles = beatmapManager.assignedSongData.chartFiles;
for (int i = 0; i < chartFiles.Count; i++)
{
ChartFileEntry entry = chartFiles[i];
if (entry == null || entry.difficulty != difficultyID)
continue;
return Mathf.Max(0f, entry.difficultyLEVEL);
}
return 1f;
}
private void SetEnemyBountyDisplayImmediate(int value)
{
currentDisplayedEnemyBounty = Mathf.Max(0, value);
if (currentEnemy_bountyText != null)
currentEnemy_bountyText.text = currentDisplayedEnemyBounty.ToString();
}
private void HideEnemyBountyUiImmediate()
{
if (enemyBountyTextCoroutine != null)
{
StopCoroutine(enemyBountyTextCoroutine);
enemyBountyTextCoroutine = null;
}
enemyBountyTransitionActive = false;
SetEnemyBountyDisplayImmediate(0);
if (currentEnemy_bountyObject != null)
currentEnemy_bountyObject.SetActive(false);
}
private void AnimateEnemyBountyRise(int targetValue)
{
if (enemyBountyTextCoroutine != null)
StopCoroutine(enemyBountyTextCoroutine);
if (currentEnemy_bountyObject != null)
currentEnemy_bountyObject.SetActive(true);
enemyBountyTransitionActive = true;
enemyBountyTextCoroutine = StartCoroutine(AnimateEnemyBountyValueRoutine(0, Mathf.Max(0, targetValue), 1f, false));
}
private void AnimateEnemyBountyToZero(bool hideAfterZero)
{
if (enemyBountyTextCoroutine != null)
StopCoroutine(enemyBountyTextCoroutine);
if (currentEnemy_bountyObject != null)
currentEnemy_bountyObject.SetActive(true);
enemyBountyTransitionActive = true;
enemyBountyTextCoroutine = StartCoroutine(AnimateEnemyBountyValueRoutine(currentDisplayedEnemyBounty, 0, 1f, hideAfterZero));
}
private IEnumerator AnimateEnemyBountyValueRoutine(int startValue, int endValue, float duration, bool deactivateAtEnd)
{
enemyBountyTransitionActive = true;
SetEnemyBountyDisplayImmediate(startValue);
if (duration <= 0f)
{
SetEnemyBountyDisplayImmediate(endValue);
}
else
{
float elapsed = 0f;
while (elapsed < duration)
{
elapsed += Time.deltaTime;
float t = Mathf.Clamp01(elapsed / duration);
int value = Mathf.RoundToInt(Mathf.Lerp(startValue, endValue, t));
SetEnemyBountyDisplayImmediate(value);
yield return null;
}
SetEnemyBountyDisplayImmediate(endValue);
}
enemyBountyTransitionActive = false;
enemyBountyTextCoroutine = null;
if (deactivateAtEnd && currentEnemy_bountyObject != null)
currentEnemy_bountyObject.SetActive(false);
}
// Documentation text normalized.
// =========================================================
@@ -2066,6 +2259,15 @@ public class teamUIController : MonoBehaviour
Debug.Log($"[teamUIController] Re-initializing current enemy instance with new HP: {stats.enemy_maxHP}");
enemyCombatantInstance.InitializeFromSO(currentSO, diffID);
UpdateEnemyUIImmediate();
// The first enemy can be spawned before BeatmapManager finishes writing
// the calculated HP back into the enemy SO. Refresh bounty text here so it
// reflects the final computed max HP rather than the pre-calculation value.
int refreshedBounty = CalculateEnemyBountyScore(currentSO);
if (currentEnemy_bountyObject != null)
currentEnemy_bountyObject.SetActive(true);
if (!enemyBountyTransitionActive)
SetEnemyBountyDisplayImmediate(refreshedBounty);
}
}
}
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 90bd6951a29795d4a943028d2150ce08
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 3211f9d28619bb347a531aa2252d51eb
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,159 @@
#if UNITY_EDITOR
using System.Reflection;
using UnityEditor;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
[InitializeOnLoad]
public static class GlobalAfterimageInstaller
{
private const string RendererDataPath = "Assets/Settings/Renderer2D.asset";
private const string GameplayVolumeProfilePath = "Assets/Scenes/gamePlay_gamePlay/gpGV.asset";
private static bool installScheduled;
static GlobalAfterimageInstaller()
{
ScheduleInstall();
}
[MenuItem("Bansonic/Rendering/Install Global Afterimage")]
public static void EnsureInstalledMenu()
{
EnsureInstalled();
}
private static void ScheduleInstall()
{
if (installScheduled)
return;
installScheduled = true;
EditorApplication.delayCall += RunScheduledInstall;
}
private static void RunScheduledInstall()
{
installScheduled = false;
EnsureInstalled();
}
private static void EnsureInstalled()
{
if (EditorApplication.isCompiling || BuildPipeline.isBuildingPlayer)
{
ScheduleInstall();
return;
}
if (IsUnsafeSelectionActive())
{
ScheduleInstall();
return;
}
EnsureRendererFeatureInstalled();
EnsureVolumeOverrideInstalled();
}
private static void EnsureRendererFeatureInstalled()
{
ScriptableRendererData rendererData = AssetDatabase.LoadAssetAtPath<ScriptableRendererData>(RendererDataPath);
if (rendererData == null)
return;
if (!rendererData.TryGetRendererFeature<GlobalAfterimageRendererFeature>(out GlobalAfterimageRendererFeature feature))
{
feature = ScriptableObject.CreateInstance<GlobalAfterimageRendererFeature>();
feature.name = "Global Afterimage Renderer Feature";
AssetDatabase.AddObjectToAsset(feature, rendererData);
rendererData.rendererFeatures.Add(feature);
rendererData.SetDirty();
EditorUtility.SetDirty(feature);
EditorUtility.SetDirty(rendererData);
TryValidateRendererFeatures(rendererData);
AssetDatabase.SaveAssets();
AssetDatabase.ImportAsset(RendererDataPath);
return;
}
if (feature.renderPassEvent != RenderPassEvent.AfterRenderingPostProcessing)
{
feature.renderPassEvent = RenderPassEvent.AfterRenderingPostProcessing;
rendererData.SetDirty();
EditorUtility.SetDirty(feature);
EditorUtility.SetDirty(rendererData);
AssetDatabase.SaveAssets();
}
}
private static void EnsureVolumeOverrideInstalled()
{
VolumeProfile profile = AssetDatabase.LoadAssetAtPath<VolumeProfile>(GameplayVolumeProfilePath);
if (profile == null)
return;
RemoveNullVolumeComponents(profile);
if (profile.TryGet<GlobalAfterimageVolume>(out _))
return;
GlobalAfterimageVolume component = profile.Add<GlobalAfterimageVolume>(true);
component.active = false;
component.opacity.overrideState = true;
component.opacity.value = 0f;
component.scale.overrideState = true;
component.scale.value = 1.05f;
component.affectSceneView.overrideState = true;
component.affectSceneView.value = false;
EditorUtility.SetDirty(component);
EditorUtility.SetDirty(profile);
AssetDatabase.SaveAssets();
}
private static void RemoveNullVolumeComponents(VolumeProfile profile)
{
SerializedObject serializedObject = new SerializedObject(profile);
SerializedProperty componentsProperty = serializedObject.FindProperty("components");
if (componentsProperty == null || !componentsProperty.isArray)
return;
bool removed = false;
for (int i = componentsProperty.arraySize - 1; i >= 0; i--)
{
SerializedProperty element = componentsProperty.GetArrayElementAtIndex(i);
if (element.objectReferenceValue != null)
continue;
componentsProperty.DeleteArrayElementAtIndex(i);
removed = true;
}
if (!removed)
return;
serializedObject.ApplyModifiedPropertiesWithoutUndo();
EditorUtility.SetDirty(profile);
AssetDatabase.SaveAssets();
}
private static void TryValidateRendererFeatures(ScriptableRendererData rendererData)
{
MethodInfo validateMethod = typeof(ScriptableRendererData).GetMethod("ValidateRendererFeatures", BindingFlags.Instance | BindingFlags.NonPublic);
validateMethod?.Invoke(rendererData, null);
}
private static bool IsUnsafeSelectionActive()
{
Object activeObject = Selection.activeObject;
if (activeObject is VolumeProfile || activeObject is Volume)
return true;
GameObject activeGameObject = Selection.activeGameObject;
if (activeGameObject == null)
return false;
return activeGameObject.TryGetComponent<Volume>(out _);
}
}
#endif
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: e5a6ce7542914bd428842b45057360d0
@@ -0,0 +1,167 @@
#if UNITY_EDITOR
using System.Reflection;
using UnityEditor;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
[InitializeOnLoad]
public static class GlobalDistortionInstaller
{
private const string RendererDataPath = "Assets/Settings/Renderer2D.asset";
private const string GameplayVolumeProfilePath = "Assets/Scenes/gamePlay_gamePlay/gpGV.asset";
private static bool installScheduled;
static GlobalDistortionInstaller()
{
ScheduleInstall();
}
[MenuItem("Bansonic/Rendering/Install Global Distortion")]
public static void EnsureInstalledMenu()
{
EnsureInstalled();
}
private static void ScheduleInstall()
{
if (installScheduled)
return;
installScheduled = true;
EditorApplication.delayCall += RunScheduledInstall;
}
private static void RunScheduledInstall()
{
installScheduled = false;
EnsureInstalled();
}
private static void EnsureInstalled()
{
if (EditorApplication.isCompiling || BuildPipeline.isBuildingPlayer)
{
ScheduleInstall();
return;
}
if (IsUnsafeSelectionActive())
{
ScheduleInstall();
return;
}
EnsureRendererFeatureInstalled();
EnsureVolumeOverrideInstalled();
}
private static void EnsureRendererFeatureInstalled()
{
ScriptableRendererData rendererData = AssetDatabase.LoadAssetAtPath<ScriptableRendererData>(RendererDataPath);
if (rendererData == null)
return;
if (!rendererData.TryGetRendererFeature<GlobalDistortionRendererFeature>(out GlobalDistortionRendererFeature feature))
{
feature = ScriptableObject.CreateInstance<GlobalDistortionRendererFeature>();
feature.name = "Global Distortion Renderer Feature";
AssetDatabase.AddObjectToAsset(feature, rendererData);
rendererData.rendererFeatures.Add(feature);
rendererData.SetDirty();
EditorUtility.SetDirty(feature);
EditorUtility.SetDirty(rendererData);
TryValidateRendererFeatures(rendererData);
AssetDatabase.SaveAssets();
AssetDatabase.ImportAsset(RendererDataPath);
return;
}
if (feature.renderPassEvent != RenderPassEvent.AfterRenderingPostProcessing)
{
feature.renderPassEvent = RenderPassEvent.AfterRenderingPostProcessing;
rendererData.SetDirty();
EditorUtility.SetDirty(feature);
EditorUtility.SetDirty(rendererData);
AssetDatabase.SaveAssets();
}
}
private static void EnsureVolumeOverrideInstalled()
{
VolumeProfile profile = AssetDatabase.LoadAssetAtPath<VolumeProfile>(GameplayVolumeProfilePath);
if (profile == null)
return;
RemoveNullVolumeComponents(profile);
if (profile.TryGet<GlobalDistortionVolume>(out _))
return;
GlobalDistortionVolume component = profile.Add<GlobalDistortionVolume>(true);
component.active = false;
component.intensity.overrideState = true;
component.intensity.value = 0f;
component.noiseStrength.overrideState = true;
component.noiseStrength.value = 0.16f;
component.radialStrength.overrideState = true;
component.radialStrength.value = 0.35f;
component.noiseScale.overrideState = true;
component.noiseScale.value = 12f;
component.center.overrideState = true;
component.center.value = new Vector2(0.5f, 0.5f);
component.edgeFade.overrideState = true;
component.edgeFade.value = 1.25f;
component.affectSceneView.overrideState = true;
component.affectSceneView.value = false;
EditorUtility.SetDirty(component);
EditorUtility.SetDirty(profile);
AssetDatabase.SaveAssets();
}
private static void RemoveNullVolumeComponents(VolumeProfile profile)
{
SerializedObject serializedObject = new SerializedObject(profile);
SerializedProperty componentsProperty = serializedObject.FindProperty("components");
if (componentsProperty == null || !componentsProperty.isArray)
return;
bool removed = false;
for (int i = componentsProperty.arraySize - 1; i >= 0; i--)
{
SerializedProperty element = componentsProperty.GetArrayElementAtIndex(i);
if (element.objectReferenceValue != null)
continue;
componentsProperty.DeleteArrayElementAtIndex(i);
removed = true;
}
if (!removed)
return;
serializedObject.ApplyModifiedPropertiesWithoutUndo();
EditorUtility.SetDirty(profile);
AssetDatabase.SaveAssets();
}
private static void TryValidateRendererFeatures(ScriptableRendererData rendererData)
{
MethodInfo validateMethod = typeof(ScriptableRendererData).GetMethod("ValidateRendererFeatures", BindingFlags.Instance | BindingFlags.NonPublic);
validateMethod?.Invoke(rendererData, null);
}
private static bool IsUnsafeSelectionActive()
{
Object activeObject = Selection.activeObject;
if (activeObject is VolumeProfile || activeObject is Volume)
return true;
GameObject activeGameObject = Selection.activeGameObject;
if (activeGameObject == null)
return false;
return activeGameObject.TryGetComponent<Volume>(out _);
}
}
#endif
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 8da344594051c8647abdb52bec165007
@@ -0,0 +1,167 @@
#if UNITY_EDITOR
using System.Reflection;
using UnityEditor;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
[InitializeOnLoad]
public static class GlobalGlitchInstaller
{
private const string RendererDataPath = "Assets/Settings/Renderer2D.asset";
private const string GameplayVolumeProfilePath = "Assets/Scenes/gamePlay_gamePlay/gpGV.asset";
private static bool installScheduled;
static GlobalGlitchInstaller()
{
ScheduleInstall();
}
[MenuItem("Bansonic/Rendering/Install Global Glitch")]
public static void EnsureInstalledMenu()
{
EnsureInstalled();
}
private static void ScheduleInstall()
{
if (installScheduled)
return;
installScheduled = true;
EditorApplication.delayCall += RunScheduledInstall;
}
private static void RunScheduledInstall()
{
installScheduled = false;
EnsureInstalled();
}
private static void EnsureInstalled()
{
if (EditorApplication.isCompiling || BuildPipeline.isBuildingPlayer)
{
ScheduleInstall();
return;
}
if (IsUnsafeSelectionActive())
{
ScheduleInstall();
return;
}
EnsureRendererFeatureInstalled();
EnsureVolumeOverrideInstalled();
}
private static void EnsureRendererFeatureInstalled()
{
ScriptableRendererData rendererData = AssetDatabase.LoadAssetAtPath<ScriptableRendererData>(RendererDataPath);
if (rendererData == null)
return;
if (!rendererData.TryGetRendererFeature<GlobalGlitchRendererFeature>(out GlobalGlitchRendererFeature feature))
{
feature = ScriptableObject.CreateInstance<GlobalGlitchRendererFeature>();
feature.name = "Global Glitch Renderer Feature";
AssetDatabase.AddObjectToAsset(feature, rendererData);
rendererData.rendererFeatures.Add(feature);
rendererData.SetDirty();
EditorUtility.SetDirty(feature);
EditorUtility.SetDirty(rendererData);
TryValidateRendererFeatures(rendererData);
AssetDatabase.SaveAssets();
AssetDatabase.ImportAsset(RendererDataPath);
return;
}
if (feature.renderPassEvent != RenderPassEvent.AfterRenderingPostProcessing)
{
feature.renderPassEvent = RenderPassEvent.AfterRenderingPostProcessing;
rendererData.SetDirty();
EditorUtility.SetDirty(feature);
EditorUtility.SetDirty(rendererData);
AssetDatabase.SaveAssets();
}
}
private static void EnsureVolumeOverrideInstalled()
{
VolumeProfile profile = AssetDatabase.LoadAssetAtPath<VolumeProfile>(GameplayVolumeProfilePath);
if (profile == null)
return;
RemoveNullVolumeComponents(profile);
if (profile.TryGet<GlobalGlitchVolume>(out _))
return;
GlobalGlitchVolume component = profile.Add<GlobalGlitchVolume>(true);
component.active = false;
component.intensity.overrideState = true;
component.intensity.value = 0f;
component.blockStrength.overrideState = true;
component.blockStrength.value = 0.45f;
component.colorSplit.overrideState = true;
component.colorSplit.value = 0.01f;
component.jitterAmount.overrideState = true;
component.jitterAmount.value = 0.4f;
component.stripFrequency.overrideState = true;
component.stripFrequency.value = 48f;
component.scanlineStrength.overrideState = true;
component.scanlineStrength.value = 0.18f;
component.affectSceneView.overrideState = true;
component.affectSceneView.value = false;
EditorUtility.SetDirty(component);
EditorUtility.SetDirty(profile);
AssetDatabase.SaveAssets();
}
private static void RemoveNullVolumeComponents(VolumeProfile profile)
{
SerializedObject serializedObject = new SerializedObject(profile);
SerializedProperty componentsProperty = serializedObject.FindProperty("components");
if (componentsProperty == null || !componentsProperty.isArray)
return;
bool removed = false;
for (int i = componentsProperty.arraySize - 1; i >= 0; i--)
{
SerializedProperty element = componentsProperty.GetArrayElementAtIndex(i);
if (element.objectReferenceValue != null)
continue;
componentsProperty.DeleteArrayElementAtIndex(i);
removed = true;
}
if (!removed)
return;
serializedObject.ApplyModifiedPropertiesWithoutUndo();
EditorUtility.SetDirty(profile);
AssetDatabase.SaveAssets();
}
private static void TryValidateRendererFeatures(ScriptableRendererData rendererData)
{
MethodInfo validateMethod = typeof(ScriptableRendererData).GetMethod("ValidateRendererFeatures", BindingFlags.Instance | BindingFlags.NonPublic);
validateMethod?.Invoke(rendererData, null);
}
private static bool IsUnsafeSelectionActive()
{
Object activeObject = Selection.activeObject;
if (activeObject is VolumeProfile || activeObject is Volume)
return true;
GameObject activeGameObject = Selection.activeGameObject;
if (activeGameObject == null)
return false;
return activeGameObject.TryGetComponent<Volume>(out _);
}
}
#endif
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: f7effde50fff3c34c8c188a696cf3bcf
@@ -0,0 +1,157 @@
#if UNITY_EDITOR
using System.Reflection;
using UnityEditor;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
[InitializeOnLoad]
public static class GlobalMonochromeInstaller
{
private const string RendererDataPath = "Assets/Settings/Renderer2D.asset";
private const string GameplayVolumeProfilePath = "Assets/Scenes/gamePlay_gamePlay/gpGV.asset";
private static bool installScheduled;
static GlobalMonochromeInstaller()
{
ScheduleInstall();
}
[MenuItem("Bansonic/Rendering/Install Global Monochrome")]
public static void EnsureInstalledMenu()
{
EnsureInstalled();
}
private static void ScheduleInstall()
{
if (installScheduled)
return;
installScheduled = true;
EditorApplication.delayCall += RunScheduledInstall;
}
private static void RunScheduledInstall()
{
installScheduled = false;
EnsureInstalled();
}
private static void EnsureInstalled()
{
if (EditorApplication.isCompiling || BuildPipeline.isBuildingPlayer)
{
ScheduleInstall();
return;
}
if (IsUnsafeSelectionActive())
{
ScheduleInstall();
return;
}
EnsureRendererFeatureInstalled();
EnsureVolumeOverrideInstalled();
}
private static void EnsureRendererFeatureInstalled()
{
ScriptableRendererData rendererData = AssetDatabase.LoadAssetAtPath<ScriptableRendererData>(RendererDataPath);
if (rendererData == null)
return;
if (!rendererData.TryGetRendererFeature<GlobalMonochromeRendererFeature>(out GlobalMonochromeRendererFeature feature))
{
feature = ScriptableObject.CreateInstance<GlobalMonochromeRendererFeature>();
feature.name = "Global Monochrome Renderer Feature";
AssetDatabase.AddObjectToAsset(feature, rendererData);
rendererData.rendererFeatures.Add(feature);
rendererData.SetDirty();
EditorUtility.SetDirty(feature);
EditorUtility.SetDirty(rendererData);
TryValidateRendererFeatures(rendererData);
AssetDatabase.SaveAssets();
AssetDatabase.ImportAsset(RendererDataPath);
return;
}
if (feature.renderPassEvent != RenderPassEvent.AfterRenderingPostProcessing)
{
feature.renderPassEvent = RenderPassEvent.AfterRenderingPostProcessing;
rendererData.SetDirty();
EditorUtility.SetDirty(feature);
EditorUtility.SetDirty(rendererData);
AssetDatabase.SaveAssets();
}
}
private static void EnsureVolumeOverrideInstalled()
{
VolumeProfile profile = AssetDatabase.LoadAssetAtPath<VolumeProfile>(GameplayVolumeProfilePath);
if (profile == null)
return;
RemoveNullVolumeComponents(profile);
if (profile.TryGet<GlobalMonochromeVolume>(out _))
return;
GlobalMonochromeVolume component = profile.Add<GlobalMonochromeVolume>(true);
component.active = false;
component.intensity.overrideState = true;
component.intensity.value = 0f;
component.affectSceneView.overrideState = true;
component.affectSceneView.value = false;
EditorUtility.SetDirty(component);
EditorUtility.SetDirty(profile);
AssetDatabase.SaveAssets();
}
private static void RemoveNullVolumeComponents(VolumeProfile profile)
{
SerializedObject serializedObject = new SerializedObject(profile);
SerializedProperty componentsProperty = serializedObject.FindProperty("components");
if (componentsProperty == null || !componentsProperty.isArray)
return;
bool removed = false;
for (int i = componentsProperty.arraySize - 1; i >= 0; i--)
{
SerializedProperty element = componentsProperty.GetArrayElementAtIndex(i);
if (element.objectReferenceValue != null)
continue;
componentsProperty.DeleteArrayElementAtIndex(i);
removed = true;
}
if (!removed)
return;
serializedObject.ApplyModifiedPropertiesWithoutUndo();
EditorUtility.SetDirty(profile);
AssetDatabase.SaveAssets();
}
private static void TryValidateRendererFeatures(ScriptableRendererData rendererData)
{
MethodInfo validateMethod = typeof(ScriptableRendererData).GetMethod("ValidateRendererFeatures", BindingFlags.Instance | BindingFlags.NonPublic);
validateMethod?.Invoke(rendererData, null);
}
private static bool IsUnsafeSelectionActive()
{
Object activeObject = Selection.activeObject;
if (activeObject is VolumeProfile || activeObject is Volume)
return true;
GameObject activeGameObject = Selection.activeGameObject;
if (activeGameObject == null)
return false;
return activeGameObject.TryGetComponent<Volume>(out _);
}
}
#endif
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 9530a18d124454244a6fc70d833e3182
@@ -0,0 +1,178 @@
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.RenderGraphModule;
using UnityEngine.Rendering.RenderGraphModule.Util;
using UnityEngine.Rendering.Universal;
public class GlobalAfterimageRendererFeature : ScriptableRendererFeature
{
[Tooltip("When the custom afterimage pass should execute.")]
public RenderPassEvent renderPassEvent = RenderPassEvent.AfterRenderingPostProcessing;
private Material material;
private GlobalAfterimagePass pass;
public override void Create()
{
if (pass == null)
pass = new GlobalAfterimagePass();
pass.renderPassEvent = renderPassEvent;
EnsureMaterial();
}
public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
{
if (!EnsureMaterial())
return;
Camera camera = renderingData.cameraData.camera;
if (camera == null)
return;
if (renderingData.cameraData.cameraType == CameraType.Preview || renderingData.cameraData.cameraType == CameraType.Reflection)
return;
if (!renderingData.cameraData.postProcessEnabled)
return;
GlobalAfterimageVolume settings = VolumeManager.instance.stack.GetComponent<GlobalAfterimageVolume>();
bool hasVolume = settings != null && settings.active;
float runtimeOpacity = GlobalAfterimageRuntimeController.RuntimeOpacity;
float baseOpacity = hasVolume ? settings.opacity.value : 0f;
float finalOpacity = Mathf.Clamp01(Mathf.Max(baseOpacity, runtimeOpacity));
if (finalOpacity <= 0.0001f)
return;
if (camera.cameraType == CameraType.SceneView && hasVolume && !settings.affectSceneView.value)
return;
float runtimeScale = Mathf.Max(1f, GlobalAfterimageRuntimeController.RuntimeScale);
float baseScale = hasVolume ? settings.scale.value : 1.05f;
float finalScale = Mathf.Max(baseScale, runtimeScale);
bool captureRequested = GlobalAfterimageRuntimeController.ConsumeCaptureRequest();
pass.Setup(material, finalOpacity, finalScale, captureRequested, renderingData.cameraData.cameraTargetDescriptor);
renderer.EnqueuePass(pass);
}
protected override void Dispose(bool disposing)
{
if (pass != null)
{
pass.Dispose();
pass = null;
}
if (material != null)
{
CoreUtils.Destroy(material);
material = null;
}
}
private bool EnsureMaterial()
{
if (material != null)
return true;
Shader shader = Shader.Find("Hidden/Bansonic/GlobalAfterimage");
if (shader == null)
return false;
material = CoreUtils.CreateEngineMaterial(shader);
return material != null;
}
private sealed class GlobalAfterimagePass : ScriptableRenderPass
{
private static readonly int OpacityId = Shader.PropertyToID("_AfterimageOpacity");
private static readonly int ScaleId = Shader.PropertyToID("_AfterimageScale");
private static readonly int SnapshotTexId = Shader.PropertyToID("_SnapshotTex");
private Material passMaterial;
private float opacity;
private float scale;
private bool captureRequested;
private RenderTextureDescriptor descriptor;
private RTHandle compatibilityCopy;
private RTHandle snapshotTexture;
public void Setup(Material material, float passOpacity, float passScale, bool passCaptureRequested, RenderTextureDescriptor targetDescriptor)
{
passMaterial = material;
opacity = passOpacity;
scale = Mathf.Max(1f, passScale);
captureRequested = passCaptureRequested;
descriptor = targetDescriptor;
descriptor.msaaSamples = 1;
descriptor.depthBufferBits = 0;
requiresIntermediateTexture = true;
RenderingUtils.ReAllocateHandleIfNeeded(ref snapshotTexture, descriptor, FilterMode.Bilinear, TextureWrapMode.Clamp, name: "_GlobalAfterimageSnapshot");
}
public void Dispose()
{
compatibilityCopy?.Release();
compatibilityCopy = null;
snapshotTexture?.Release();
snapshotTexture = null;
}
public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData)
{
if (passMaterial == null || snapshotTexture == null)
return;
UniversalResourceData resourceData = frameData.Get<UniversalResourceData>();
if (resourceData.isActiveTargetBackBuffer)
return;
ApplyMaterialProperties();
TextureHandle source = resourceData.activeColorTexture;
TextureHandle importedSnapshot = renderGraph.ImportTexture(snapshotTexture);
if (captureRequested)
{
renderGraph.AddBlitPass(source, importedSnapshot, Vector2.one, Vector2.zero, passName: "Global Afterimage Capture");
}
TextureDesc tempDesc = renderGraph.GetTextureDesc(source);
tempDesc.name = "CameraColor-GlobalAfterimageTemp";
tempDesc.clearBuffer = false;
TextureHandle tempTexture = renderGraph.CreateTexture(tempDesc);
RenderGraphUtils.BlitMaterialParameters effectParameters = new(source, tempTexture, passMaterial, 0);
renderGraph.AddBlitPass(effectParameters, passName: "Global Afterimage Effect");
renderGraph.AddBlitPass(tempTexture, resourceData.activeColorTexture, Vector2.one, Vector2.zero, passName: "Global Afterimage Restore");
}
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
if (passMaterial == null || snapshotTexture == null)
return;
ApplyMaterialProperties();
RenderingUtils.ReAllocateHandleIfNeeded(ref compatibilityCopy, descriptor, FilterMode.Bilinear, TextureWrapMode.Clamp, name: "_GlobalAfterimageCompatibilityCopy");
CommandBuffer cmd = CommandBufferPool.Get("Global Afterimage Pass");
if (captureRequested)
{
Blitter.BlitCameraTexture(cmd, renderingData.cameraData.renderer.cameraColorTargetHandle, snapshotTexture);
}
Blitter.BlitCameraTexture(cmd, renderingData.cameraData.renderer.cameraColorTargetHandle, compatibilityCopy);
Blitter.BlitCameraTexture(cmd, compatibilityCopy, renderingData.cameraData.renderer.cameraColorTargetHandle, passMaterial, 0);
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
}
private void ApplyMaterialProperties()
{
passMaterial.SetFloat(OpacityId, opacity);
passMaterial.SetFloat(ScaleId, scale);
if (snapshotTexture != null)
passMaterial.SetTexture(SnapshotTexId, snapshotTexture);
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: a28c239b9c2736e489a75bd286167cb9
@@ -0,0 +1,125 @@
using UnityEngine;
public class GlobalAfterimageRuntimeController : MonoBehaviour
{
public static GlobalAfterimageRuntimeController Instance { get; private set; }
[Header("Runtime Afterimage Defaults")]
public float defaultStartOpacity = 0.5f;
public float defaultFadeDuration = 0.22f;
public float defaultEndScale = 1.12f;
public bool useUnscaledTime = true;
public bool triggerOnEnable = false;
private static float sRuntimeOpacity;
private static float sRuntimeScale = 1f;
private static bool sCaptureRequested;
private float activeStartOpacity;
private float activeFadeDuration;
private float activeEndScale = 1f;
private float activeElapsed;
private bool activeAfterimage;
public static float RuntimeOpacity => sRuntimeOpacity;
public static float RuntimeScale => sRuntimeScale;
public static bool HasActiveAfterimage => sRuntimeOpacity > 0.0001f;
private void Awake()
{
if (Instance == null)
{
Instance = this;
return;
}
if (Instance != this)
Destroy(gameObject);
}
private void OnEnable()
{
if (triggerOnEnable)
TriggerAfterimage();
}
private void Update()
{
float delta = useUnscaledTime ? Time.unscaledDeltaTime : Time.deltaTime;
UpdateAfterimage(delta);
}
public void TriggerAfterimage()
{
TriggerAfterimage(defaultStartOpacity, defaultFadeDuration, defaultEndScale);
}
public void TriggerAfterimage(float startOpacity, float fadeDuration, float endScale)
{
activeStartOpacity = Mathf.Clamp01(startOpacity);
activeFadeDuration = Mathf.Max(0.0001f, fadeDuration);
activeEndScale = Mathf.Max(1f, endScale);
activeElapsed = 0f;
activeAfterimage = activeStartOpacity > 0.0001f;
sRuntimeOpacity = activeStartOpacity;
sRuntimeScale = 1f;
sCaptureRequested = activeAfterimage;
}
private void UpdateAfterimage(float delta)
{
if (!activeAfterimage)
{
sRuntimeOpacity = 0f;
sRuntimeScale = 1f;
return;
}
activeElapsed += delta;
float normalized = Mathf.Clamp01(activeElapsed / activeFadeDuration);
sRuntimeOpacity = Mathf.Lerp(activeStartOpacity, 0f, normalized);
sRuntimeScale = Mathf.Lerp(1f, activeEndScale, normalized);
if (normalized < 1f)
return;
activeAfterimage = false;
sRuntimeOpacity = 0f;
sRuntimeScale = 1f;
}
public static bool ConsumeCaptureRequest()
{
bool requested = sCaptureRequested;
sCaptureRequested = false;
return requested;
}
public static GlobalAfterimageRuntimeController EnsureInstance()
{
if (Instance != null)
return Instance;
GlobalAfterimageRuntimeController existing = FindFirstObjectByType<GlobalAfterimageRuntimeController>();
if (existing != null)
{
Instance = existing;
return existing;
}
GameObject runtimeObject = new GameObject("__global_afterimage_runtime");
Instance = runtimeObject.AddComponent<GlobalAfterimageRuntimeController>();
return Instance;
}
public static void Trigger(float startOpacity, float fadeDuration, float endScale)
{
EnsureInstance().TriggerAfterimage(startOpacity, fadeDuration, endScale);
}
public static void TriggerDefault()
{
EnsureInstance().TriggerAfterimage();
}
}

Some files were not shown because too many files have changed in this diff Show More