Рефакторинг MenuState

Сокращение и реорганизация кода;
Больше SRP
This commit is contained in:
Сергей Бондарь 2026-07-16 11:33:31 +03:00
parent b0cd7f54e2
commit b60ca37793
7 changed files with 267 additions and 428 deletions

View File

@ -3205,71 +3205,6 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 646dddf8b78bd2947bc1cac55fa02da6, type: 3}
m_Name:
m_EditorClassIdentifier:
PriceKey: PricePVP
readyToBlink: 0
frequency: -6
gradient:
key0:
r: 0.5294118
g: 0.8117648
b: 0.9490197
a: 0.039215688
key1:
r: 0.5294118
g: 0.8117648
b: 0.9490197
a: 0.39215687
key2:
r: 0
g: 0
b: 0
a: 0
key3:
r: 0
g: 0
b: 0
a: 0
key4:
r: 0
g: 0
b: 0
a: 0
key5:
r: 0
g: 0
b: 0
a: 0
key6:
r: 0
g: 0
b: 0
a: 0
key7:
r: 0
g: 0
b: 0
a: 0
ctime0: 0
ctime1: 65535
ctime2: 0
ctime3: 0
ctime4: 0
ctime5: 0
ctime6: 0
ctime7: 0
atime0: 0
atime1: 65535
atime2: 0
atime3: 0
atime4: 0
atime5: 0
atime6: 0
atime7: 0
m_Mode: 0
m_ColorSpace: -1
m_NumColorKeys: 2
m_NumAlphaKeys: 2
graphic: {fileID: 95872203}
--- !u!1 &96763655
GameObject:
m_ObjectHideFlags: 0
@ -6751,6 +6686,7 @@ MonoBehaviour:
board: {fileID: 1551328425}
noPrizeLabel: {fileID: 1796045835}
mainMenu: {fileID: 1122363131}
menuUi: {fileID: 1122363136}
russo_font: {fileID: 11400000, guid: 3f10bbcf486189d4f95b8de6dc2e2177, type: 2}
player1score: 0
player2score: 0
@ -8283,10 +8219,6 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: ee65f6c8bbb4bd74184a7984a8cc7d7a, type: 3}
m_Name:
m_EditorClassIdentifier:
settingId: DisplayPrizingError
SetEnabled: 1
Graphics:
- {fileID: 347540321}
--- !u!222 &347540323
CanvasRenderer:
m_ObjectHideFlags: 0
@ -11049,10 +10981,6 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: ee65f6c8bbb4bd74184a7984a8cc7d7a, type: 3}
m_Name:
m_EditorClassIdentifier:
settingId: Freeplay
SetEnabled: 1
Graphics:
- {fileID: 455099233}
--- !u!1 &457509955
GameObject:
m_ObjectHideFlags: 0
@ -26876,9 +26804,6 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: ae9fad8beffef1646a394c1b001fea29, type: 3}
m_Name:
m_EditorClassIdentifier:
startText: "\u0442\u0435\u0445. \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u043A\u0430:
+"
label: {fileID: 0}
--- !u!114 &850635957
MonoBehaviour:
m_ObjectHideFlags: 0
@ -36717,9 +36642,6 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: ae9fad8beffef1646a394c1b001fea29, type: 3}
m_Name:
m_EditorClassIdentifier:
startText: "\u0442\u0435\u0445. \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u043A\u0430:
+"
label: {fileID: 0}
--- !u!114 &1080584100
MonoBehaviour:
m_ObjectHideFlags: 0
@ -37946,6 +37868,7 @@ MonoBehaviour:
PveOption: {fileID: 2047831684}
PvpOption: {fileID: 95872202}
DownMenuGroup: {fileID: 109738548}
<AnimationInProcess>k__BackingField: 0
--- !u!1 &1124603895
GameObject:
m_ObjectHideFlags: 0
@ -58883,8 +58806,6 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: d437d18138bfafd49801f816f7babdd5, type: 3}
m_Name:
m_EditorClassIdentifier:
needToDisplay: 1
label: {fileID: 1279805984}
--- !u!114 &1796045838
MonoBehaviour:
m_ObjectHideFlags: 0
@ -58897,7 +58818,6 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 1a59fdef12446b242864a0d31143ffea, type: 3}
m_Name:
m_EditorClassIdentifier:
prizeLabel: {fileID: 1279805982}
--- !u!1 &1803015774
GameObject:
m_ObjectHideFlags: 0

