Доработать PvP и ранний выход из игры
Реализовать матч PvP до пяти очков и рабочую панель победы. Исправить возврат подготовленной фишки и оплаты при раннем выходе. Ограничить перемещения фишки бота осмысленными кандидатами.
This commit is contained in:
parent
28fc3c87ae
commit
ebc47a80dd
@ -68,7 +68,10 @@ public class GameManager : MonoBehaviour
|
||||
public QrPanel qrPanel;
|
||||
public TakeOrRiskPanel takeOrRiskPanel;
|
||||
|
||||
private const int PvpWinningScore = 5;
|
||||
private bool _isLeavingGameplay;
|
||||
private int _paidEntryAmount;
|
||||
private bool _canRefundEntry;
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
@ -90,11 +93,18 @@ public class GameManager : MonoBehaviour
|
||||
|
||||
public void TryEnterGame(GameMode mode)
|
||||
{
|
||||
int entryPrice = PaymentSystem.GetModePrice(mode);
|
||||
if (!PaymentSystem.TryPayForMode(mode))
|
||||
return;
|
||||
|
||||
_paidEntryAmount = PaymentSystem.Freeplay ? 0 : entryPrice;
|
||||
_canRefundEntry = true;
|
||||
SetMode(mode);
|
||||
_isLeavingGameplay = false;
|
||||
|
||||
if (mode == GameMode.pvp)
|
||||
ResetPvpScores();
|
||||
|
||||
if (mode == GameMode.pve)
|
||||
CharactersController.I.ApplyFirstCharacterColorsToBoard();
|
||||
|
||||
@ -132,9 +142,11 @@ public class GameManager : MonoBehaviour
|
||||
if (_isLeavingGameplay)
|
||||
return;
|
||||
|
||||
RefundEntryIfAvailable();
|
||||
_isLeavingGameplay = true;
|
||||
ControlsPerformer.Instance.SetControlable(null);
|
||||
VideoUtility.CrossFadeToMenu();
|
||||
turnManager.CancelPlayerPreparation();
|
||||
_fieldCleaner.Clear();
|
||||
|
||||
if (gameMode == GameMode.pve)
|
||||
@ -157,7 +169,14 @@ public class GameManager : MonoBehaviour
|
||||
|
||||
public void SetMode(GameMode mode) => gameMode = mode;
|
||||
|
||||
public void DisableEarlyMenuExit() => _backToMenu.Hide();
|
||||
public void EnableEarlyMenuExit() => _backToMenu.EnableExit();
|
||||
|
||||
public void DisableEarlyMenuExit()
|
||||
{
|
||||
_paidEntryAmount = 0;
|
||||
_canRefundEntry = false;
|
||||
_backToMenu.Hide();
|
||||
}
|
||||
|
||||
public void PerformRevenge()
|
||||
=> ContinueAfterPveLoss();
|
||||
@ -193,6 +212,18 @@ public class GameManager : MonoBehaviour
|
||||
public void ContinueAfterPveDraw()
|
||||
=> StartPveRound(CharactersController.CharacterIndex);
|
||||
|
||||
public void ContinueAfterPvpRound()
|
||||
{
|
||||
_fieldCleaner.Clear();
|
||||
StartRound();
|
||||
}
|
||||
|
||||
public void RestartPvpMatch()
|
||||
{
|
||||
ResetPvpScores();
|
||||
ContinueAfterPvpRound();
|
||||
}
|
||||
|
||||
public void IncreaseScore(Team player)
|
||||
{
|
||||
if (player == Team.Player1)
|
||||
@ -201,6 +232,9 @@ public class GameManager : MonoBehaviour
|
||||
player2score += 1;
|
||||
}
|
||||
|
||||
public bool HasPvpMatchWinner(Team player)
|
||||
=> player == Team.Player1 ? player1score >= PvpWinningScore : player2score >= PvpWinningScore;
|
||||
|
||||
public void ProcessDifficultyCounter()//вызывается каждый раз, когда приходит COIN с платы или обновились настройки
|
||||
{
|
||||
string previous = PlayerPrefs.GetString("PreviousBaseBotDifficulty", "Прохождение");
|
||||
@ -247,7 +281,7 @@ public class GameManager : MonoBehaviour
|
||||
timerManager.SetActiveTimer(Team.Player1);
|
||||
}
|
||||
else if (gameMode == GameMode.pvp)
|
||||
DualAvatarController.Instance.ShowCharacters();
|
||||
DualAvatarController.Instance?.ShowCharacters();
|
||||
|
||||
VitrinaView.Instance.ActivateIfNeed();
|
||||
DetermineNextTurn(switchPlayer: false);
|
||||
@ -300,6 +334,22 @@ public class GameManager : MonoBehaviour
|
||||
OnRoundStarted?.Invoke();
|
||||
}
|
||||
|
||||
private void RefundEntryIfAvailable()
|
||||
{
|
||||
if (!_canRefundEntry)
|
||||
return;
|
||||
|
||||
PaymentSystem.ReturnCredits(_paidEntryAmount);
|
||||
_paidEntryAmount = 0;
|
||||
_canRefundEntry = false;
|
||||
}
|
||||
|
||||
private void ResetPvpScores()
|
||||
{
|
||||
player1score = 0;
|
||||
player2score = 0;
|
||||
}
|
||||
|
||||
|
||||
public void upgradeFeeshkaDifficulty()
|
||||
{
|
||||
|
||||
@ -9,6 +9,7 @@ public class BackToMenuController : MonoBehaviour
|
||||
private CanvasGroup _canvasGroup;
|
||||
private Tween _fadeTween;
|
||||
private bool _canExit;
|
||||
private bool _isWaitingForPreparedChip;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
@ -29,6 +30,7 @@ public class BackToMenuController : MonoBehaviour
|
||||
_fadeTween?.Kill();
|
||||
_fadeTween = null;
|
||||
_canExit = false;
|
||||
_isWaitingForPreparedChip = false;
|
||||
}
|
||||
|
||||
public void Show()
|
||||
@ -36,12 +38,23 @@ public class BackToMenuController : MonoBehaviour
|
||||
_fadeTween?.Kill();
|
||||
_fadeTween = null;
|
||||
_canvasGroup.alpha = 1f;
|
||||
_canExit = false;
|
||||
_isWaitingForPreparedChip = true;
|
||||
}
|
||||
|
||||
public void EnableExit()
|
||||
{
|
||||
if (!_isWaitingForPreparedChip)
|
||||
return;
|
||||
|
||||
_isWaitingForPreparedChip = false;
|
||||
_canExit = true;
|
||||
}
|
||||
|
||||
public void Hide()
|
||||
{
|
||||
_canExit = false;
|
||||
_isWaitingForPreparedChip = false;
|
||||
_fadeTween?.Kill();
|
||||
_fadeTween = _canvasGroup
|
||||
.DOFade(0f, _fadeDuration)
|
||||
|
||||
@ -12,6 +12,7 @@ public class Bot : BasePlayer, IGamePlayer
|
||||
[SerializeField] private DifficultyPreset difficultyPreset;
|
||||
[SerializeField] private bool useDummyBots = false;
|
||||
[SerializeField] private float minThinkingTime = 1f;
|
||||
[SerializeField, Min(0f)] private float _candidatePauseDuration = 0.35f;
|
||||
|
||||
public DifficultyPreset dummyPreset;
|
||||
|
||||
@ -34,9 +35,10 @@ public class Bot : BasePlayer, IGamePlayer
|
||||
private DifficultyPreset _activeDifficultyPreset;
|
||||
private bool _useStrongSolver;
|
||||
|
||||
// Random movement
|
||||
private float randomMoveTimer;
|
||||
private float randomMoveInterval = 0.3f;
|
||||
private int[] _thinkingCandidates;
|
||||
private int _thinkingCandidateIndex;
|
||||
private float _candidatePauseUntil;
|
||||
private bool _isVisitingCandidates;
|
||||
|
||||
private int droppedRow, droppedColumn;
|
||||
|
||||
@ -94,31 +96,35 @@ public class Bot : BasePlayer, IGamePlayer
|
||||
|
||||
private void UpdateThinking()
|
||||
{
|
||||
// Случайные движения (инициируют переход в Moving)
|
||||
TryRandomMovement();
|
||||
if (!isThinkingComplete)
|
||||
return;
|
||||
|
||||
// Проверяем, завершены ли вычисления и прошло ли минимальное время
|
||||
if (isThinkingComplete && Time.time - thinkingStartTime >= _requiredThinkingTime)
|
||||
if (!_isVisitingCandidates)
|
||||
{
|
||||
MoveToCalculatedColumn();
|
||||
StartCandidateVisit();
|
||||
return;
|
||||
}
|
||||
|
||||
if (Time.time < _candidatePauseUntil)
|
||||
return;
|
||||
|
||||
if (_thinkingCandidateIndex < _thinkingCandidates.Length - 1)
|
||||
{
|
||||
_thinkingCandidateIndex++;
|
||||
MoveToCandidate(_thinkingCandidates[_thinkingCandidateIndex]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Time.time - thinkingStartTime >= _requiredThinkingTime)
|
||||
PerformDrop();
|
||||
}
|
||||
|
||||
private void UpdateMoving()
|
||||
{
|
||||
// Плавное горизонтальное движение к целевой позиции (Y сохраняется)
|
||||
if (currentChip.MoveToLinear(stickedTargetPosition, moveSpeed))
|
||||
{
|
||||
// Если условия для дропа выполнены - бросаем
|
||||
if (isThinkingComplete && Time.time - thinkingStartTime >= _requiredThinkingTime)
|
||||
{
|
||||
PerformDrop();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Иначе возвращаемся в режим раздумий
|
||||
SetState(PlayerState.Thinking);
|
||||
}
|
||||
SetState(PlayerState.Thinking);
|
||||
_candidatePauseUntil = Time.time + _candidatePauseDuration;
|
||||
}
|
||||
}
|
||||
|
||||
@ -137,7 +143,10 @@ public class Bot : BasePlayer, IGamePlayer
|
||||
isThinkingComplete = false;
|
||||
calculatedColumn = -1;
|
||||
thinkingStartTime = Time.time;
|
||||
randomMoveTimer = 0f;
|
||||
_thinkingCandidates = null;
|
||||
_thinkingCandidateIndex = 0;
|
||||
_candidatePauseUntil = 0f;
|
||||
_isVisitingCandidates = false;
|
||||
CacheDifficulty();
|
||||
|
||||
StopThinking();
|
||||
@ -174,21 +183,26 @@ public class Bot : BasePlayer, IGamePlayer
|
||||
}
|
||||
}
|
||||
|
||||
private void MoveToCalculatedColumn()
|
||||
private void StartCandidateVisit()
|
||||
{
|
||||
if (calculatedColumn == -1) return;
|
||||
_thinkingCandidates = BuildThinkingCandidates();
|
||||
_thinkingCandidateIndex = 0;
|
||||
_isVisitingCandidates = true;
|
||||
MoveToCandidate(_thinkingCandidates[_thinkingCandidateIndex]);
|
||||
}
|
||||
|
||||
int targetIndex = System.Array.IndexOf(availableColumns, calculatedColumn);
|
||||
private void MoveToCandidate(int column)
|
||||
{
|
||||
int targetIndex = System.Array.IndexOf(availableColumns, column);
|
||||
if (targetIndex == -1)
|
||||
{
|
||||
Debug.LogWarning($"Column {calculatedColumn} is not available!");
|
||||
Debug.LogWarning($"Column {column} is not available!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (selectedColumnIndex == targetIndex)
|
||||
{
|
||||
|
||||
PerformDrop();
|
||||
_candidatePauseUntil = Time.time + _candidatePauseDuration;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -197,6 +211,82 @@ public class Bot : BasePlayer, IGamePlayer
|
||||
SetState(PlayerState.Moving);
|
||||
}
|
||||
|
||||
private int[] BuildThinkingCandidates()
|
||||
{
|
||||
int alternativeColumn = FindAlternativeCandidate(calculatedColumn);
|
||||
return alternativeColumn >= 0
|
||||
? new[] { alternativeColumn, calculatedColumn }
|
||||
: new[] { calculatedColumn };
|
||||
}
|
||||
|
||||
private int FindAlternativeCandidate(int finalColumn)
|
||||
{
|
||||
Team[,] grid = board.GridToTeam();
|
||||
Team opponent = team == Team.Player1 ? Team.Player2 : Team.Player1;
|
||||
int bestColumn = -1;
|
||||
float bestScore = float.NegativeInfinity;
|
||||
float boardCenter = (board.Columns - 1) * 0.5f;
|
||||
|
||||
foreach (int column in availableColumns)
|
||||
{
|
||||
if (column == finalColumn)
|
||||
continue;
|
||||
|
||||
int row = board.GetLowestEmptyRow(column);
|
||||
int attackScore = EvaluatePlacement(grid, row, column, team);
|
||||
int blockScore = EvaluatePlacement(grid, row, column, opponent);
|
||||
float centerPenalty = Mathf.Abs(column - boardCenter);
|
||||
float score = attackScore * 2f + blockScore * 1.5f - centerPenalty;
|
||||
|
||||
if (score > bestScore)
|
||||
{
|
||||
bestScore = score;
|
||||
bestColumn = column;
|
||||
}
|
||||
}
|
||||
|
||||
return bestColumn;
|
||||
}
|
||||
|
||||
private int EvaluatePlacement(Team[,] grid, int row, int column, Team evaluatedTeam)
|
||||
{
|
||||
grid[row, column] = evaluatedTeam;
|
||||
|
||||
int longestLine = Mathf.Max(
|
||||
GetLineLength(grid, row, column, evaluatedTeam, 1, 0),
|
||||
GetLineLength(grid, row, column, evaluatedTeam, 0, 1),
|
||||
GetLineLength(grid, row, column, evaluatedTeam, 1, 1),
|
||||
GetLineLength(grid, row, column, evaluatedTeam, 1, -1));
|
||||
|
||||
grid[row, column] = Team.None;
|
||||
return longestLine >= 4 ? 100 + longestLine : longestLine * longestLine;
|
||||
}
|
||||
|
||||
private int GetLineLength(Team[,] grid, int row, int column, Team evaluatedTeam, int rowStep, int columnStep)
|
||||
{
|
||||
return 1
|
||||
+ CountDirection(grid, row, column, evaluatedTeam, rowStep, columnStep)
|
||||
+ CountDirection(grid, row, column, evaluatedTeam, -rowStep, -columnStep);
|
||||
}
|
||||
|
||||
private int CountDirection(Team[,] grid, int row, int column, Team evaluatedTeam, int rowStep, int columnStep)
|
||||
{
|
||||
int count = 0;
|
||||
int currentRow = row + rowStep;
|
||||
int currentColumn = column + columnStep;
|
||||
|
||||
while (currentRow >= 0 && currentRow < grid.GetLength(0) &&
|
||||
currentColumn >= 0 && currentColumn < grid.GetLength(1) &&
|
||||
grid[currentRow, currentColumn] == evaluatedTeam)
|
||||
{
|
||||
count++;
|
||||
currentRow += rowStep;
|
||||
currentColumn += columnStep;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
private void PerformDrop()
|
||||
{
|
||||
dropTargetPosition = board.GetTargetPosition(SelectedColumn);
|
||||
@ -208,27 +298,6 @@ public class Bot : BasePlayer, IGamePlayer
|
||||
SetState(PlayerState.Dropping);
|
||||
}
|
||||
|
||||
private void TryRandomMovement()
|
||||
{
|
||||
if (availableColumns == null || availableColumns.Length <= 1) return;
|
||||
|
||||
randomMoveTimer += Time.deltaTime;
|
||||
if (randomMoveTimer >= randomMoveInterval)
|
||||
{
|
||||
randomMoveTimer = 0f;
|
||||
int direction = Random.Range(0, 2) * 2 - 1;
|
||||
int newIndex = Mathf.Clamp(selectedColumnIndex + direction, 0, availableColumns.Length - 1);
|
||||
|
||||
if (newIndex != selectedColumnIndex)
|
||||
{
|
||||
selectedColumnIndex = newIndex;
|
||||
// Сохраняем текущий Y, меняем только X
|
||||
UpdateTargetPositionX(board.GetStickedPosition(SelectedColumn).x);
|
||||
SetState(PlayerState.Moving);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void CacheAvailableColumns()
|
||||
{
|
||||
availableColumns = board.GetNonFullColumns();
|
||||
@ -276,6 +345,7 @@ public class Bot : BasePlayer, IGamePlayer
|
||||
{
|
||||
// Начальная позиция – сверху с оффсетом
|
||||
stickedTargetPosition = board.GetMiddleStickedPosition();
|
||||
stickedTargetPosition.x = board.GetStickedPosition(SelectedColumn).x;
|
||||
currentChip.transform.position = stickedTargetPosition + Vector2.up * 5f;
|
||||
}
|
||||
|
||||
|
||||
@ -30,7 +30,13 @@ public class EndGameHandler : MonoBehaviour
|
||||
}
|
||||
else
|
||||
{
|
||||
_pvpWinPanel.Open();
|
||||
GameManager gameManager = GameManager.Instance;
|
||||
_pvpWinPanel.Open(
|
||||
Team.None,
|
||||
false,
|
||||
gameManager.player1score,
|
||||
gameManager.player2score,
|
||||
gameManager.ContinueAfterPvpRound);
|
||||
}
|
||||
}
|
||||
|
||||
@ -54,7 +60,15 @@ public class EndGameHandler : MonoBehaviour
|
||||
}
|
||||
else
|
||||
{
|
||||
_pvpWinPanel.Open();
|
||||
GameManager gameManager = GameManager.Instance;
|
||||
gameManager.IncreaseScore(winner);
|
||||
bool isMatchWin = gameManager.HasPvpMatchWinner(winner);
|
||||
_pvpWinPanel.Open(
|
||||
winner,
|
||||
isMatchWin,
|
||||
gameManager.player1score,
|
||||
gameManager.player2score,
|
||||
isMatchWin ? gameManager.RestartPvpMatch : gameManager.ContinueAfterPvpRound);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,156 +1,159 @@
|
||||
using DG.Tweening;
|
||||
using DG.Tweening;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Serialization;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public class PvpWinPanel : MonoBehaviour, IControlable
|
||||
{
|
||||
[SerializeField] private RectTransform panel;
|
||||
[SerializeField] private float startPanelX, shownPanelX, hiddenPanelX;
|
||||
[SerializeField] private Transform description;
|
||||
[SerializeField] private RevengeButton revengeButton;
|
||||
[SerializeField] private GotoMenuButton menuButton;
|
||||
[SerializeField] private Image background;
|
||||
[SerializeField] private Color backgroundEnabledColor, backgroundDisabledColor;
|
||||
[SerializeField, FormerlySerializedAs("panel")] private RectTransform _panel;
|
||||
[SerializeField, FormerlySerializedAs("startPanelX")] private float _startPanelX;
|
||||
[SerializeField, FormerlySerializedAs("shownPanelX")] private float _shownPanelX;
|
||||
[SerializeField, FormerlySerializedAs("hiddenPanelX")] private float _hiddenPanelX;
|
||||
[SerializeField, FormerlySerializedAs("description")] private Transform _description;
|
||||
[SerializeField, FormerlySerializedAs("revengeButton")] private RevengeButton _restartButton;
|
||||
[SerializeField, FormerlySerializedAs("menuButton")] private GotoMenuButton _menuButton;
|
||||
[SerializeField, FormerlySerializedAs("background")] private Image _background;
|
||||
[SerializeField, FormerlySerializedAs("backgroundEnabledColor")] private Color _backgroundEnabledColor;
|
||||
[SerializeField, FormerlySerializedAs("backgroundDisabledColor")] private Color _backgroundDisabledColor;
|
||||
[SerializeField, FormerlySerializedAs("elasticCurve")] private AnimationCurve _elasticCurve;
|
||||
[SerializeField, FormerlySerializedAs("buttons")] private List<PveLossButton> _buttons;
|
||||
|
||||
[SerializeField] private AnimationCurve elasticCurve;
|
||||
private Sequence _animation;
|
||||
|
||||
[Header("Работа с кнопками")]
|
||||
[SerializeField] private List<PveLossButton> buttons;
|
||||
private int buttonIndex;
|
||||
private int _buttonIndex;
|
||||
private Action _restartAction;
|
||||
|
||||
public bool ControlsEnabled { get; set; }
|
||||
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
_animation?.Kill();
|
||||
_animation = null;
|
||||
_restartAction = null;
|
||||
ControlsEnabled = false;
|
||||
}
|
||||
|
||||
public void UpdateControls()
|
||||
{
|
||||
int direction = In.GetAxis(JoystickSide.Both, InteractMode.Discrete).x;
|
||||
int newButtonIndex = Mathf.Clamp(_buttonIndex + direction, 0, _buttons.Count - 1);
|
||||
|
||||
int newButtonIndex = Mathf.Clamp(buttonIndex + direction, 0, buttons.Count);
|
||||
bool indexChanged = newButtonIndex != buttonIndex;
|
||||
if (indexChanged)
|
||||
if (newButtonIndex != _buttonIndex)
|
||||
{
|
||||
buttonIndex = newButtonIndex;
|
||||
_buttonIndex = newButtonIndex;
|
||||
RefreshButtons();
|
||||
}
|
||||
|
||||
//interact
|
||||
if (In.GetAction(JoystickSide.Both, InteractMode.Discrete))
|
||||
{
|
||||
var selectedButton = buttons[buttonIndex];
|
||||
selectedButton.Interact();
|
||||
}
|
||||
Close();
|
||||
}
|
||||
|
||||
public void Open()
|
||||
public void Open(Team winner, bool isMatchWin, int player1Score, int player2Score, Action restartAction)
|
||||
{
|
||||
if (_animation != null)
|
||||
{
|
||||
_animation.Kill();
|
||||
}
|
||||
_animation?.Kill();
|
||||
_restartAction = restartAction;
|
||||
Initialize(winner, isMatchWin, player1Score, player2Score);
|
||||
|
||||
Initialize();
|
||||
_animation = GetOpenSequence();
|
||||
_animation.onComplete += () =>
|
||||
_animation.OnComplete(() =>
|
||||
{
|
||||
ControlsEnabled = true;
|
||||
RefreshButtons();
|
||||
};
|
||||
});
|
||||
_animation.PlayForward();
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
if (_animation != null)
|
||||
{
|
||||
_animation.Kill();
|
||||
}
|
||||
ControlsEnabled = false;
|
||||
ControlsPerformer.Instance.SetControlable(null);
|
||||
|
||||
int selectedButtonIndex = _buttonIndex;
|
||||
_animation?.Kill();
|
||||
_animation = GetCloseSequence();
|
||||
_animation.onComplete += () =>
|
||||
{
|
||||
ControlsEnabled = false;
|
||||
revengeButton.Select();
|
||||
menuButton.Deselect();
|
||||
};
|
||||
_animation.OnComplete(() => CompleteClose(selectedButtonIndex));
|
||||
_animation.PlayForward();
|
||||
}
|
||||
|
||||
private Sequence GetCloseSequence()
|
||||
private void Initialize(Team winner, bool isMatchWin, int player1Score, int player2Score)
|
||||
{
|
||||
Sequence seq = DOTween.Sequence();
|
||||
ControlsEnabled = false;
|
||||
gameObject.SetActive(true);
|
||||
ControlsPerformer.Instance.SetControlable(this);
|
||||
|
||||
foreach (var button in buttons)
|
||||
{
|
||||
seq.Join(button.transform.DOScale(0, 0.4f).SetEase(Ease.InBack));
|
||||
}
|
||||
_panel.anchoredPosition = new Vector2(_startPanelX, _panel.anchoredPosition.y);
|
||||
_description.localScale = Vector3.zero;
|
||||
_description.localRotation = Quaternion.identity;
|
||||
_description.GetComponent<TextMeshProUGUI>().text = GetDescription(winner, isMatchWin, player1Score, player2Score);
|
||||
|
||||
seq.Append(panel.DOAnchorPosX(hiddenPanelX, 1f).SetEase(Ease.InBack));
|
||||
seq.Join(background.DOColor(backgroundDisabledColor, 2).SetEase(Ease.InCubic));
|
||||
|
||||
return seq;
|
||||
}
|
||||
|
||||
private void Initialize()
|
||||
{
|
||||
panel.anchoredPosition = new Vector2(startPanelX, panel.anchoredPosition.y);
|
||||
description.localScale = Vector3.zero;
|
||||
|
||||
var text = description.GetComponent<TextMeshProUGUI>();
|
||||
int winner = GameManager.Instance.currentPlayer == Team.Player1 ? 1 : 2;
|
||||
text.text = $"игрок {winner} победил";
|
||||
|
||||
revengeButton.Initialize();
|
||||
|
||||
revengeButton.transform.localScale = Vector3.zero;
|
||||
menuButton.transform.localScale = Vector3.zero;
|
||||
|
||||
background.color = backgroundDisabledColor;
|
||||
|
||||
buttonIndex = 0;
|
||||
_restartButton.InitializeForFreeRestart();
|
||||
_restartButton.transform.localScale = Vector3.zero;
|
||||
_menuButton.transform.localScale = Vector3.zero;
|
||||
_background.color = _backgroundDisabledColor;
|
||||
_buttonIndex = 0;
|
||||
}
|
||||
|
||||
private Sequence GetOpenSequence()
|
||||
{
|
||||
Sequence seq = DOTween.Sequence();
|
||||
Sequence sequence = DOTween.Sequence();
|
||||
sequence.Append(_panel.DOAnchorPosX(_shownPanelX, 1f).SetEase(Ease.OutBack));
|
||||
sequence.Join(_background.DOColor(_backgroundEnabledColor, 1f).SetEase(Ease.OutCubic));
|
||||
sequence.Append(_description.DOScale(1f, 0.5f).SetEase(_elasticCurve));
|
||||
sequence.AppendInterval(0.2f);
|
||||
sequence.Append(_description.DOLocalRotate(new Vector3(0f, 0f, 2f), 0.2f));
|
||||
sequence.Append(_description.DOLocalRotate(new Vector3(0f, 0f, -2f), 0.2f));
|
||||
sequence.Append(_description.DOLocalRotate(Vector3.zero, 0.1f));
|
||||
sequence.Join(_restartButton.transform.DOScale(1.05f, 0.5f).SetEase(Ease.OutBack));
|
||||
sequence.Append(_menuButton.transform.DOScale(0.9f, 0.5f).SetEase(Ease.OutBack));
|
||||
return sequence;
|
||||
}
|
||||
|
||||
//приезд панели
|
||||
seq.Append(panel.DOAnchorPosX(shownPanelX, 1f).SetEase(Ease.OutBack));
|
||||
private Sequence GetCloseSequence()
|
||||
{
|
||||
Sequence sequence = DOTween.Sequence();
|
||||
|
||||
//фон
|
||||
seq.Join(background.DOColor(backgroundEnabledColor, 1).SetEase(Ease.OutCubic));
|
||||
foreach (PveLossButton button in _buttons)
|
||||
sequence.Join(button.transform.DOScale(0f, 0.4f).SetEase(Ease.InBack));
|
||||
|
||||
//текст описания
|
||||
seq.Append(description.DOScale(1, 0.5f).SetEase(elasticCurve));
|
||||
seq.AppendInterval(0.2f);
|
||||
sequence.Append(_panel.DOAnchorPosX(_hiddenPanelX, 1f).SetEase(Ease.InBack));
|
||||
sequence.Join(_background.DOColor(_backgroundDisabledColor, 2f).SetEase(Ease.InCubic));
|
||||
return sequence;
|
||||
}
|
||||
|
||||
//вращение описания
|
||||
float rotationDuration = 0.2f;
|
||||
seq.Append(description.DOLocalRotate(new Vector3(0, 0, 2), rotationDuration));
|
||||
seq.Append(description.DOLocalRotate(new Vector3(0, 0, -2), rotationDuration));
|
||||
seq.Append(description.DOLocalRotate(new Vector3(0, 0, 0), rotationDuration / 2));
|
||||
private void CompleteClose(int selectedButtonIndex)
|
||||
{
|
||||
ControlsEnabled = false;
|
||||
Action restartAction = _restartAction;
|
||||
_restartAction = null;
|
||||
gameObject.SetActive(false);
|
||||
|
||||
//появление кнопок
|
||||
seq.Join(revengeButton.transform.DOScale(1.05f, 0.5f).SetEase(Ease.OutBack));
|
||||
seq.Append(menuButton.transform.DOScale(0.9f, 0.5f).SetEase(Ease.OutBack));
|
||||
|
||||
return seq;
|
||||
if (selectedButtonIndex == 0)
|
||||
restartAction?.Invoke();
|
||||
else
|
||||
GameManager.Instance.GotoMenu();
|
||||
}
|
||||
|
||||
private void RefreshButtons()
|
||||
{
|
||||
if (buttonIndex == 0)
|
||||
for (int index = 0; index < _buttons.Count; index++)
|
||||
{
|
||||
buttons[0].Select();
|
||||
buttons[1].Deselect();
|
||||
}
|
||||
else if (buttonIndex == 1)
|
||||
{
|
||||
buttons[1].Select();
|
||||
buttons[0].Deselect();
|
||||
if (index == _buttonIndex)
|
||||
_buttons[index].Select();
|
||||
else
|
||||
_buttons[index].Deselect();
|
||||
}
|
||||
}
|
||||
|
||||
private string GetDescription(Team winner, bool isMatchWin, int player1Score, int player2Score)
|
||||
{
|
||||
if (winner == Team.None)
|
||||
return $"ничья · счёт {player1Score}:{player2Score}";
|
||||
|
||||
int playerNumber = winner == Team.Player1 ? 1 : 2;
|
||||
return isMatchWin
|
||||
? $"поздравляем! игрок {playerNumber} победил {player1Score}:{player2Score}"
|
||||
: $"игрок {playerNumber} победил · счёт {player1Score}:{player2Score}";
|
||||
}
|
||||
}
|
||||
|
||||
@ -33,6 +33,13 @@ public class RevengeButton : PveLossButton
|
||||
saleImage.gameObject.SetActive(revengeCheaper);
|
||||
}
|
||||
|
||||
public void InitializeForFreeRestart()
|
||||
{
|
||||
oldPrice.gameObject.SetActive(false);
|
||||
actualPrice.gameObject.SetActive(false);
|
||||
saleImage.gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
public override void Interact()
|
||||
{
|
||||
if (!interactable) return;
|
||||
|
||||
@ -46,6 +46,17 @@ public class Player : BasePlayer, IGamePlayer
|
||||
availableColumns = null;
|
||||
}
|
||||
|
||||
public void ReturnPreparedChipToPool()
|
||||
{
|
||||
if (currentChip == null || state == PlayerState.Sleep || state == PlayerState.Dropping)
|
||||
return;
|
||||
|
||||
ChipPool.Instance.Release(currentChip);
|
||||
currentChip = null;
|
||||
availableColumns = null;
|
||||
SetState(PlayerState.Sleep);
|
||||
}
|
||||
|
||||
public void UpdateControls()
|
||||
{
|
||||
// Always update state machine regardless of ControlsEnabled
|
||||
@ -176,6 +187,7 @@ public class Player : BasePlayer, IGamePlayer
|
||||
private void SetInitialChipPosition()
|
||||
{
|
||||
stickedTargetPosition = board.GetMiddleStickedPosition();
|
||||
stickedTargetPosition.x = board.GetStickedPosition(SelectedColumn).x;
|
||||
currentChip.transform.position = stickedTargetPosition + Vector2.up * chipYOffset;
|
||||
}
|
||||
|
||||
|
||||
@ -24,6 +24,14 @@ public class TurnManager : MonoBehaviour
|
||||
StartTurn(_currentPlayer);
|
||||
}
|
||||
|
||||
public void CancelPlayerPreparation()
|
||||
{
|
||||
_player1.OnMoveCommitted -= OnPlayerMoveCommitted;
|
||||
_player1.OnThinkingStarted -= OnPlayerThinkingStarted;
|
||||
_player1.OnChipDropped -= OnTurnCompleted;
|
||||
_player1.ReturnPreparedChipToPool();
|
||||
}
|
||||
|
||||
private void SetupPlayers()
|
||||
=> _currentPlayer = _player1;
|
||||
|
||||
@ -38,17 +46,14 @@ public class TurnManager : MonoBehaviour
|
||||
{
|
||||
_player1.OnMoveCommitted -= OnPlayerMoveCommitted;
|
||||
_player1.OnMoveCommitted += OnPlayerMoveCommitted;
|
||||
|
||||
_player1.OnThinkingStarted -= OnPlayerThinkingStarted;
|
||||
_player1.OnThinkingStarted += OnPlayerThinkingStarted;
|
||||
}
|
||||
|
||||
if (_gameMode == GameMode.pve)
|
||||
{
|
||||
GameManager.Instance.turnTracker.EnableTimer(false);
|
||||
|
||||
if (isPlayerOneTurn)
|
||||
{
|
||||
_player1.OnThinkingStarted -= OnPlayerThinkingStarted;
|
||||
_player1.OnThinkingStarted += OnPlayerThinkingStarted;
|
||||
}
|
||||
}
|
||||
|
||||
player.OnChipDropped -= OnTurnCompleted;
|
||||
@ -127,6 +132,9 @@ public class TurnManager : MonoBehaviour
|
||||
private void OnPlayerThinkingStarted()
|
||||
{
|
||||
_player1.OnThinkingStarted -= OnPlayerThinkingStarted;
|
||||
GameManager.Instance.turnTracker.EnableTimer(true);
|
||||
GameManager.Instance.EnableEarlyMenuExit();
|
||||
|
||||
if (_gameMode == GameMode.pve)
|
||||
GameManager.Instance.turnTracker.EnableTimer(true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -48,8 +48,7 @@ public static class PaymentSystem
|
||||
|
||||
public static bool TryPayForMode(GameMode mode)
|
||||
{
|
||||
int price = mode == GameMode.pve ? PricePve : PricePvp;
|
||||
return TryPay(price);
|
||||
return TryPay(GetModePrice(mode));
|
||||
}
|
||||
|
||||
public static void AddCredit()
|
||||
@ -69,9 +68,14 @@ public static class PaymentSystem
|
||||
public static void AddCreditNoCounters(int amount) => ChangeBalance(amount);
|
||||
|
||||
public static void ReturnCredits(GameMode gameMode)
|
||||
=> ReturnCredits(Freeplay ? 0 : GetModePrice(gameMode));
|
||||
|
||||
public static void ReturnCredits(int amount)
|
||||
{
|
||||
int gamemodePrice = gameMode == GameMode.pvp ? PricePvp : PricePve;
|
||||
ChangeBalance(gamemodePrice);
|
||||
if (amount <= 0)
|
||||
return;
|
||||
|
||||
ChangeBalance(amount);
|
||||
}
|
||||
|
||||
public static void ResetBalance()
|
||||
@ -82,6 +86,8 @@ public static class PaymentSystem
|
||||
|
||||
public static int GetRevengePrice(GameMode gameMode) => gameMode == GameMode.pve ? PriceRevengePve : PriceRevengePvP;
|
||||
|
||||
public static int GetModePrice(GameMode gameMode) => gameMode == GameMode.pve ? PricePve : PricePvp;
|
||||
|
||||
private static void ApplySettings()
|
||||
{
|
||||
Freeplay = SettingsManager.GetBool(SettingKey.FREEPLAY);
|
||||
@ -135,10 +141,9 @@ public static class PaymentSystem
|
||||
}
|
||||
else
|
||||
{
|
||||
int price = mode == GameMode.pve ? PricePve : PricePvp;
|
||||
return GetPluralizedMoney(price);
|
||||
return GetPluralizedMoney(GetModePrice(mode));
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetPluralizedMoney(int amount) => $"{amount} {PluralizeUtil.GetValutaPluralized(ValutaName, amount)}";
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user