feat: Implement balance system and fix pause bug
Some checks failed
Gitea Actions Demo / Explore-Gitea-Actions (push) Has been cancelled
Some checks failed
Gitea Actions Demo / Explore-Gitea-Actions (push) Has been cancelled
- Добавлена система баланса игры (BalanceManager) для управления внутриигровой валютой - Баланс начисляется за импульсы оплаты и списывается за начало/продолжение игры - При старте игры весь внесенный баланс списывается, а жизни начисляются в соответствии с количеством оплат - Добавлены проверки достаточности баланса для начала и продолжения игры - Интегрирован BalanceManager с PaymentManager и GameManager - Исправлен баг с возможностью снятия паузы при показе баннера проигрыша/победы - Добавлена блокировка переключения паузы через IsActive флаг в PauseMenu - Жизни больше не могут уйти в минус при повторной смерти во время показа баннера - Настройки стоимости импульса, начала и продолжения игры берутся из SettingsManager
This commit is contained in:
parent
009152ac5b
commit
3944534cd0
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -16,6 +16,7 @@ GameObject:
|
||||
- component: {fileID: 6566017136146807207}
|
||||
- component: {fileID: 5633451267958679388}
|
||||
- component: {fileID: 6824661392768214298}
|
||||
- component: {fileID: -381940896145096749}
|
||||
- component: {fileID: -3912971501865491093}
|
||||
m_Layer: 0
|
||||
m_Name: Globals
|
||||
@ -159,6 +160,29 @@ MonoBehaviour:
|
||||
OnCreditRemoved:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
--- !u!114 &-381940896145096749
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4763496076470024150}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 729da18f5e9741c28ca2d1e11d3fb43b, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Assembly-CSharp::RR.Common.Managers.BalanceManager
|
||||
currentBalance: 0
|
||||
saveBalanceBetweenSessions: 0
|
||||
OnBalanceChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
OnBalanceAdded:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
OnBalanceSpent:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
--- !u!114 &-3912971501865491093
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
|
||||
@ -138,7 +138,7 @@ GameObject:
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
m_IsActive: 0
|
||||
--- !u!224 &28542763
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
@ -1279,9 +1279,9 @@ RectTransform:
|
||||
m_Father: {fileID: 2054206196}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 1, y: 0}
|
||||
m_AnchorMax: {x: 1, y: 0}
|
||||
m_AnchorMax: {x: 1, y: 1}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 20, y: 0}
|
||||
m_SizeDelta: {x: 20, y: -17}
|
||||
m_Pivot: {x: 1, y: 1}
|
||||
--- !u!114 &273493570
|
||||
MonoBehaviour:
|
||||
@ -1518,7 +1518,7 @@ MonoBehaviour:
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_text: "\u041E\u041F\u041B\u0410\u0422\u0410 \u041D\u0415 \u0412\u041D\u0415\u0421\u0415\u041D\u0410"
|
||||
m_text: "\u0411\u0410\u041B\u0410\u041D\u0421\u0410 \u041D\u0415\u0414\u041E\u0421\u0422\u0410\u0422\u041E\u0427\u041D\u041E"
|
||||
m_isRightToLeft: 0
|
||||
m_fontAsset: {fileID: 11400000, guid: 5302535af1044152a457ed104f1f4b91, type: 2}
|
||||
m_sharedMaterial: {fileID: 2164040, guid: 5302535af1044152a457ed104f1f4b91, type: 2}
|
||||
@ -1633,9 +1633,9 @@ RectTransform:
|
||||
m_Father: {fileID: 2054206196}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 1, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 20}
|
||||
m_SizeDelta: {x: -17, y: 20}
|
||||
m_Pivot: {x: 0, y: 0}
|
||||
--- !u!114 &328533400
|
||||
MonoBehaviour:
|
||||
@ -1788,10 +1788,10 @@ RectTransform:
|
||||
m_Children: []
|
||||
m_Father: {fileID: 545548130}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_AnchorMin: {x: 0, y: 1}
|
||||
m_AnchorMax: {x: 0, y: 1}
|
||||
m_AnchoredPosition: {x: 307.1872, y: -384.23657}
|
||||
m_SizeDelta: {x: 600, y: 100}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &430243133
|
||||
MonoBehaviour:
|
||||
@ -1969,7 +1969,7 @@ RectTransform:
|
||||
m_Father: {fileID: 112549352}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 1, y: 1}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 20, y: 20}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
@ -3199,10 +3199,10 @@ RectTransform:
|
||||
m_Children: []
|
||||
m_Father: {fileID: 545548130}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_AnchorMin: {x: 0, y: 1}
|
||||
m_AnchorMax: {x: 0, y: 1}
|
||||
m_AnchoredPosition: {x: 307.1872, y: -534.2366}
|
||||
m_SizeDelta: {x: 600, y: 100}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &674695656
|
||||
MonoBehaviour:
|
||||
@ -3716,10 +3716,10 @@ RectTransform:
|
||||
- {fileID: 1631191833}
|
||||
m_Father: {fileID: 519510896}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_AnchorMin: {x: 0, y: 1}
|
||||
m_AnchorMax: {x: 0, y: 1}
|
||||
m_AnchoredPosition: {x: 307.1872, y: -209.23657}
|
||||
m_SizeDelta: {x: 400, y: 150}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!1 &780569109
|
||||
GameObject:
|
||||
@ -3981,10 +3981,10 @@ RectTransform:
|
||||
m_Children: []
|
||||
m_Father: {fileID: 545548130}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_AnchorMin: {x: 0, y: 1}
|
||||
m_AnchorMax: {x: 0, y: 1}
|
||||
m_AnchoredPosition: {x: 307.1872, y: -234.23657}
|
||||
m_SizeDelta: {x: 600, y: 100}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &783722930
|
||||
MonoBehaviour:
|
||||
@ -4122,9 +4122,9 @@ RectTransform:
|
||||
m_Father: {fileID: 265801313}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 1, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 20}
|
||||
m_SizeDelta: {x: -17, y: 20}
|
||||
m_Pivot: {x: 0, y: 0}
|
||||
--- !u!114 &787002084
|
||||
MonoBehaviour:
|
||||
@ -4395,10 +4395,10 @@ RectTransform:
|
||||
- {fileID: 457224350}
|
||||
m_Father: {fileID: 519510896}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_AnchorMin: {x: 0, y: 1}
|
||||
m_AnchorMax: {x: 0, y: 1}
|
||||
m_AnchoredPosition: {x: 307.1872, y: -409.23657}
|
||||
m_SizeDelta: {x: 400, y: 150}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!1 &817313575
|
||||
GameObject:
|
||||
@ -4569,10 +4569,10 @@ RectTransform:
|
||||
m_Children: []
|
||||
m_Father: {fileID: 545548130}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_AnchorMin: {x: 0, y: 1}
|
||||
m_AnchorMax: {x: 0, y: 1}
|
||||
m_AnchoredPosition: {x: 307.1872, y: -84.23657}
|
||||
m_SizeDelta: {x: 600, y: 100}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &820785317
|
||||
MonoBehaviour:
|
||||
@ -5926,7 +5926,7 @@ RectTransform:
|
||||
m_Father: {fileID: 1819180688}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 1, y: 1}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 20, y: 20}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
@ -6171,7 +6171,7 @@ RectTransform:
|
||||
m_Father: {fileID: 837630039}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 1, y: 1}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 20, y: 20}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
@ -7052,7 +7052,7 @@ GameObject:
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
m_IsActive: 0
|
||||
--- !u!224 &1460883867
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
@ -7221,9 +7221,9 @@ RectTransform:
|
||||
m_Father: {fileID: 265801313}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 1, y: 1}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: -17, y: 0}
|
||||
m_Pivot: {x: 0, y: 1}
|
||||
--- !u!114 &1461740380
|
||||
MonoBehaviour:
|
||||
@ -7703,7 +7703,7 @@ RectTransform:
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 1, y: 1}
|
||||
m_AnchoredPosition: {x: 100, y: 0}
|
||||
m_SizeDelta: {x: -100, y: 0}
|
||||
m_SizeDelta: {x: -100, y: -630.0134}
|
||||
m_Pivot: {x: 0, y: 1}
|
||||
--- !u!114 &1537614490
|
||||
MonoBehaviour:
|
||||
@ -7812,9 +7812,9 @@ RectTransform:
|
||||
m_Father: {fileID: 2054206196}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 1, y: 1}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: -17, y: -17}
|
||||
m_Pivot: {x: 0, y: 1}
|
||||
--- !u!114 &1549457647
|
||||
MonoBehaviour:
|
||||
@ -8128,6 +8128,195 @@ Transform:
|
||||
- {fileID: 1696942874}
|
||||
m_Father: {fileID: 1996696314}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!1 &1625478927
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 1625478928}
|
||||
- component: {fileID: 1625478930}
|
||||
- component: {fileID: 1625478929}
|
||||
- component: {fileID: 1625478931}
|
||||
m_Layer: 5
|
||||
m_Name: BalanceText
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &1625478928
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1625478927}
|
||||
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: 1851115885}
|
||||
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: -375}
|
||||
m_SizeDelta: {x: 400, y: 50}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &1625478929
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1625478927}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Unity.TextMeshPro::TMPro.TextMeshProUGUI
|
||||
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: "\u0422\u0435\u043A\u0443\u0449\u0438\u0439 \u0431\u0430\u043B\u0430\u043D\u0441:
|
||||
0"
|
||||
m_isRightToLeft: 0
|
||||
m_fontAsset: {fileID: 11400000, guid: 5302535af1044152a457ed104f1f4b91, type: 2}
|
||||
m_sharedMaterial: {fileID: 2164040, guid: 5302535af1044152a457ed104f1f4b91, 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: 42.65
|
||||
m_fontSizeBase: 36
|
||||
m_fontWeight: 400
|
||||
m_enableAutoSizing: 1
|
||||
m_fontSizeMin: 18
|
||||
m_fontSizeMax: 72
|
||||
m_fontStyle: 0
|
||||
m_HorizontalAlignment: 1
|
||||
m_VerticalAlignment: 256
|
||||
m_textAlignment: 65535
|
||||
m_characterSpacing: 0
|
||||
m_characterHorizontalScale: 1
|
||||
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!222 &1625478930
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1625478927}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &1625478931
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1625478927}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: d67352bcb19c4561bb19609a290e8f84, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Assembly-CSharp::RR.Common.UI.BalanceDisplay
|
||||
balanceText: {fileID: 1625478929}
|
||||
textFormat: "\u0422\u0435\u043A\u0443\u0449\u0438\u0439 \u0431\u0430\u043B\u0430\u043D\u0441:
|
||||
{0}"
|
||||
animateOnChange: 1
|
||||
animationDuration: 0.3
|
||||
scaleCurve:
|
||||
serializedVersion: 2
|
||||
m_Curve:
|
||||
- serializedVersion: 3
|
||||
time: 0
|
||||
value: 1
|
||||
inSlope: 0
|
||||
outSlope: 0
|
||||
tangentMode: 0
|
||||
weightedMode: 0
|
||||
inWeight: 0
|
||||
outWeight: 0
|
||||
- serializedVersion: 3
|
||||
time: 0.44773006
|
||||
value: 1.0396395
|
||||
inSlope: -0.116342045
|
||||
outSlope: -0.116342045
|
||||
tangentMode: 0
|
||||
weightedMode: 0
|
||||
inWeight: 0.112806365
|
||||
outWeight: 0.33333334
|
||||
- serializedVersion: 3
|
||||
time: 0.99993896
|
||||
value: 1
|
||||
inSlope: 0
|
||||
outSlope: 0
|
||||
tangentMode: 0
|
||||
weightedMode: 0
|
||||
inWeight: 0
|
||||
outWeight: 0
|
||||
m_PreInfinity: 2
|
||||
m_PostInfinity: 2
|
||||
m_RotationOrder: 4
|
||||
--- !u!1 &1628533780
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
@ -9281,7 +9470,7 @@ MonoBehaviour:
|
||||
rememberGroupFoldout: 1
|
||||
groupOrder:
|
||||
- "\u041C\u0443\u0437\u044B\u043A\u0430 \u0438 \u0437\u0432\u0443\u043A\u0438"
|
||||
sortByNameInsideGroup: 1
|
||||
sortByNameInsideGroup: 0
|
||||
toggleRowPrefab: {fileID: -3497382869404314779, guid: 3f18baed1f4d89f4ab9b4caf0c789a38, type: 3}
|
||||
sliderRowPrefab: {fileID: 5445087308684328405, guid: a85153c0090994b438ad050a1dbcc306, type: 3}
|
||||
valueSelectorRowPrefab: {fileID: 5605032421712587294, guid: ef3fe155416356b4babfbdf354df7056, type: 3}
|
||||
@ -9433,7 +9622,7 @@ RectTransform:
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 1}
|
||||
m_AnchorMax: {x: 1, y: 1}
|
||||
m_AnchoredPosition: {x: 0, y: -0.00000016372034}
|
||||
m_AnchoredPosition: {x: 0, y: 0.00086001726}
|
||||
m_SizeDelta: {x: 0, y: 300}
|
||||
m_Pivot: {x: 0, y: 1}
|
||||
--- !u!114 &1792218764
|
||||
@ -9771,6 +9960,7 @@ RectTransform:
|
||||
- {fileID: 1200884212}
|
||||
- {fileID: 1532558928}
|
||||
- {fileID: 1227305891}
|
||||
- {fileID: 1625478928}
|
||||
m_Father: {fileID: 2082092901}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
@ -10069,7 +10259,7 @@ GameObject:
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
m_IsActive: 0
|
||||
--- !u!224 &1932206569
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
@ -10595,8 +10785,8 @@ RectTransform:
|
||||
m_Children: []
|
||||
m_Father: {fileID: 1071857129}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchorMin: {x: 0.000000059604645, y: 0}
|
||||
m_AnchorMax: {x: 1, y: 1}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 20, y: 20}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
|
||||
@ -252,6 +252,25 @@ namespace RR.Common.Controls
|
||||
/// </summary>
|
||||
public static int GetCredits() => CreditsCount;
|
||||
|
||||
/// <summary>
|
||||
/// Устанавливает количество кредитов напрямую (для синхронизации с балансом)
|
||||
/// </summary>
|
||||
public static void SetCredits(int amount)
|
||||
{
|
||||
int oldCredits = CreditsCount;
|
||||
CreditsCount = Mathf.Max(0, amount);
|
||||
PlayerPrefs.SetInt("CoinsCount", CreditsCount);
|
||||
|
||||
if (CreditsCount > oldCredits)
|
||||
{
|
||||
OnCreditAdded?.Invoke(CreditsCount);
|
||||
}
|
||||
else if (CreditsCount < oldCredits)
|
||||
{
|
||||
OnCreditRemoved?.Invoke(CreditsCount);
|
||||
}
|
||||
}
|
||||
|
||||
//===========================end: PUBLIC API===========================//
|
||||
|
||||
private void Update()
|
||||
|
||||
329
Assets/Scripts/Managers/BalanceManager.cs
Normal file
329
Assets/Scripts/Managers/BalanceManager.cs
Normal file
@ -0,0 +1,329 @@
|
||||
using RR.Common.Controls;
|
||||
using RR.Common.Settings;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
|
||||
namespace RR.Common.Managers
|
||||
{
|
||||
/// <summary>
|
||||
/// Менеджер игрового баланса. Управляет внутриигровой валютой,
|
||||
/// которая начисляется за импульсы оплаты и списывается за начало/продолжение игры.
|
||||
/// </summary>
|
||||
public class BalanceManager : MonoBehaviour
|
||||
{
|
||||
public static BalanceManager Instance { get; private set; }
|
||||
|
||||
[Header("Текущий баланс")]
|
||||
[SerializeField] private int currentBalance;
|
||||
|
||||
[Header("Настройки сохранения")]
|
||||
[SerializeField] private bool saveBalanceBetweenSessions = false;
|
||||
|
||||
// События для уведомления UI и других систем
|
||||
public UnityEvent<int> OnBalanceChanged;
|
||||
public UnityEvent<int, int> OnBalanceAdded; // (добавлено, новый баланс)
|
||||
public UnityEvent<int, int> OnBalanceSpent; // (потрачено, новый баланс)
|
||||
|
||||
/// <summary>
|
||||
/// Текущий баланс игрока
|
||||
/// </summary>
|
||||
public int CurrentBalance => currentBalance;
|
||||
|
||||
private const string BALANCE_SAVE_KEY = "PlayerBalance";
|
||||
|
||||
// Кешированные значения из настроек
|
||||
private int _impulseCost = 10;
|
||||
private int _startGameCost = 10;
|
||||
private int _continueGameCost = 5;
|
||||
private bool _freeGame = false;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (Instance != null && Instance != this)
|
||||
{
|
||||
Destroy(gameObject);
|
||||
return;
|
||||
}
|
||||
|
||||
Instance = this;
|
||||
DontDestroyOnLoad(gameObject);
|
||||
|
||||
Initialize();
|
||||
}
|
||||
|
||||
private void Initialize()
|
||||
{
|
||||
// Инициализация событий
|
||||
OnBalanceChanged ??= new UnityEvent<int>();
|
||||
OnBalanceChanged ??= new UnityEvent<int>();
|
||||
OnBalanceAdded ??= new UnityEvent<int, int>();
|
||||
OnBalanceSpent ??= new UnityEvent<int, int>();
|
||||
|
||||
// Загрузка баланса из сохранений
|
||||
if (saveBalanceBetweenSessions)
|
||||
{
|
||||
currentBalance = PlayerPrefs.GetInt(BALANCE_SAVE_KEY, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
currentBalance = 0;
|
||||
PlayerPrefs.SetInt(BALANCE_SAVE_KEY, 0);
|
||||
}
|
||||
|
||||
// Подписка на события настроек для кеширования значений
|
||||
var settingsManager = SettingsManager.Instance;
|
||||
if (settingsManager != null)
|
||||
{
|
||||
settingsManager.OnSettingsLoaded += CacheSettingsValues;
|
||||
settingsManager.OnSettingsSaved += CacheSettingsValues;
|
||||
CacheSettingsValues(); // Загрузка при инициализации
|
||||
}
|
||||
|
||||
// Подписка на события оплаты
|
||||
if (PaymentManager.Instance != null)
|
||||
{
|
||||
PaymentManager.Instance.OnCreditAdded.AddListener(OnImpulsePaid);
|
||||
}
|
||||
|
||||
Debug.Log($"[BalanceManager] Инициализирован. Баланс: {currentBalance}");
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
if (PaymentManager.Instance != null)
|
||||
{
|
||||
PaymentManager.Instance.OnCreditAdded.RemoveListener(OnImpulsePaid);
|
||||
}
|
||||
|
||||
var settingsManager = SettingsManager.Instance;
|
||||
if (settingsManager != null)
|
||||
{
|
||||
settingsManager.OnSettingsLoaded -= CacheSettingsValues;
|
||||
settingsManager.OnSettingsSaved -= CacheSettingsValues;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Кеширует значения из настроек
|
||||
/// </summary>
|
||||
private void CacheSettingsValues()
|
||||
{
|
||||
var settings = SettingsManager.Instance;
|
||||
if (settings == null)
|
||||
{
|
||||
Debug.LogError("[BalanceManager] SettingsManager is null, cannot cache settings!");
|
||||
return;
|
||||
}
|
||||
|
||||
_impulseCost = settings.GetInt("payment.paymentImpulseCost");
|
||||
_startGameCost = settings.GetInt("payment.startGameCost");
|
||||
_continueGameCost = settings.GetInt("payment.continueGameCost");
|
||||
_freeGame = settings.GetBool("payment.freeGame");
|
||||
|
||||
// Валидация значений
|
||||
if (_impulseCost <= 0)
|
||||
{
|
||||
Debug.LogError($"[BalanceManager] Invalid payment.paymentImpulseCost: {_impulseCost}");
|
||||
_impulseCost = 10;
|
||||
}
|
||||
if (_startGameCost <= 0)
|
||||
{
|
||||
Debug.LogError($"[BalanceManager] Invalid payment.startGameCost: {_startGameCost}");
|
||||
_startGameCost = 10;
|
||||
}
|
||||
if (_continueGameCost <= 0)
|
||||
{
|
||||
Debug.LogError($"[BalanceManager] Invalid payment.continueGameCost: {_continueGameCost}");
|
||||
_continueGameCost = 5;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Обработчик оплаты импульса - начисляет баланс
|
||||
/// </summary>
|
||||
private void OnImpulsePaid(int creditsCount)
|
||||
{
|
||||
// creditsCount - это количество добавленных кредитов (всегда 1 для одного импульса)
|
||||
// Начисляем стоимость импульса
|
||||
AddBalance(_impulseCost);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Добавляет баланс игроку
|
||||
/// </summary>
|
||||
/// <param name="amount">Количество добавляемого баланса</param>
|
||||
public void AddBalance(int amount)
|
||||
{
|
||||
if (amount <= 0)
|
||||
{
|
||||
Debug.LogWarning($"[BalanceManager] Trying to add invalid amount: {amount}");
|
||||
return;
|
||||
}
|
||||
|
||||
currentBalance += amount;
|
||||
|
||||
// Сохранение если включено
|
||||
if (saveBalanceBetweenSessions)
|
||||
{
|
||||
PlayerPrefs.SetInt(BALANCE_SAVE_KEY, currentBalance);
|
||||
PlayerPrefs.Save();
|
||||
}
|
||||
|
||||
// Синхронизация кредитов с балансом
|
||||
SyncCreditsWithBalance();
|
||||
|
||||
// Уведомление подписчиков
|
||||
OnBalanceAdded?.Invoke(amount, currentBalance);
|
||||
OnBalanceChanged?.Invoke(currentBalance);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Проверяет, достаточно ли баланса для начала игры
|
||||
/// </summary>
|
||||
public bool CanStartGame()
|
||||
{
|
||||
// Проверка бесплатной игры
|
||||
if (_freeGame)
|
||||
return true;
|
||||
|
||||
return currentBalance >= _startGameCost;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Проверяет, достаточно ли баланса для продолжения игры
|
||||
/// </summary>
|
||||
public bool CanContinueGame()
|
||||
{
|
||||
// Проверка бесплатной игры
|
||||
if (_freeGame)
|
||||
return true;
|
||||
|
||||
return currentBalance >= _continueGameCost;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Списывает баланс за начало игры
|
||||
/// </summary>
|
||||
/// <returns>true если списание успешно</returns>
|
||||
public bool SpendForStart()
|
||||
{
|
||||
// Проверка бесплатной игры
|
||||
if (_freeGame)
|
||||
return true;
|
||||
|
||||
return SpendBalance(_startGameCost, "начало игры");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Списывает баланс за продолжение игры
|
||||
/// </summary>
|
||||
/// <returns>true если списание успешно</returns>
|
||||
public bool SpendForContinue()
|
||||
{
|
||||
// Проверка бесплатной игры
|
||||
if (_freeGame)
|
||||
return true;
|
||||
|
||||
return SpendBalance(_continueGameCost, "продолжение игры");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Списывает указанное количество баланса
|
||||
/// </summary>
|
||||
/// <param name="amount">Количество списываемого баланса</param>
|
||||
/// <param name="reason">Причина списания (для логирования)</param>
|
||||
/// <returns>true если списание успешно</returns>
|
||||
public bool SpendBalance(int amount, string reason = "")
|
||||
{
|
||||
if (amount <= 0)
|
||||
{
|
||||
Debug.LogWarning($"[BalanceManager] Trying to spend invalid amount: {amount}");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (currentBalance < amount)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
currentBalance -= amount;
|
||||
|
||||
// Сохранение если включено
|
||||
if (saveBalanceBetweenSessions)
|
||||
{
|
||||
PlayerPrefs.SetInt(BALANCE_SAVE_KEY, currentBalance);
|
||||
PlayerPrefs.Save();
|
||||
}
|
||||
|
||||
// Синхронизация кредитов с балансом
|
||||
SyncCreditsWithBalance();
|
||||
|
||||
// Уведомление подписчиков
|
||||
OnBalanceSpent?.Invoke(amount, currentBalance);
|
||||
OnBalanceChanged?.Invoke(currentBalance);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Сбрасывает баланс до нуля
|
||||
/// </summary>
|
||||
public void ResetBalance()
|
||||
{
|
||||
currentBalance = 0;
|
||||
|
||||
if (saveBalanceBetweenSessions)
|
||||
{
|
||||
PlayerPrefs.SetInt(BALANCE_SAVE_KEY, 0);
|
||||
PlayerPrefs.Save();
|
||||
}
|
||||
|
||||
// Синхронизация кредитов с балансом
|
||||
SyncCreditsWithBalance();
|
||||
|
||||
OnBalanceChanged?.Invoke(currentBalance);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Синхронизирует кредиты в ComWrapper с текущим балансом
|
||||
/// по формуле: кредиты = баланс / стоимость_импульса (округление вниз)
|
||||
/// </summary>
|
||||
private void SyncCreditsWithBalance()
|
||||
{
|
||||
if (_impulseCost <= 0)
|
||||
{
|
||||
Debug.LogError("[BalanceManager] Cannot sync credits - invalid impulse cost");
|
||||
return;
|
||||
}
|
||||
|
||||
int targetCredits = currentBalance / _impulseCost;
|
||||
int currentCredits = ComWrapper.GetCredits();
|
||||
|
||||
if (targetCredits == currentCredits)
|
||||
return; // Кредиты уже синхронизированы
|
||||
|
||||
// Устанавливаем кредиты напрямую через SetCredits
|
||||
ComWrapper.SetCredits(targetCredits);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Устанавливает баланс напрямую (для тестирования/отладки)
|
||||
/// </summary>
|
||||
public void SetBalance(int amount)
|
||||
{
|
||||
currentBalance = Mathf.Max(0, amount);
|
||||
|
||||
if (saveBalanceBetweenSessions)
|
||||
{
|
||||
PlayerPrefs.SetInt(BALANCE_SAVE_KEY, currentBalance);
|
||||
PlayerPrefs.Save();
|
||||
}
|
||||
|
||||
// Синхронизация кредитов с балансом
|
||||
SyncCreditsWithBalance();
|
||||
|
||||
OnBalanceChanged?.Invoke(currentBalance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
3
Assets/Scripts/Managers/BalanceManager.cs.meta
Normal file
3
Assets/Scripts/Managers/BalanceManager.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 729da18f5e9741c28ca2d1e11d3fb43b
|
||||
timeCreated: 1770384164
|
||||
@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.IO;
|
||||
using RR.Common.Controls;
|
||||
using UnityEngine;
|
||||
@ -26,6 +26,8 @@ namespace RR.Game2D.Core.Managers
|
||||
public AudioManager Audio {get; private set;}
|
||||
// Payment control for game
|
||||
public PaymentManager Payment {get; private set;}
|
||||
// Balance control for game
|
||||
public BalanceManager Balance {get; private set;}
|
||||
|
||||
// Plate control for game
|
||||
public ComWrapper Plate { get; private set; }
|
||||
@ -144,6 +146,10 @@ namespace RR.Game2D.Core.Managers
|
||||
// Initialize Payment control
|
||||
if (Payment == null) Payment = globals.GetComponent<PaymentManager>();
|
||||
|
||||
// Initialize Balance control
|
||||
if (Balance == null) Balance = globals.GetComponent<BalanceManager>();
|
||||
if (Balance == null) Balance = BalanceManager.Instance;
|
||||
|
||||
// Apply loaded settings (new system applies automatically in Awake)
|
||||
|
||||
if (Plate == null) Plate = globals.GetComponent<ComWrapper>();
|
||||
@ -264,7 +270,52 @@ public void TogglePause() => SetPause(!IsPaused);
|
||||
/// </summary>
|
||||
public void NewGame()
|
||||
{
|
||||
Lives = MaxLives;
|
||||
Debug.Log("[GameManager] NewGame called");
|
||||
|
||||
// Проверка баланса перед началом игры
|
||||
if (Balance != null && !Balance.CanStartGame())
|
||||
{
|
||||
Logger?.Log(gameObject.name, "Cannot start game - insufficient balance");
|
||||
Debug.LogWarning("[GameManager] Cannot start - insufficient balance");
|
||||
return;
|
||||
}
|
||||
|
||||
int livesToGive = StartingLives;
|
||||
int balanceToSpend = 0;
|
||||
|
||||
if (Balance != null)
|
||||
{
|
||||
int currentBalance = Balance.CurrentBalance;
|
||||
int impulseCost = Settings?.GetInt("payment.paymentImpulseCost") ?? 10;
|
||||
|
||||
// Рассчитываем количество оплат
|
||||
int totalImpulses = currentBalance / impulseCost;
|
||||
|
||||
// Первая оплата даёт базовые жизни
|
||||
// Каждая дополнительная оплата даёт LivesIncrement жизней
|
||||
if (totalImpulses > 0)
|
||||
{
|
||||
int additionalImpulses = totalImpulses - 1;
|
||||
int bonusLives = additionalImpulses * LivesIncrement;
|
||||
livesToGive = StartingLives + bonusLives;
|
||||
|
||||
Debug.Log($"[GameManager] Balance: {currentBalance}, Impulses: {totalImpulses}, Base lives: {StartingLives}, Bonus lives: {bonusLives}, Total lives: {livesToGive}");
|
||||
}
|
||||
|
||||
// Списываем ВЕСЬ баланс
|
||||
balanceToSpend = currentBalance;
|
||||
|
||||
if (!Balance.SpendBalance(balanceToSpend, "начало игры (полный баланс)"))
|
||||
{
|
||||
Logger?.Log(gameObject.name, "Failed to spend balance for game start");
|
||||
Debug.LogError("[GameManager] Failed to spend balance!");
|
||||
return;
|
||||
}
|
||||
|
||||
Debug.Log($"[GameManager] Spent entire balance: {balanceToSpend}, Lives given: {livesToGive}");
|
||||
}
|
||||
|
||||
Lives = livesToGive;
|
||||
LivesChanged?.Invoke(Lives);
|
||||
Coins = 0;
|
||||
CoinsChanged?.Invoke(Coins);
|
||||
@ -272,16 +323,27 @@ public void TogglePause() => SetPause(!IsPaused);
|
||||
_gameStartTime = Time.time;
|
||||
Logger.Log(gameObject.name,$"Game start time = {_gameStartTime}");
|
||||
|
||||
if (!Payment.IsFreePlayEnabled()) Payment.ProcessPayment(Payment.CreditsCount);
|
||||
if (Plate) Plate.StopBlink();
|
||||
|
||||
LoadLevel(1, 1);
|
||||
|
||||
}
|
||||
|
||||
public void ContinueGame()
|
||||
{
|
||||
if (!Payment.ProcessPayment()) return;
|
||||
// Проверка баланса перед продолжением игры
|
||||
if (Balance != null && !Balance.CanContinueGame())
|
||||
{
|
||||
Logger?.Log(gameObject.name, "Cannot continue game - insufficient balance");
|
||||
return;
|
||||
}
|
||||
|
||||
// Списание баланса за продолжение игры
|
||||
if (Balance != null && !Balance.SpendForContinue())
|
||||
{
|
||||
Logger?.Log(gameObject.name, "Failed to spend balance for continue");
|
||||
return;
|
||||
}
|
||||
|
||||
Lives = StartingLives + 1;
|
||||
LivesChanged?.Invoke(Lives);
|
||||
Coins = 0;
|
||||
|
||||
@ -119,8 +119,8 @@ MonoBehaviour:
|
||||
options: []
|
||||
defaultOptionIndex: 0
|
||||
- key: payment.paymentImpulseCost
|
||||
displayName: "\u0421\u0442\u043E\u0438\u043C\u043E\u0441\u0442\u044C \u043E\u0434\u043D\u043E\u0433\u043E
|
||||
\u0438\u043C\u043F\u0443\u043B\u044C\u0441\u0430"
|
||||
displayName: "\u0421\u0442\u043E\u0438\u043C\u043E\u0441\u0442\u044C \u0438\u043C\u043F\u0443\u043B\u044C\u0441\u0430
|
||||
\u043E\u043F\u043B\u0430\u0442\u044B"
|
||||
description:
|
||||
group: "\u041E\u043F\u043B\u0430\u0442\u0430 \u0438 \u0441\u0442\u043E\u0438\u043C\u043E\u0441\u0442\u044C"
|
||||
shownInSettings: 1
|
||||
@ -145,6 +145,60 @@ MonoBehaviour:
|
||||
buttonSprite: {fileID: 0}
|
||||
options: []
|
||||
defaultOptionIndex: 0
|
||||
- key: payment.startGameCost
|
||||
displayName: "\u0421\u0442\u043E\u0438\u043C\u043E\u0441\u0442\u044C \u043D\u0430\u0447\u0430\u043B\u0430
|
||||
\u0438\u0433\u0440\u044B"
|
||||
description:
|
||||
group: "\u041E\u043F\u043B\u0430\u0442\u0430 \u0438 \u0441\u0442\u043E\u0438\u043C\u043E\u0441\u0442\u044C"
|
||||
shownInSettings: 1
|
||||
exposed: 0
|
||||
valueType: 1
|
||||
defaultBool: 0
|
||||
defaultInt: 10
|
||||
defaultFloat: 0
|
||||
defaultString:
|
||||
minInt: 10
|
||||
maxInt: 1000
|
||||
intDisplayFormat: 1
|
||||
intStep: 5
|
||||
minFloat: 0
|
||||
maxFloat: 1
|
||||
displayAsPercentage: 0
|
||||
applyTarget: 0
|
||||
audioTargetType: 0
|
||||
buttonText:
|
||||
buttonData:
|
||||
buttonColor: {r: 0, g: 0, b: 0, a: 0}
|
||||
buttonSprite: {fileID: 0}
|
||||
options: []
|
||||
defaultOptionIndex: 0
|
||||
- key: payment.continueGameCost
|
||||
displayName: "\u0421\u0442\u043E\u0438\u043C\u043E\u0441\u0442\u044C \u043F\u0440\u043E\u0434\u043E\u043B\u0436\u0435\u043D\u0438\u044F
|
||||
\u0438\u0433\u0440\u044B"
|
||||
description:
|
||||
group: "\u041E\u043F\u043B\u0430\u0442\u0430 \u0438 \u0441\u0442\u043E\u0438\u043C\u043E\u0441\u0442\u044C"
|
||||
shownInSettings: 1
|
||||
exposed: 0
|
||||
valueType: 1
|
||||
defaultBool: 0
|
||||
defaultInt: 10
|
||||
defaultFloat: 0
|
||||
defaultString:
|
||||
minInt: 5
|
||||
maxInt: 1000
|
||||
intDisplayFormat: 1
|
||||
intStep: 5
|
||||
minFloat: 0
|
||||
maxFloat: 1
|
||||
displayAsPercentage: 0
|
||||
applyTarget: 0
|
||||
audioTargetType: 0
|
||||
buttonText:
|
||||
buttonData:
|
||||
buttonColor: {r: 0, g: 0, b: 0, a: 0}
|
||||
buttonSprite: {fileID: 0}
|
||||
options: []
|
||||
defaultOptionIndex: 0
|
||||
- key: prizes.giveSmallPrize
|
||||
displayName: "\u0412\u044B\u0434\u0430\u0432\u0430\u0442\u044C \u043C\u0430\u043B\u0435\u043D\u044C\u043A\u0438\u0439
|
||||
\u043F\u0440\u0438\u0437"
|
||||
|
||||
@ -20,10 +20,26 @@ namespace RR.Common.Settings.UI
|
||||
|
||||
public void Setup(SettingEntry entry, int currentValue)
|
||||
{
|
||||
_entry = entry;
|
||||
_currentValue = Mathf.Clamp(currentValue, entry.minInt, entry.maxInt);
|
||||
_step = Mathf.Max(1, entry.intStep);
|
||||
if (entry == null)
|
||||
{
|
||||
Debug.LogError("[ValueSelectorRow] Cannot setup with null entry!");
|
||||
return;
|
||||
}
|
||||
|
||||
_entry = entry;
|
||||
|
||||
// Валидация step
|
||||
if (entry.intStep <= 0)
|
||||
{
|
||||
Debug.LogWarning($"[ValueSelectorRow] Invalid step {entry.intStep} for key {entry.key}, using 1");
|
||||
_step = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
_step = entry.intStep;
|
||||
}
|
||||
|
||||
_currentValue = Mathf.Clamp(currentValue, entry.minInt, entry.maxInt);
|
||||
UpdateUI();
|
||||
}
|
||||
|
||||
@ -61,9 +77,7 @@ namespace RR.Common.Settings.UI
|
||||
int newValue = Mathf.Max(_entry.minInt, _currentValue - _step);
|
||||
if (newValue != _currentValue)
|
||||
{
|
||||
_currentValue = newValue;
|
||||
UpdateUI();
|
||||
SettingsManager.Instance?.SetInt(_entry.key, _currentValue);
|
||||
SetValue(newValue);
|
||||
}
|
||||
}
|
||||
|
||||
@ -72,9 +86,7 @@ namespace RR.Common.Settings.UI
|
||||
int newValue = Mathf.Min(_entry.maxInt, _currentValue + _step);
|
||||
if (newValue != _currentValue)
|
||||
{
|
||||
_currentValue = newValue;
|
||||
UpdateUI();
|
||||
SettingsManager.Instance?.SetInt(_entry.key, _currentValue);
|
||||
SetValue(newValue);
|
||||
}
|
||||
}
|
||||
|
||||
@ -89,8 +101,23 @@ namespace RR.Common.Settings.UI
|
||||
if (_entry == null)
|
||||
return;
|
||||
|
||||
_currentValue = Mathf.Clamp(value, _entry.minInt, _entry.maxInt);
|
||||
UpdateUI();
|
||||
int clampedValue = Mathf.Clamp(value, _entry.minInt, _entry.maxInt);
|
||||
if (clampedValue != _currentValue)
|
||||
{
|
||||
_currentValue = clampedValue;
|
||||
UpdateUI();
|
||||
|
||||
// Сохраняем изменения через SettingsManager
|
||||
var manager = SettingsManager.Instance;
|
||||
if (manager != null)
|
||||
{
|
||||
manager.SetInt(_entry.key, _currentValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("[ValueSelectorRow] SettingsManager.Instance is null!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string Key => _entry?.key;
|
||||
|
||||
164
Assets/Scripts/UI/BalanceDisplay.cs
Normal file
164
Assets/Scripts/UI/BalanceDisplay.cs
Normal file
@ -0,0 +1,164 @@
|
||||
using RR.Common.Managers;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
|
||||
namespace RR.Common.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// UI компонент для отображения текущего баланса игрока.
|
||||
/// Автоматически обновляется при изменении баланса.
|
||||
/// </summary>
|
||||
public class BalanceDisplay : MonoBehaviour
|
||||
{
|
||||
[Header("Настройки отображения")]
|
||||
[SerializeField] private TextMeshProUGUI balanceText;
|
||||
[SerializeField] private string textFormat = "Текущий баланс: {0}";
|
||||
|
||||
[Header("Опциональная анимация")]
|
||||
[SerializeField] private bool animateOnChange = true;
|
||||
[SerializeField] private float animationDuration = 0.3f;
|
||||
[SerializeField] private AnimationCurve scaleCurve = AnimationCurve.EaseInOut(0, 1, 1, 1);
|
||||
|
||||
private BalanceManager _balanceManager;
|
||||
private Coroutine _animationCoroutine;
|
||||
private Vector3 _originalScale;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (balanceText != null)
|
||||
{
|
||||
_originalScale = balanceText.transform.localScale;
|
||||
}
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
_balanceManager = BalanceManager.Instance;
|
||||
|
||||
if (_balanceManager != null)
|
||||
{
|
||||
// Подписываемся на события изменения баланса
|
||||
_balanceManager.OnBalanceChanged.AddListener(OnBalanceChanged);
|
||||
|
||||
// Устанавливаем начальное значение
|
||||
UpdateBalanceDisplay(_balanceManager.CurrentBalance);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning("[BalanceDisplay] BalanceManager not found! Balance display will not work.");
|
||||
if (balanceText != null)
|
||||
{
|
||||
balanceText.text = string.Format(textFormat, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
if (_balanceManager != null)
|
||||
{
|
||||
_balanceManager.OnBalanceChanged.RemoveListener(OnBalanceChanged);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Обработчик изменения баланса
|
||||
/// </summary>
|
||||
private void OnBalanceChanged(int newBalance)
|
||||
{
|
||||
UpdateBalanceDisplay(newBalance);
|
||||
|
||||
if (animateOnChange && balanceText != null)
|
||||
{
|
||||
AnimateBalanceChange();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Обновляет текст баланса
|
||||
/// </summary>
|
||||
private void UpdateBalanceDisplay(int balance)
|
||||
{
|
||||
if (balanceText != null)
|
||||
{
|
||||
balanceText.text = string.Format(textFormat, balance);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Анимирует изменение баланса (масштабирование)
|
||||
/// </summary>
|
||||
private void AnimateBalanceChange()
|
||||
{
|
||||
if (_animationCoroutine != null)
|
||||
{
|
||||
StopCoroutine(_animationCoroutine);
|
||||
}
|
||||
|
||||
_animationCoroutine = StartCoroutine(ScaleAnimation());
|
||||
}
|
||||
|
||||
private System.Collections.IEnumerator ScaleAnimation()
|
||||
{
|
||||
float elapsed = 0f;
|
||||
|
||||
while (elapsed < animationDuration)
|
||||
{
|
||||
elapsed += Time.unscaledDeltaTime;
|
||||
float t = elapsed / animationDuration;
|
||||
|
||||
// Применяем кривую анимации
|
||||
float scaleMultiplier = scaleCurve.Evaluate(t);
|
||||
|
||||
// Небольшое увеличение и возврат к исходному размеру
|
||||
float scale = Mathf.Lerp(1.2f, 1f, t);
|
||||
balanceText.transform.localScale = _originalScale * scale * scaleMultiplier;
|
||||
|
||||
yield return null;
|
||||
}
|
||||
|
||||
// Гарантируем возврат к исходному масштабу
|
||||
balanceText.transform.localScale = _originalScale;
|
||||
_animationCoroutine = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Принудительное обновление отображения (для отладки)
|
||||
/// </summary>
|
||||
public void ForceUpdate()
|
||||
{
|
||||
if (_balanceManager != null)
|
||||
{
|
||||
UpdateBalanceDisplay(_balanceManager.CurrentBalance);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Изменить формат отображения текста
|
||||
/// </summary>
|
||||
public void SetTextFormat(string format)
|
||||
{
|
||||
textFormat = format;
|
||||
if (_balanceManager != null)
|
||||
{
|
||||
UpdateBalanceDisplay(_balanceManager.CurrentBalance);
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
/// <summary>
|
||||
/// Для предварительного просмотра в редакторе
|
||||
/// </summary>
|
||||
private void OnValidate()
|
||||
{
|
||||
if (Application.isPlaying) return;
|
||||
|
||||
if (balanceText != null)
|
||||
{
|
||||
balanceText.text = string.Format(textFormat, 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
3
Assets/Scripts/UI/BalanceDisplay.cs.meta
Normal file
3
Assets/Scripts/UI/BalanceDisplay.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d67352bcb19c4561bb19609a290e8f84
|
||||
timeCreated: 1770385844
|
||||
@ -24,8 +24,9 @@ namespace RR.Common.UI
|
||||
[Header("Тексты")]
|
||||
[SerializeField] private string creditTextFormat = "У вас осталось: {0}";
|
||||
|
||||
private RR.Common.Managers.PaymentManager _paymentManager;
|
||||
private RR.Common.Managers.BalanceManager _balanceManager;
|
||||
private Coroutine _continueCountdownCoroutine;
|
||||
private bool _isSubscribedToBalance = false;
|
||||
|
||||
/// <summary>
|
||||
/// Событие, вызываемое при нажатии "Продолжить" или закрытии баннера.
|
||||
@ -46,16 +47,22 @@ namespace RR.Common.UI
|
||||
{
|
||||
base.OnEnable();
|
||||
|
||||
_paymentManager = GameManager.Instance?.Payment;
|
||||
|
||||
if (_paymentManager != null)
|
||||
// Инициализируем BalanceManager
|
||||
if (_balanceManager == null)
|
||||
{
|
||||
int credits = _paymentManager.CreditsCount;
|
||||
_balanceManager = GameManager.Instance?.Balance;
|
||||
}
|
||||
|
||||
// Подписываемся на событие только если еще не подписаны
|
||||
if (_balanceManager != null && !_isSubscribedToBalance)
|
||||
{
|
||||
int balance = _balanceManager.CurrentBalance;
|
||||
if (creditText)
|
||||
{
|
||||
creditText.text = string.Format(creditTextFormat, credits);
|
||||
creditText.text = string.Format(creditTextFormat, balance);
|
||||
}
|
||||
_paymentManager.OnCreditAdded.AddListener(UnlockContinueButton);
|
||||
_balanceManager.OnBalanceChanged.AddListener(UnlockContinueButton);
|
||||
_isSubscribedToBalance = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -68,9 +75,11 @@ namespace RR.Common.UI
|
||||
_continueCountdownCoroutine = null;
|
||||
}
|
||||
|
||||
if (_paymentManager != null)
|
||||
// Безопасная отписка от события
|
||||
if (_balanceManager != null && _isSubscribedToBalance)
|
||||
{
|
||||
_paymentManager.OnCreditAdded.RemoveListener(UnlockContinueButton);
|
||||
_balanceManager.OnBalanceChanged.RemoveListener(UnlockContinueButton);
|
||||
_isSubscribedToBalance = false;
|
||||
}
|
||||
|
||||
base.OnDisable();
|
||||
@ -82,14 +91,27 @@ namespace RR.Common.UI
|
||||
/// <param name="gameTime">Время игры в секундах</param>
|
||||
public void ShowLose(float gameTime)
|
||||
{
|
||||
// Инициализируем BalanceManager до открытия окна
|
||||
if (_balanceManager == null)
|
||||
{
|
||||
_balanceManager = GameManager.Instance?.Balance;
|
||||
}
|
||||
|
||||
// Подписываемся на событие изменения баланса, если еще не подписаны
|
||||
if (_balanceManager != null && !_isSubscribedToBalance)
|
||||
{
|
||||
_balanceManager.OnBalanceChanged.AddListener(UnlockContinueButton);
|
||||
_isSubscribedToBalance = true;
|
||||
}
|
||||
|
||||
if (loseText)
|
||||
{
|
||||
loseText.text = $"Время игры: {TimeFormatHelper.FormatTime(gameTime)}";
|
||||
}
|
||||
|
||||
if (creditText && _paymentManager != null)
|
||||
if (creditText && _balanceManager != null)
|
||||
{
|
||||
creditText.text = string.Format(creditTextFormat, (object)_paymentManager.CreditsCount);
|
||||
creditText.text = string.Format(creditTextFormat, (object)_balanceManager.CurrentBalance);
|
||||
}
|
||||
|
||||
if (continueButtonCountdown <= 0f)
|
||||
@ -103,8 +125,9 @@ namespace RR.Common.UI
|
||||
if (continueButton)
|
||||
{
|
||||
continueButton.gameObject.SetActive(true);
|
||||
var settings = RR.Common.Settings.SettingsManager.Instance;
|
||||
continueButton.interactable = (settings != null && settings.GetBool("payment.freeGame")) || (_paymentManager != null && _paymentManager.CreditsCount > 0);
|
||||
// Проверяем возможность продолжить игру через BalanceManager
|
||||
bool canContinue = _balanceManager != null && _balanceManager.CanContinueGame();
|
||||
continueButton.interactable = canContinue;
|
||||
}
|
||||
|
||||
Open();
|
||||
@ -160,23 +183,20 @@ namespace RR.Common.UI
|
||||
}
|
||||
}
|
||||
|
||||
private void UnlockContinueButton(int newCredits)
|
||||
private void UnlockContinueButton(int newBalance)
|
||||
{
|
||||
if (_paymentManager == null) return;
|
||||
if (_balanceManager == null) return;
|
||||
|
||||
var settings = RR.Common.Settings.SettingsManager.Instance;
|
||||
if (_paymentManager.IsFreePlayEnabled() || (settings != null && settings.GetBool("payment.freeGame")))
|
||||
{
|
||||
if (continueButton)
|
||||
{
|
||||
continueButton.interactable = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Проверяем возможность продолжить через BalanceManager
|
||||
if (continueButton)
|
||||
{
|
||||
continueButton.interactable = _paymentManager.CreditsCount > 0;
|
||||
continueButton.interactable = _balanceManager.CanContinueGame();
|
||||
}
|
||||
|
||||
// Обновляем текст баланса
|
||||
if (creditText)
|
||||
{
|
||||
creditText.text = string.Format(creditTextFormat, newBalance);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using TMPro;
|
||||
|
||||
@ -16,12 +16,12 @@ namespace RR.Common.UI
|
||||
[Header("Тексты")]
|
||||
[SerializeField] private TextMeshProUGUI paymentText;
|
||||
|
||||
private RR.Common.Managers.PaymentManager _paymentManager;
|
||||
private RR.Common.Managers.BalanceManager _balanceManager;
|
||||
private RR.Common.Settings.SettingsManager _settingsManager;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
_paymentManager = RR.Common.Managers.PaymentManager.Instance;
|
||||
_balanceManager = RR.Common.Managers.BalanceManager.Instance;
|
||||
_settingsManager = RR.Common.Settings.SettingsManager.Instance;
|
||||
|
||||
Bootstrap();
|
||||
@ -31,8 +31,8 @@ namespace RR.Common.UI
|
||||
quitButton.gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
if (_paymentManager != null)
|
||||
_paymentManager.OnCreditsChanged.AddListener(OnCreditsChanged);
|
||||
if (_balanceManager != null)
|
||||
_balanceManager.OnBalanceChanged.AddListener(OnBalanceChanged);
|
||||
|
||||
if (_settingsManager != null)
|
||||
{
|
||||
@ -43,8 +43,8 @@ namespace RR.Common.UI
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
if (_paymentManager != null)
|
||||
_paymentManager.OnCreditsChanged.RemoveListener(OnCreditsChanged);
|
||||
if (_balanceManager != null)
|
||||
_balanceManager.OnBalanceChanged.RemoveListener(OnBalanceChanged);
|
||||
|
||||
if (_settingsManager != null)
|
||||
{
|
||||
@ -84,9 +84,9 @@ namespace RR.Common.UI
|
||||
Application.Quit();
|
||||
}
|
||||
|
||||
private void OnCreditsChanged(int credits)
|
||||
private void OnBalanceChanged(int balance)
|
||||
{
|
||||
UpdatePlayButtonState(credits);
|
||||
UpdatePlayButtonState();
|
||||
}
|
||||
|
||||
private void OnSettingsChanged()
|
||||
@ -94,12 +94,11 @@ namespace RR.Common.UI
|
||||
UpdatePlayButtonState();
|
||||
}
|
||||
|
||||
private void UpdatePlayButtonState(int credits = -1)
|
||||
private void UpdatePlayButtonState()
|
||||
{
|
||||
if (credits < 0)
|
||||
credits = _paymentManager?.CreditsCount ?? 0;
|
||||
if (!newGameButton) return;
|
||||
|
||||
// Проверяем только через SettingsManager, так как PaymentManager обновляется с задержкой
|
||||
// Проверяем бесплатную игру
|
||||
if (_settingsManager != null && _settingsManager.GetBool("payment.freeGame"))
|
||||
{
|
||||
newGameButton.interactable = true;
|
||||
@ -107,10 +106,9 @@ namespace RR.Common.UI
|
||||
return;
|
||||
}
|
||||
|
||||
paymentText.gameObject.SetActive(true);
|
||||
|
||||
if (!newGameButton) return;
|
||||
bool canStartGame = credits >= 1;
|
||||
// Проверяем баланс через BalanceManager
|
||||
bool canStartGame = _balanceManager != null && _balanceManager.CanStartGame();
|
||||
|
||||
newGameButton.interactable = canStartGame;
|
||||
paymentText.gameObject.SetActive(!canStartGame);
|
||||
}
|
||||
|
||||
@ -22,7 +22,10 @@ namespace RR.Common.UI
|
||||
[Header("Связь с другими элементами")]
|
||||
[SerializeField] private GameEndUIController bannerController;
|
||||
|
||||
private bool _isActive = true;
|
||||
/// <summary>
|
||||
/// Флаг активности меню. Деактивируется когда показан баннер проигрыша/победы.
|
||||
/// </summary>
|
||||
public bool IsActive { get; private set; } = true;
|
||||
|
||||
protected override void Awake()
|
||||
{
|
||||
@ -41,9 +44,9 @@ namespace RR.Common.UI
|
||||
|
||||
if (bannerController)
|
||||
{
|
||||
bannerController.WinBannerShown += _ => { _isActive = false; };
|
||||
bannerController.LoseBannerShown += _ => { _isActive = false; };
|
||||
bannerController.BannerDismissed += () => { _isActive = true; };
|
||||
bannerController.WinBannerShown += _ => { IsActive = false; };
|
||||
bannerController.LoseBannerShown += _ => { IsActive = false; };
|
||||
bannerController.BannerDismissed += () => { IsActive = true; };
|
||||
}
|
||||
|
||||
// Изначально скрыто - не вызываем base.Awake(), делаем это вручную
|
||||
@ -52,6 +55,9 @@ namespace RR.Common.UI
|
||||
|
||||
private void OnPauseToggle(InputAction.CallbackContext ctx)
|
||||
{
|
||||
// Блокируем паузу если меню неактивно (например, показан баннер проигрыша/победы)
|
||||
if (!IsActive) return;
|
||||
|
||||
GameManager.Instance.TogglePause();
|
||||
}
|
||||
|
||||
@ -68,7 +74,7 @@ namespace RR.Common.UI
|
||||
/// </summary>
|
||||
private void HandlePauseChanged(bool paused)
|
||||
{
|
||||
if (!_isActive) return;
|
||||
if (!IsActive) return;
|
||||
|
||||
if (paused)
|
||||
Open();
|
||||
@ -81,6 +87,9 @@ namespace RR.Common.UI
|
||||
/// </summary>
|
||||
public override void Close()
|
||||
{
|
||||
// Блокируем закрытие если меню неактивно (показан баннер)
|
||||
if (!IsActive) return;
|
||||
|
||||
base.Close();
|
||||
|
||||
// Если игра ещё на паузе, снимаем её
|
||||
@ -93,7 +102,14 @@ namespace RR.Common.UI
|
||||
/// <summary>
|
||||
/// Метод для возобновления игры.
|
||||
/// </summary>
|
||||
public static void OnResumeClicked() => GameManager.Instance.TogglePause();
|
||||
public static void OnResumeClicked()
|
||||
{
|
||||
// Блокируем если меню неактивно (показан баннер)
|
||||
var pauseMenu = FindFirstObjectByType<PauseMenu>();
|
||||
if (pauseMenu != null && !pauseMenu.IsActive) return;
|
||||
|
||||
GameManager.Instance.TogglePause();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Метод для выхода в главное меню.
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
using RR.Game2D.Core.Managers;
|
||||
using RR.Game2D.Core.Managers;
|
||||
using RR.Common.Settings;
|
||||
using RR.Common.Managers;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
|
||||
@ -17,10 +18,12 @@ namespace RR.Common.UI
|
||||
|
||||
private GameManager _gameManager;
|
||||
private SettingsManager _settingsManager;
|
||||
private BalanceManager _balanceManager;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
_gameManager = GameManager.Instance;
|
||||
_balanceManager = BalanceManager.Instance;
|
||||
|
||||
if (_gameManager == null) return;
|
||||
|
||||
@ -28,14 +31,21 @@ namespace RR.Common.UI
|
||||
|
||||
if (_settingsManager == null) _settingsManager = SettingsManager.Instance;
|
||||
|
||||
UpdateLivesText(_gameManager.MaxLives);
|
||||
UpdateLivesText();
|
||||
UpdateLivesIncreaseText();
|
||||
|
||||
_gameManager.MaxLivesChanged += UpdateLivesText;
|
||||
// Подписываемся на изменение баланса для пересчета жизней
|
||||
if (_balanceManager != null)
|
||||
{
|
||||
_balanceManager.OnBalanceChanged.AddListener(OnBalanceChanged);
|
||||
}
|
||||
|
||||
if (_settingsManager != null)
|
||||
{
|
||||
_settingsManager.OnSettingsLoaded += UpdateLivesIncreaseText;
|
||||
_settingsManager.OnSettingsSaved += UpdateLivesIncreaseText;
|
||||
_settingsManager.OnSettingsLoaded += OnSettingsChanged;
|
||||
_settingsManager.OnSettingsSaved += OnSettingsChanged;
|
||||
}
|
||||
}
|
||||
|
||||
@ -43,24 +53,59 @@ namespace RR.Common.UI
|
||||
{
|
||||
if (_gameManager == null) _gameManager = GameManager.Instance;
|
||||
|
||||
if (_gameManager != null) _gameManager.MaxLivesChanged -= UpdateLivesText;
|
||||
if (_balanceManager != null)
|
||||
{
|
||||
_balanceManager.OnBalanceChanged.RemoveListener(OnBalanceChanged);
|
||||
}
|
||||
|
||||
if (_settingsManager != null)
|
||||
{
|
||||
_settingsManager.OnSettingsLoaded -= UpdateLivesIncreaseText;
|
||||
_settingsManager.OnSettingsSaved -= UpdateLivesIncreaseText;
|
||||
_settingsManager.OnSettingsLoaded -= OnSettingsChanged;
|
||||
_settingsManager.OnSettingsSaved -= OnSettingsChanged;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnBalanceChanged(int newBalance)
|
||||
{
|
||||
UpdateLivesText();
|
||||
}
|
||||
|
||||
private void OnSettingsChanged()
|
||||
{
|
||||
UpdateLivesText();
|
||||
}
|
||||
|
||||
private void UpdateLivesIncreaseText()
|
||||
{
|
||||
if (_settingsManager != null)
|
||||
livesIncreaseText.text = string.Format(livesIncreaseString, _settingsManager.GetInt("gameplay.additionalLives"));
|
||||
}
|
||||
|
||||
private void UpdateLivesText(int newLives)
|
||||
private void UpdateLivesText()
|
||||
{
|
||||
livesText.text = string.Format(livesString, (object)newLives);
|
||||
if (_gameManager == null || _balanceManager == null || _settingsManager == null)
|
||||
return;
|
||||
|
||||
int currentBalance = _balanceManager.CurrentBalance;
|
||||
int impulseCost = _settingsManager.GetInt("payment.paymentImpulseCost");
|
||||
int startLives = _settingsManager.GetInt("gameplay.startLives");
|
||||
int livesIncrement = _settingsManager.GetInt("gameplay.additionalLives");
|
||||
|
||||
if (impulseCost <= 0) impulseCost = 10;
|
||||
|
||||
// Рассчитываем количество жизней на основе баланса
|
||||
int totalImpulses = currentBalance / impulseCost;
|
||||
int totalLives = startLives;
|
||||
|
||||
if (totalImpulses > 0)
|
||||
{
|
||||
int additionalImpulses = totalImpulses - 1;
|
||||
totalLives = startLives + (additionalImpulses * livesIncrement);
|
||||
}
|
||||
|
||||
livesText.text = string.Format(livesString, totalLives);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user