View File

@ -1,375 +1,139 @@
using System.Collections;
using UnityEngine;
enum MenuSubStates { OpeningMenu, Choosing, Payment, ClosingMenu, SwitchState }
public class MenuState : IState
public class MenuState : IState
{
GameManager gm;
UiManager ui;
float SecondsToPromo = 180;
float ElapsedPromoTimer;
float timeToFastcheck = 2;
float GotoSettingsPressedTime = 3;
float ElapsedSettinsPressedTime;
bool animationEnded = true;
public Transform
label,
buttonLeft,
buttonRight,
coinPanel,
label2,
board,
noPrizeLabel;
RectTransform SmallPrizesOut;
MenuSubStates subState;
#region начальные и конечные позиции для элементов меню
//s - startPosition, e - endPosition
Vector2
//надпись "ФИШКА"
sLabel = new Vector2(0, 320),
eLabel = new Vector2(0, 1000),
//Иконки режимов
sButton = new Vector2(400, -15),
eButton = new Vector2(2000, -15),
//подсказка + лого + техподдержка
sLabel2 = new Vector2(0, -380),
eLabel2 = new Vector2(0, -1000),
//ИГРОВОЕ ПОЛЕ
sBoard = new Vector2(-40, -0.5f),
eBoard = new Vector2(0, -0.5f),
sNoPrize = new Vector2(-0, -70f),
eNoPrize = new Vector2(15, -409);
Vector3
sCoin = new Vector3(0, -201.538483f, 0),
eCoin = new Vector3(-732.999939f, 372, 0);
Vector2 sSmallPrizesOutSize = new Vector2(560, 100);
Vector2 eSmallPrizesOutSize = new Vector2(660, 100);
#endregion
public MenuState()
{
subState = MenuSubStates.Choosing;//субстейт и так ставится в энтере
}
private GameManager gm;
private UiManager ui;
private HoldTimer promoTimer;
private HoldTimer settingsTimer;
private MenuSubStates subState;
public void enter()
{
PullRefs();
ResetGameSession();
gm = GameManager.instance;
gm.ResetGameSession();
ElapsedPromoTimer = 0;
ui = gm.menuUi;
ui.OpenMenu();
subState = MenuSubStates.InputPolling;
promoTimer = new(180f);
settingsTimer = new(3f);
subState = gm.menuOpened ? MenuSubStates.Choosing : MenuSubStates.OpeningMenu;
LightUtility.Idle();
}
private void PullRefs()
public void exit()
{
gm = GameManager.instance;
ui = UiManager.Instance;
label = ui.UpperMenuGroup;
buttonLeft = ui.PveOption;
buttonRight = ui.PvpOption;
label2 = ui.DownMenuGroup;
coinPanel = gm.coinPanel;
board = gm.board;
noPrizeLabel = gm.noPrizeLabel;
SmallPrizesOut = gm.smallPrizesOut;
promoTimer.Reset();
settingsTimer.Reset();
}
private void ResetGameSession()
{
//ресет
gm.vsBotThinkTime = 0;
gm.vsBotMoves = 0;
gm.movesAndTimeCounter.SetVisibility(false);
CharacterController.HideCharacter();
CharacterController.I.SetAllCharactersPrizeAvailable(true);
DualAvatarController.Instance.HideCharacters();
DifficultyManager.Instance.ResetDifficulty();
gm.player1score = 0;
gm.player2score = 0;
gm.vsBotScore = 0;
VitrinaView.Instance.Deactivate();
gm.moveMade = false;
}
public void exit() { }
public void update()
{
switch (subState)
{
case MenuSubStates.OpeningMenu:
OpenMenu();
break;
case MenuSubStates.Choosing:
ChoosingMode();
break;
case MenuSubStates.Payment:
Payment();
break;
case MenuSubStates.ClosingMenu:
CloseMenu();
break;
case MenuSubStates.SwitchState:
SwitchState();
break;
}
if (subState == MenuSubStates.InputPolling)
InputPolling();
else if (subState == MenuSubStates.WaitAnimation)
WaitAnimation();
}
private void ChoosingMode()//основное состояние(выбор)
private void InputPolling()//основное состояние(выбор)
{
if (!animationEnded)
return;
if (ui.AnimationInProcess) return;
//Заход в настройки
if (ShouldGotosettings())
if (HandleSettings()) return;
if (HandleGameStart()) return;
if (HandleRules()) return;
if (HandleLeaderboard()) return;
if (HandlePromo()) return;
}
private bool HandleSettings()
{
bool settingButtonPressed = In.GetButton(ButtonPinMapping.secret);
bool gotoSettings = UnityEngine.Input.GetKeyDown(UnityEngine.KeyCode.F5) || settingsTimer.Update(settingButtonPressed);
if (gotoSettings)
{
SoundManager.instance.playChoose();
//gm.stateMachine.ChangeState(new SettingsState());
gm.stateMachine.ChangeState(new CheckSettingsPasswordState());
return;
TransitionTo(new CheckSettingsPasswordState());
return true;
}
return false;
}
//Определяемся с режимом игры
if (GamemodeChosen()) return;
private bool HandleGameStart() => TrySelectGameMode(out var mode) && TryStartGame(mode);
//Правила
private bool HandleRules()
{
if (In.GetButtonDownAnyPlayer(PlayerAction.down))
{
gm.stateMachine.ChangeState(new RulesState());
return;
TransitionTo(new RulesState());
return true;
}
return false;
}
//Промовидос
ElapsedPromoTimer = Mathf.Clamp(ElapsedPromoTimer + Time.deltaTime, 0, SecondsToPromo);
if (ElapsedPromoTimer == SecondsToPromo)
{
gm.stateMachine.ChangeState(new PromoState());
return;
}
//Заход в лидерборд
private bool HandleLeaderboard()
{
bool gotoLeaderboard = In.GetButtonDownAnyPlayer(PlayerAction.left) && In.GetButtonDownAnyPlayer(PlayerAction.right);
if (gotoLeaderboard)
{
ElapsedPromoTimer = 0;
gm.stateMachine.ChangeState(new CheckLeadersFromMenuState());
return;
}
//проверка счетчиков
bool checkCountersCombination = In.GetButton(ButtonPinMapping.startOnePlayer) && In.GetButton(ButtonPinMapping.startTwoPlayers);
if (checkCountersCombination)
{
timeToFastcheck -= Time.deltaTime;
if (timeToFastcheck <= 0)
{
bool fastCheckEnabled = SettingsManager.GetBool("FastCheck", false);
if (fastCheckEnabled) gm.fastCheckCounters.SetActive(true);
timeToFastcheck = 2;
}
}
else
timeToFastcheck = 2;
}
private bool ShouldGotosettings()
{
//читаем кнопки
bool settingButtonPressed = In.GetButton(ButtonPinMapping.secret);
//считаем таймер
float sign = settingButtonPressed ? 1 : -1;
ElapsedSettinsPressedTime += Time.deltaTime * sign;
ElapsedSettinsPressedTime = Mathf.Clamp(ElapsedSettinsPressedTime, 0, GotoSettingsPressedTime);
//Жали столько сколько надо для захода в меню
if (ElapsedSettinsPressedTime == GotoSettingsPressedTime
#if UNITY_EDITOR
|| Input.GetKey(KeyCode.F5)//по f5 для тестов заходим моментально
#endif
)
{
ElapsedSettinsPressedTime = 0;
TransitionTo(new CheckLeadersFromMenuState());
return true;
}
return false;
}
private bool GamemodeChosen()
{
bool onePlayer = In.GetButtonDown(ButtonPinMapping.startOnePlayer);
bool twoPlayer = In.GetButtonDown(ButtonPinMapping.startTwoPlayers);
if (onePlayer) gm.SetMode(GameMode.pve);
if (twoPlayer) gm.SetMode(GameMode.pvp);
if (onePlayer || twoPlayer)
{
ElapsedPromoTimer = 0;
gm.InitVictoryScales();
SoundManager.instance.playChoose();
subState = MenuSubStates.Payment;
return true;
}
return false;
}
private void Payment()
private bool HandlePromo()
{
int creditsPrice = gm.gameMode == GameMode.pve ? PaymentSystem.PricePve : PaymentSystem.PricePvp;
if (PaymentSystem.TryPay(creditsPrice))
if (promoTimer.Update(!In.AnyButton()))
{
subState = MenuSubStates.ClosingMenu;
}
else
{
subState = MenuSubStates.Choosing;
TransitionTo(new PromoState(), playSound: false);
return true;
}
return false;
}
void CloseMenu()
private bool TrySelectGameMode(out GameMode mode)
{
mode = GameMode.pve;
if (In.GetButtonDown(ButtonPinMapping.startOnePlayer))
mode = GameMode.pve;
else if (In.GetButtonDown(ButtonPinMapping.startTwoPlayers))
mode = GameMode.pvp;
else
return false;
return true;
}
private bool TryStartGame(GameMode mode)
{
if (!PaymentSystem.TryPayForMode(mode)) return false;
gm.SetMode(mode);
gm.timerManager.SetTimersActivity(gm.gameMode);
ui.CloseMenu();
gm.InitVictoryScales();
gm.menuOpened = true;
animationEnded = false;
gm.StartCoroutine(closeMenuAnimation());
subState = MenuSubStates.SwitchState;
subState = MenuSubStates.WaitAnimation;
return true;
}
void OpenMenu()
private void WaitAnimation()
{
animationEnded = false;
gm.menuOpened = true;
if (ui.AnimationInProcess) return;
gm.StartCoroutine(openMenuAnimation());
CharacterController.ResetState();
TransitionTo(new StartRoundState(CellState.Player1));
subState = MenuSubStates.Choosing;
if (gm.gameMode == GameMode.pve)
gm.movesAndTimeCounter.SetVisibility(true);
}
void SwitchState()
private void TransitionTo(IState state, bool playSound = true)
{
if (animationEnded)
{
if (subState == MenuSubStates.OpeningMenu)
{
subState = MenuSubStates.Choosing;
return;
}
else
{//заход в игру
gm.menuOpened = false;
CharacterController.ResetState();
//при переходе из меню первым ходит игрок1
gm.stateMachine.ChangeState(new StartRoundState(CellState.Player1));
if (gm.gameMode == GameMode.pve) gm.movesAndTimeCounter.SetVisibility(true);
}
}
if (playSound) SoundManager.instance.playChoose();
gm.stateMachine.ChangeState(state);
}
IEnumerator closeMenuAnimation()
{
animationEnded = false;
float parametr;
//Мув кнопок, надписей, монетника
parametr = 0;
while (parametr < 1)
{
parametr += Time.deltaTime * 2;
label.localPosition = Vector3.Lerp(sLabel, eLabel, parametr);
buttonLeft.localPosition = Vector3.Lerp(new Vector3(-sButton.x, sButton.y, 0), new Vector3(-eButton.x, eButton.y, 0), parametr);
buttonRight.localPosition = Vector3.Lerp(sButton, eButton, parametr);
label2.localPosition = Vector3.Lerp(sLabel2, eLabel2, parametr);
noPrizeLabel.localPosition = Vector3.Lerp(sNoPrize, eNoPrize + Vector2.left * 3500, parametr);
coinPanel.localPosition = Vector3.Lerp(sCoin, eCoin, parametr);
SmallPrizesOut.sizeDelta = Vector2.Lerp(sSmallPrizesOutSize, eSmallPrizesOutSize, parametr);
yield return null;
}
buttonLeft.localPosition = -eButton;
buttonRight.localPosition = eButton;
//мув доски
parametr = 0;
while (parametr < 1)
{
parametr += Time.deltaTime * 2;
board.localPosition = Vector3.Lerp(sBoard, eBoard, parametr);
noPrizeLabel.localPosition = Vector3.Lerp(sNoPrize + Vector2.left * 3500, eNoPrize, parametr);
yield return null;
}
animationEnded = true;
}
IEnumerator openMenuAnimation()
{
animationEnded = false;
float parametr = 1;
while (parametr >= 0)
{
board.localPosition = Vector3.Lerp(sBoard, eBoard, parametr);
noPrizeLabel.localPosition = Vector3.Lerp(eNoPrize + Vector2.left * 3500, eNoPrize, parametr);
parametr -= Time.deltaTime * 2;
yield return null;
}
parametr = 1;
while (parametr >= 0)
{
parametr -= Time.deltaTime * 2;
label.localPosition = Vector3.Lerp(sLabel, eLabel, parametr);
buttonLeft.localPosition = Vector3.Lerp(-sButton + Vector2.up * sButton.y * 2, -eButton, parametr);
buttonRight.localPosition = Vector3.Lerp(sButton, eButton, parametr);
noPrizeLabel.localPosition = Vector3.Lerp(sNoPrize, eNoPrize + Vector2.left * 3500, parametr);
coinPanel.localPosition = Vector3.Lerp(sCoin, eCoin, parametr);
label2.localPosition = Vector3.Lerp(sLabel2, eLabel2, parametr);
SmallPrizesOut.sizeDelta = Vector2.Lerp(sSmallPrizesOutSize, eSmallPrizesOutSize, parametr);
yield return null;
}
animationEnded = true;
}
}
private enum MenuSubStates { InputPolling, WaitAnimation }
}

View File

@ -28,13 +28,13 @@ public class GameManager : MonoBehaviour
public RulesController rulesController;
[Header("Menu")]
public bool menuOpened = true;
public GameMode gameMode;
public Transform
coinPanel,
board,
noPrizeLabel;
public GameObject mainMenu;
public UiManager menuUi;
public TMP_FontAsset russo_font;
@ -417,8 +417,27 @@ public class GameManager : MonoBehaviour
}
}
}
public void ResetGameSession()
{
vsBotThinkTime = 0;
vsBotMoves = 0;
movesAndTimeCounter.SetVisibility(false);
CharacterController.HideCharacter();
CharacterController.I.SetAllCharactersPrizeAvailable(true);
DualAvatarController.Instance.HideCharacters();
DifficultyManager.Instance.ResetDifficulty();
player1score = 0;
player2score = 0;
vsBotScore = 0;
VitrinaView.Instance.Deactivate();
moveMade = false;
}
IEnumerator AddBotRecordEvery2Days()
{

View File

@ -44,6 +44,12 @@ public static class PaymentSystem
}
}
public static bool TryPayForMode(GameMode mode)
{
int price = mode == GameMode.pve ? PricePve : PricePvp;
return TryPay(price);
}
public static void AddCredit()
{
ChangeBalance(ValutaPerImpulse);

View File

@ -0,0 +1,19 @@
using UnityEngine;
public class HoldTimer
{
private float targetTime;
private float currentTime;
public HoldTimer(float target) => targetTime = target;
public bool Update(bool isHolding)
{
currentTime = isHolding
? Mathf.Min(currentTime + Time.deltaTime, targetTime)
: 0;
return currentTime >= targetTime;
}
public void Reset() => currentTime = 0;
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 4f3a022221194f94ba82020c740c82ba

View File

@ -1,28 +1,137 @@
using UnityEngine;
using System.Collections;
using UnityEngine;
public class UiManager : MonoBehaviour
{
private static UiManager _instance;
public static UiManager Instance
{
get
{
if (_instance == null)
{
_instance = FindAnyObjectByType<UiManager>();
if (_instance == null)
{
Debug.LogWarning($"Не найден {typeof(UiManager)}");
}
}
return _instance;
}
}
//Ссылки главно меню
public RectTransform UpperMenuGroup;
public RectTransform PveOption;
public RectTransform PvpOption;
public RectTransform DownMenuGroup;
[field: SerializeField] public bool AnimationInProcess { get; private set; } = false;
private GameManager gm => GameManager.instance;
private bool menuOpened = true;
#region начальные и конечные позиции для элементов меню
//s - startPosition, e - endPosition
Vector2
//надпись "ФИШКА"
sLabel = new Vector2(0, 320),
eLabel = new Vector2(0, 1000),
//Иконки режимов
sButton = new Vector2(400, -15),
eButton = new Vector2(2000, -15),
//подсказка + лого + техподдержка
sLabel2 = new Vector2(0, -380),
eLabel2 = new Vector2(0, -1000),
//ИГРОВОЕ ПОЛЕ
sBoard = new Vector2(-40, -0.5f),
eBoard = new Vector2(0, -0.5f),
sNoPrize = new Vector2(-0, -70f),
eNoPrize = new Vector2(15, -409);
Vector3
sCoin = new Vector3(0, -201.538483f, 0),
eCoin = new Vector3(-732.999939f, 372, 0);
Vector2 sSmallPrizesOutSize = new Vector2(560, 100);
Vector2 eSmallPrizesOutSize = new Vector2(660, 100);
#endregion
public void CloseMenu()
{
if (!menuOpened) return;
menuOpened = false;
AnimationInProcess = true;
StopAllCoroutines();
StartCoroutine(CloseMenuCoroutine());
}
private IEnumerator CloseMenuCoroutine()
{
float parametr;
//Мув кнопок, надписей, монетника
parametr = 0;
while (parametr < 1)
{
parametr += Time.deltaTime * 2;
UpperMenuGroup.localPosition = Vector3.Lerp(sLabel, eLabel, parametr);
PveOption.localPosition = Vector3.Lerp(new Vector3(-sButton.x, sButton.y, 0), new Vector3(-eButton.x, eButton.y, 0), parametr);
PvpOption.localPosition = Vector3.Lerp(sButton, eButton, parametr);
DownMenuGroup.localPosition = Vector3.Lerp(sLabel2, eLabel2, parametr);
gm.noPrizeLabel.localPosition = Vector3.Lerp(sNoPrize, eNoPrize + Vector2.left * 3500, parametr);
gm.coinPanel.localPosition = Vector3.Lerp(sCoin, eCoin, parametr);
gm.smallPrizesOut.sizeDelta = Vector2.Lerp(sSmallPrizesOutSize, eSmallPrizesOutSize, parametr);
yield return null;
}
PveOption.localPosition = -eButton;
PvpOption.localPosition = eButton;
//мув доски
parametr = 0;
while (parametr < 1)
{
parametr += Time.deltaTime * 2;
gm.board.localPosition = Vector3.Lerp(sBoard, eBoard, parametr);
gm.noPrizeLabel.localPosition = Vector3.Lerp(sNoPrize + Vector2.left * 3500, eNoPrize, parametr);
yield return null;
}
AnimationInProcess = false;
}
public void OpenMenu()
{
if(menuOpened) return;
menuOpened = true;
AnimationInProcess = true;
StopAllCoroutines();
StartCoroutine(OpenMenuCoroutine());
}
private IEnumerator OpenMenuCoroutine()
{
float parametr = 1;
while (parametr >= 0)
{
gm.board.localPosition = Vector3.Lerp(sBoard, eBoard, parametr);
gm.noPrizeLabel.localPosition = Vector3.Lerp(eNoPrize + Vector2.left * 3500, eNoPrize, parametr);
parametr -= Time.deltaTime * 2;
yield return null;
}
parametr = 1;
while (parametr >= 0)
{
parametr -= Time.deltaTime * 2;
UpperMenuGroup.localPosition = Vector3.Lerp(sLabel, eLabel, parametr);
PveOption.localPosition = Vector3.Lerp(-sButton + Vector2.up * sButton.y * 2, -eButton, parametr);
PvpOption.localPosition = Vector3.Lerp(sButton, eButton, parametr);
gm.noPrizeLabel.localPosition = Vector3.Lerp(sNoPrize, eNoPrize + Vector2.left * 3500, parametr);
gm.coinPanel.localPosition = Vector3.Lerp(sCoin, eCoin, parametr);
DownMenuGroup.localPosition = Vector3.Lerp(sLabel2, eLabel2, parametr);
gm.smallPrizesOut.sizeDelta = Vector2.Lerp(sSmallPrizesOutSize, eSmallPrizesOutSize, parametr);
yield return null;
}
AnimationInProcess = false;
}
}