[Fix] Rename Scripts Folder
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 648cba2aa826df04aa6de2236d532ff7
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,12 @@
|
||||
using Minesweeper.Core;
|
||||
|
||||
namespace Minesweeper.Presentation.Adapters
|
||||
{
|
||||
public sealed class GameStateViewAdapter : IGameStateViewAdapter
|
||||
{
|
||||
public string GetDisplayName(GameState state)
|
||||
{
|
||||
return state.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a10e635e4da16d24db457ead4d139896
|
||||
@@ -0,0 +1,9 @@
|
||||
using Minesweeper.Core;
|
||||
|
||||
namespace Minesweeper.Presentation.Adapters
|
||||
{
|
||||
public interface IGameStateViewAdapter
|
||||
{
|
||||
string GetDisplayName(GameState state);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 058bab5bc0f87f64dbbf668e5e390216
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ec6192ca6506ac64c8aa089466c86db5
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,52 @@
|
||||
using Minesweeper.Config;
|
||||
using Minesweeper.Core;
|
||||
using Minesweeper.Presentation.Views;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Minesweeper.Presentation.Factories
|
||||
{
|
||||
public sealed class CellViewFactory : ICellViewFactory
|
||||
{
|
||||
private readonly MinesweeperUiConfig uiConfig;
|
||||
|
||||
public CellViewFactory(MinesweeperUiConfig uiConfig)
|
||||
{
|
||||
this.uiConfig = uiConfig;
|
||||
}
|
||||
|
||||
public CellView CreateCell(BoardCellData cell, Transform parent)
|
||||
{
|
||||
var prefab = uiConfig.CellButtonPrefab;
|
||||
if (prefab == null)
|
||||
{
|
||||
Debug.LogError("CellViewFactory failed: CellButtonPrefab is not assigned.");
|
||||
return null;
|
||||
}
|
||||
|
||||
var go = Object.Instantiate(prefab, parent);
|
||||
go.name = BuildCellName(cell.X, cell.Y, cell.DisplayValue);
|
||||
|
||||
var view = go.GetComponent<CellView>();
|
||||
if (view == null)
|
||||
{
|
||||
Debug.LogError($"CellViewFactory failed: '{prefab.name}' is missing CellView.");
|
||||
Object.Destroy(go);
|
||||
return null;
|
||||
}
|
||||
|
||||
view.Initialize(cell.X, cell.Y);
|
||||
return view;
|
||||
}
|
||||
|
||||
public string BuildCellName(int x, int y, int value, bool isMine)
|
||||
{
|
||||
return $"bt_{x}_{y}_{(isMine ? "M" : value.ToString())}";
|
||||
}
|
||||
|
||||
public string BuildCellName(int x, int y, string displayValue)
|
||||
{
|
||||
return $"bt_{x}_{y}_{displayValue}";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 681a16a970ddf3546bb4f99d93a184ca
|
||||
@@ -0,0 +1,13 @@
|
||||
using Minesweeper.Core;
|
||||
using Minesweeper.Presentation.Views;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Minesweeper.Presentation.Factories
|
||||
{
|
||||
public interface ICellViewFactory
|
||||
{
|
||||
CellView CreateCell(BoardCellData cell, Transform parent);
|
||||
string BuildCellName(int x, int y, int value, bool isMine);
|
||||
string BuildCellName(int x, int y, string displayValue);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 34c31a0f01c730440a2bcdac0f775dd8
|
||||
@@ -0,0 +1,102 @@
|
||||
using Minesweeper.Config;
|
||||
using Minesweeper.Presentation.Views;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Minesweeper.Presentation.Factories
|
||||
{
|
||||
public sealed class MinesweeperScreenBootstrapper
|
||||
{
|
||||
private const string MainMenuPanelName = "MainMenuPanel";
|
||||
private const string BoardGridName = "BoardGrid";
|
||||
private const string PausePanelName = "PausePanel";
|
||||
private const string ResultPanelName = "ResultPanel";
|
||||
|
||||
public MinesweeperScreenRefs Spawn(Transform contentRoot, MinesweeperScreenCatalog catalog)
|
||||
{
|
||||
if (contentRoot == null)
|
||||
{
|
||||
Debug.LogError("Minesweeper screen bootstrap failed: Content root is not assigned.");
|
||||
return default;
|
||||
}
|
||||
|
||||
if (catalog == null || !catalog.IsValid)
|
||||
{
|
||||
Debug.LogError("Minesweeper screen bootstrap failed: screen catalog prefab references are incomplete.");
|
||||
return default;
|
||||
}
|
||||
|
||||
ClearContent(contentRoot);
|
||||
|
||||
var mainMenu = SpawnScreen(catalog.MainMenuPanelPrefab, contentRoot, MainMenuPanelName, 0);
|
||||
var board = SpawnScreen(catalog.BoardGridPrefab, contentRoot, BoardGridName, 1);
|
||||
var pause = SpawnScreen(catalog.PausePanelPrefab, contentRoot, PausePanelName, 2);
|
||||
var result = SpawnScreen(catalog.ResultPanelPrefab, contentRoot, ResultPanelName, 3);
|
||||
|
||||
var mainMenuView = RequireComponent<MainMenuView>(mainMenu.transform, MainMenuPanelName);
|
||||
if (mainMenuView != null)
|
||||
{
|
||||
mainMenuView.BindRoot(mainMenu);
|
||||
}
|
||||
|
||||
var boardView = RequireComponent<BoardView>(board.transform, BoardGridName);
|
||||
var pauseView = RequireComponent<PauseView>(pause.transform, PausePanelName);
|
||||
var resultView = RequireComponent<ResultView>(result.transform, ResultPanelName);
|
||||
|
||||
var refs = new MinesweeperScreenRefs(
|
||||
mainMenuView,
|
||||
boardView,
|
||||
pauseView,
|
||||
resultView);
|
||||
|
||||
mainMenu.SetActive(false);
|
||||
board.SetActive(false);
|
||||
pause.SetActive(false);
|
||||
result.SetActive(false);
|
||||
|
||||
return refs;
|
||||
}
|
||||
|
||||
private static GameObject SpawnScreen(GameObject prefab, Transform parent, string expectedName, int siblingIndex)
|
||||
{
|
||||
var instance = Object.Instantiate(prefab, parent, false);
|
||||
instance.name = expectedName;
|
||||
instance.transform.SetSiblingIndex(siblingIndex);
|
||||
Stretch(instance.GetComponent<RectTransform>());
|
||||
return instance;
|
||||
}
|
||||
|
||||
private static void ClearContent(Transform contentRoot)
|
||||
{
|
||||
for (var i = contentRoot.childCount - 1; i >= 0; i--)
|
||||
{
|
||||
var child = contentRoot.GetChild(i);
|
||||
child.SetParent(null, false);
|
||||
Object.Destroy(child.gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
private static T RequireComponent<T>(Transform root, string ownerName) where T : Component
|
||||
{
|
||||
var component = root.GetComponent<T>();
|
||||
if (component == null)
|
||||
{
|
||||
Debug.LogError($"Minesweeper screen bootstrap failed: '{ownerName}' is missing {typeof(T).Name}.");
|
||||
}
|
||||
|
||||
return component;
|
||||
}
|
||||
|
||||
private static void Stretch(RectTransform rectTransform)
|
||||
{
|
||||
if (rectTransform == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
rectTransform.anchorMin = Vector2.zero;
|
||||
rectTransform.anchorMax = Vector2.one;
|
||||
rectTransform.offsetMin = Vector2.zero;
|
||||
rectTransform.offsetMax = Vector2.zero;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 38a228c86699cdb499351cf807842dfb
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3895ae14930e10841a7562a478c871ec
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,193 @@
|
||||
using Minesweeper.Commands;
|
||||
using Minesweeper.Core;
|
||||
using Minesweeper.Presentation.Factories;
|
||||
using Minesweeper.Presentation.ReadModels;
|
||||
using Minesweeper.Presentation.Views;
|
||||
|
||||
namespace Minesweeper.Presentation.Presenters
|
||||
{
|
||||
public sealed class GamePresenter : IPresenter
|
||||
{
|
||||
private readonly IGameCommandDispatcher commandDispatcher;
|
||||
private readonly ICellViewFactory cellViewFactory;
|
||||
private readonly IGamePauseService pauseService;
|
||||
private readonly IGameReadModel readModel;
|
||||
private readonly IGameStateService gameStateService;
|
||||
private readonly TopPanelPresenter topPanelPresenter;
|
||||
private readonly IBoardView boardView;
|
||||
private readonly IPauseView pauseView;
|
||||
private readonly IResultView resultView;
|
||||
private bool boardBuilt;
|
||||
|
||||
public GamePresenter(IGameCommandDispatcher commandDispatcher, ICellViewFactory cellViewFactory, IGamePauseService pauseService, IGameReadModel readModel, IGameStateService gameStateService, TopPanelPresenter topPanelPresenter, IBoardView boardView, IPauseView pauseView, IResultView resultView)
|
||||
{
|
||||
this.commandDispatcher = commandDispatcher;
|
||||
this.cellViewFactory = cellViewFactory;
|
||||
this.pauseService = pauseService;
|
||||
this.readModel = readModel;
|
||||
this.gameStateService = gameStateService;
|
||||
this.topPanelPresenter = topPanelPresenter;
|
||||
this.boardView = boardView;
|
||||
this.pauseView = pauseView;
|
||||
this.resultView = resultView;
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
boardView.CellPressStarted += OnCellPressStarted;
|
||||
boardView.CellPressEnded += OnCellPressEnded;
|
||||
boardView.PauseRequested += OnPauseRequested;
|
||||
boardView.CellOpenRequested += OnCellOpenRequested;
|
||||
boardView.CellFlagRequested += OnCellFlagRequested;
|
||||
pauseView.RestartRequested += OnRestartRequested;
|
||||
pauseView.ResumeRequested += OnResumeRequested;
|
||||
pauseView.GoToMenuRequested += OnGoToMenuRequested;
|
||||
resultView.RestartRequested += OnRestartRequested;
|
||||
resultView.GoToMenuRequested += OnGoToMenuRequested;
|
||||
gameStateService.StateChanged += OnStateChanged;
|
||||
pauseService.PauseChanged += OnPauseChanged;
|
||||
OnStateChanged(gameStateService.Current);
|
||||
OnPauseChanged(pauseService.IsPaused);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
boardView.CellPressStarted -= OnCellPressStarted;
|
||||
boardView.CellPressEnded -= OnCellPressEnded;
|
||||
boardView.PauseRequested -= OnPauseRequested;
|
||||
boardView.CellOpenRequested -= OnCellOpenRequested;
|
||||
boardView.CellFlagRequested -= OnCellFlagRequested;
|
||||
pauseView.RestartRequested -= OnRestartRequested;
|
||||
pauseView.ResumeRequested -= OnResumeRequested;
|
||||
pauseView.GoToMenuRequested -= OnGoToMenuRequested;
|
||||
resultView.RestartRequested -= OnRestartRequested;
|
||||
resultView.GoToMenuRequested -= OnGoToMenuRequested;
|
||||
gameStateService.StateChanged -= OnStateChanged;
|
||||
pauseService.PauseChanged -= OnPauseChanged;
|
||||
}
|
||||
|
||||
private void OnCellOpenRequested(int x, int y)
|
||||
{
|
||||
topPanelPresenter.SetCellPressActive(false);
|
||||
commandDispatcher.Dispatch(new OpenCellCommand(x, y));
|
||||
RefreshBoard();
|
||||
topPanelPresenter.RefreshCounters();
|
||||
UpdateBoardInput();
|
||||
}
|
||||
|
||||
private void OnCellFlagRequested(int x, int y)
|
||||
{
|
||||
commandDispatcher.Dispatch(new ToggleFlagCommand(x, y));
|
||||
RefreshBoard();
|
||||
topPanelPresenter.RefreshCounters();
|
||||
UpdateBoardInput();
|
||||
}
|
||||
|
||||
private void OnCellPressStarted()
|
||||
{
|
||||
topPanelPresenter.SetCellPressActive(true);
|
||||
}
|
||||
|
||||
private void OnCellPressEnded()
|
||||
{
|
||||
topPanelPresenter.SetCellPressActive(false);
|
||||
}
|
||||
|
||||
private void OnStateChanged(GameState state)
|
||||
{
|
||||
if (state == GameState.FieldSelection)
|
||||
{
|
||||
boardBuilt = false;
|
||||
boardView.Hide();
|
||||
pauseView.Hide();
|
||||
resultView.Hide();
|
||||
return;
|
||||
}
|
||||
|
||||
boardView.Show();
|
||||
|
||||
if (state == GameState.Won || state == GameState.Lost)
|
||||
{
|
||||
pauseView.Hide();
|
||||
resultView.Show(state);
|
||||
}
|
||||
else
|
||||
{
|
||||
resultView.Hide();
|
||||
}
|
||||
|
||||
if (!boardBuilt || state == GameState.Preparing)
|
||||
{
|
||||
RebuildBoard();
|
||||
}
|
||||
else
|
||||
{
|
||||
RefreshBoard();
|
||||
}
|
||||
|
||||
UpdateBoardInput();
|
||||
}
|
||||
|
||||
private void OnPauseChanged(bool isPaused)
|
||||
{
|
||||
if (isPaused && gameStateService.Current == GameState.Playing)
|
||||
{
|
||||
pauseView.Show();
|
||||
}
|
||||
else
|
||||
{
|
||||
pauseView.Hide();
|
||||
}
|
||||
|
||||
UpdateBoardInput();
|
||||
}
|
||||
|
||||
private void RebuildBoard()
|
||||
{
|
||||
var cells = readModel.GetCells();
|
||||
boardView.Rebuild(cells, readModel.Width, readModel.Height, cellViewFactory, IsFinalState());
|
||||
boardBuilt = true;
|
||||
topPanelPresenter.RefreshCounters();
|
||||
UpdateBoardInput();
|
||||
}
|
||||
|
||||
private void RefreshBoard()
|
||||
{
|
||||
boardView.Refresh(readModel.GetCells(), IsFinalState());
|
||||
}
|
||||
|
||||
private bool IsFinalState()
|
||||
{
|
||||
var state = gameStateService.Current;
|
||||
return state == GameState.Lost || state == GameState.Won;
|
||||
}
|
||||
|
||||
private void UpdateBoardInput()
|
||||
{
|
||||
var state = gameStateService.Current;
|
||||
boardView.SetInputEnabled(!pauseService.IsPaused && (state == GameState.Preparing || state == GameState.Playing));
|
||||
}
|
||||
|
||||
private void OnRestartRequested()
|
||||
{
|
||||
commandDispatcher.Dispatch(new RestartCommand());
|
||||
RebuildBoard();
|
||||
topPanelPresenter.RefreshCounters();
|
||||
}
|
||||
|
||||
private void OnGoToMenuRequested()
|
||||
{
|
||||
commandDispatcher.Dispatch(new GoToMenuCommand());
|
||||
}
|
||||
|
||||
private void OnResumeRequested()
|
||||
{
|
||||
commandDispatcher.Dispatch(new ResumeCommand());
|
||||
}
|
||||
|
||||
private void OnPauseRequested()
|
||||
{
|
||||
commandDispatcher.Dispatch(new PauseCommand());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9f85646fc4851054e9efffa3ab1f6853
|
||||
@@ -0,0 +1,9 @@
|
||||
using System;
|
||||
|
||||
namespace Minesweeper.Presentation.Presenters
|
||||
{
|
||||
public interface IPresenter : IDisposable
|
||||
{
|
||||
void Initialize();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e0fcee9aa500b62429eb4ffa2249de9c
|
||||
@@ -0,0 +1,81 @@
|
||||
using Minesweeper.Commands;
|
||||
using Minesweeper.Config;
|
||||
using Minesweeper.Core;
|
||||
using Minesweeper.Presentation.Views;
|
||||
|
||||
namespace Minesweeper.Presentation.Presenters
|
||||
{
|
||||
public sealed class MainMenuPresenter : IPresenter
|
||||
{
|
||||
private readonly IGameCommandDispatcher commandDispatcher;
|
||||
private readonly MinesweeperGameConfig config;
|
||||
private readonly IGameSettingsService settingsService;
|
||||
private readonly IGameStateService gameStateService;
|
||||
private readonly IMainMenuView view;
|
||||
|
||||
public MainMenuPresenter(IGameCommandDispatcher commandDispatcher, MinesweeperGameConfig config, IGameSettingsService settingsService, IGameStateService gameStateService, IMainMenuView view = null)
|
||||
{
|
||||
this.commandDispatcher = commandDispatcher;
|
||||
this.config = config;
|
||||
this.settingsService = settingsService;
|
||||
this.gameStateService = gameStateService;
|
||||
this.view = view;
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
if (view != null)
|
||||
{
|
||||
view.StartClicked += OnStartClicked;
|
||||
view.SizeChanged += OnSizeChanged;
|
||||
gameStateService.StateChanged += OnStateChanged;
|
||||
RefreshMenuValues(settingsService.Current);
|
||||
OnStateChanged(gameStateService.Current);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (view != null)
|
||||
{
|
||||
view.StartClicked -= OnStartClicked;
|
||||
view.SizeChanged -= OnSizeChanged;
|
||||
gameStateService.StateChanged -= OnStateChanged;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnStartClicked()
|
||||
{
|
||||
settingsService.ApplyAndSaveIfChanged(view.SelectedSettings);
|
||||
commandDispatcher.Dispatch(new StartGameCommand());
|
||||
}
|
||||
|
||||
private void OnSizeChanged()
|
||||
{
|
||||
var selected = settingsService.Clamp(view.SelectedSettings);
|
||||
var maxMines = settingsService.GetMaxMines(selected.SizeX, selected.SizeY);
|
||||
view.ConfigureMines(1, maxMines, selected.MinesCount);
|
||||
}
|
||||
|
||||
private void OnStateChanged(GameState state)
|
||||
{
|
||||
if (state == GameState.FieldSelection)
|
||||
{
|
||||
RefreshMenuValues(settingsService.Current);
|
||||
view.Show();
|
||||
}
|
||||
else
|
||||
{
|
||||
view.Hide();
|
||||
}
|
||||
}
|
||||
|
||||
private void RefreshMenuValues(GameSettingsValue settings)
|
||||
{
|
||||
var clamped = settingsService.Clamp(settings);
|
||||
view.ConfigureSizeX(config.MinSizeX, config.MaxSizeX, clamped.SizeX);
|
||||
view.ConfigureSizeY(config.MinSizeY, config.MaxSizeY, clamped.SizeY);
|
||||
view.ConfigureMines(1, settingsService.GetMaxMines(clamped.SizeX, clamped.SizeY), clamped.MinesCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 835a3b63609e9864fa6154be8b8283ad
|
||||
@@ -0,0 +1,130 @@
|
||||
using Minesweeper.Commands;
|
||||
using Minesweeper.Config;
|
||||
using Minesweeper.Core;
|
||||
using Minesweeper.Presentation.ReadModels;
|
||||
using Minesweeper.Presentation.Views;
|
||||
|
||||
namespace Minesweeper.Presentation.Presenters
|
||||
{
|
||||
public sealed class TopPanelPresenter : IPresenter
|
||||
{
|
||||
private readonly IGameCommandDispatcher commandDispatcher;
|
||||
private readonly IGamePauseService pauseService;
|
||||
private readonly IGameReadModel readModel;
|
||||
private readonly IGameStateService gameStateService;
|
||||
private readonly IGameTimerService timerService;
|
||||
private readonly ITopPanelView view;
|
||||
|
||||
public TopPanelPresenter(IGameCommandDispatcher commandDispatcher, IGamePauseService pauseService, IGameReadModel readModel, IGameStateService gameStateService, IGameTimerService timerService, ITopPanelView view)
|
||||
{
|
||||
this.commandDispatcher = commandDispatcher;
|
||||
this.pauseService = pauseService;
|
||||
this.readModel = readModel;
|
||||
this.gameStateService = gameStateService;
|
||||
this.timerService = timerService;
|
||||
this.view = view;
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
view.SmileClicked += OnSmileClicked;
|
||||
gameStateService.StateChanged += OnStateChanged;
|
||||
pauseService.PauseChanged += OnPauseChanged;
|
||||
timerService.TimeChanged += OnTimeChanged;
|
||||
|
||||
RefreshAll();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
view.SmileClicked -= OnSmileClicked;
|
||||
gameStateService.StateChanged -= OnStateChanged;
|
||||
pauseService.PauseChanged -= OnPauseChanged;
|
||||
timerService.TimeChanged -= OnTimeChanged;
|
||||
}
|
||||
|
||||
public void RefreshCounters()
|
||||
{
|
||||
view.SetRemainingMines(readModel.RemainingMinesCount);
|
||||
}
|
||||
|
||||
public void SetCellPressActive(bool active)
|
||||
{
|
||||
var state = gameStateService.Current;
|
||||
if (active && !pauseService.IsPaused && (state == GameState.Preparing || state == GameState.Playing))
|
||||
{
|
||||
view.SetSmile(SmileFaceState.Surprised);
|
||||
return;
|
||||
}
|
||||
|
||||
view.SetSmile(GetSmileState(state));
|
||||
}
|
||||
|
||||
private void RefreshAll()
|
||||
{
|
||||
view.SetActive(true);
|
||||
view.SetRemainingMines(readModel.RemainingMinesCount);
|
||||
view.SetTimer(timerService.ElapsedSeconds);
|
||||
view.SetSmile(GetSmileState(gameStateService.Current));
|
||||
}
|
||||
|
||||
private void OnSmileClicked()
|
||||
{
|
||||
var state = gameStateService.Current;
|
||||
if (state == GameState.FieldSelection)
|
||||
{
|
||||
commandDispatcher.Dispatch(new StartGameCommand());
|
||||
}
|
||||
else if (state == GameState.Playing && !pauseService.IsPaused)
|
||||
{
|
||||
commandDispatcher.Dispatch(new PauseCommand());
|
||||
}
|
||||
else if (state == GameState.Playing && pauseService.IsPaused)
|
||||
{
|
||||
commandDispatcher.Dispatch(new ResumeCommand());
|
||||
}
|
||||
else
|
||||
{
|
||||
commandDispatcher.Dispatch(new RestartCommand());
|
||||
}
|
||||
|
||||
RefreshAll();
|
||||
}
|
||||
|
||||
private void OnStateChanged(GameState state)
|
||||
{
|
||||
if (state == GameState.FieldSelection || state == GameState.Preparing)
|
||||
{
|
||||
view.SetTimer(0f);
|
||||
}
|
||||
|
||||
view.SetSmile(GetSmileState(state));
|
||||
view.SetRemainingMines(readModel.RemainingMinesCount);
|
||||
}
|
||||
|
||||
private void OnPauseChanged(bool isPaused)
|
||||
{
|
||||
view.SetSmile(GetSmileState(gameStateService.Current));
|
||||
}
|
||||
|
||||
private void OnTimeChanged(float seconds)
|
||||
{
|
||||
view.SetTimer(seconds);
|
||||
}
|
||||
|
||||
private SmileFaceState GetSmileState(GameState state)
|
||||
{
|
||||
if (state == GameState.Won)
|
||||
{
|
||||
return SmileFaceState.Cool;
|
||||
}
|
||||
|
||||
if (state == GameState.Lost)
|
||||
{
|
||||
return SmileFaceState.Dead;
|
||||
}
|
||||
|
||||
return SmileFaceState.Smile;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b3ac57cd2e63497d9d0d7e23659a4d45
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 590e96d08af41e346b49a7ce43641afb
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,51 @@
|
||||
using System.Collections.Generic;
|
||||
using Minesweeper.Core;
|
||||
|
||||
namespace Minesweeper.Presentation.ReadModels
|
||||
{
|
||||
public sealed class GameReadModel : IGameReadModel
|
||||
{
|
||||
private readonly IBoardService boardService;
|
||||
private readonly IGameSettingsService settingsService;
|
||||
private readonly IGameStateService gameStateService;
|
||||
|
||||
public GameReadModel(IBoardService boardService, IGameSettingsService settingsService, IGameStateService gameStateService)
|
||||
{
|
||||
this.boardService = boardService;
|
||||
this.settingsService = settingsService;
|
||||
this.gameStateService = gameStateService;
|
||||
}
|
||||
|
||||
public GameState State => gameStateService.Current;
|
||||
public int Width => boardService.Width > 0 ? boardService.Width : settingsService.SizeX;
|
||||
public int Height => boardService.Height > 0 ? boardService.Height : settingsService.SizeY;
|
||||
public int MinesCount => boardService.MinesCount > 0 ? boardService.MinesCount : settingsService.MinesCount;
|
||||
public int FlaggedCellsCount => CountFlaggedCells();
|
||||
public int RemainingMinesCount => MinesCount - FlaggedCellsCount;
|
||||
|
||||
public bool TryGetCell(int x, int y, out BoardCellData cell)
|
||||
{
|
||||
return boardService.TryGetCell(x, y, out cell);
|
||||
}
|
||||
|
||||
public IReadOnlyList<BoardCellData> GetCells()
|
||||
{
|
||||
return boardService.GetCells();
|
||||
}
|
||||
|
||||
private int CountFlaggedCells()
|
||||
{
|
||||
var cells = boardService.GetCells();
|
||||
var count = 0;
|
||||
for (var i = 0; i < cells.Count; i++)
|
||||
{
|
||||
if (cells[i].IsFlagged)
|
||||
{
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1b2a816449e034a4f9635960881ec852
|
||||
@@ -0,0 +1,18 @@
|
||||
using System.Collections.Generic;
|
||||
using Minesweeper.Core;
|
||||
|
||||
namespace Minesweeper.Presentation.ReadModels
|
||||
{
|
||||
public interface IGameReadModel
|
||||
{
|
||||
GameState State { get; }
|
||||
int Width { get; }
|
||||
int Height { get; }
|
||||
int MinesCount { get; }
|
||||
int FlaggedCellsCount { get; }
|
||||
int RemainingMinesCount { get; }
|
||||
|
||||
bool TryGetCell(int x, int y, out BoardCellData cell);
|
||||
IReadOnlyList<BoardCellData> GetCells();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e5c921f20dd6f1b40a1f73746265a63d
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0e2357d56da983b478c1cebe1e3ac363
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,297 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Minesweeper.Config;
|
||||
using Minesweeper.Core;
|
||||
using Minesweeper.Presentation.Factories;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace Minesweeper.Presentation.Views
|
||||
{
|
||||
public sealed class BoardView : MonoBehaviour, IBoardView
|
||||
{
|
||||
private const float ResizeRefreshDelaySeconds = 0.5f;
|
||||
private const float ResizeSizeEpsilon = 0.5f;
|
||||
private const float MaximumCellPixelsPerUnitMultiplier = 1f;
|
||||
private const float ContentPaddingReferenceCellSize = 202f;
|
||||
private const float ContentPaddingReferencePadding = 15f;
|
||||
private const float MinimumContentPadding = 1f;
|
||||
|
||||
[SerializeField] private GameObject root;
|
||||
[SerializeField] private RectTransform boardPanel;
|
||||
[SerializeField] private GridLayoutGroup gridLayoutGroup;
|
||||
[SerializeField] private MinesweeperUiConfig uiConfig;
|
||||
|
||||
private readonly Dictionary<int, CellView> cellsByCoordinate = new Dictionary<int, CellView>();
|
||||
private IReadOnlyList<BoardCellData> currentCells;
|
||||
private bool inputEnabled = true;
|
||||
private bool currentRevealUnflaggedMines;
|
||||
private bool resizeRefreshPending;
|
||||
private int currentBoardWidth;
|
||||
private int currentBoardHeight;
|
||||
private float currentContentPadding = MinimumContentPadding;
|
||||
private float currentPixelsPerUnitMultiplier = 1f;
|
||||
private float resizeStableAt;
|
||||
private Vector2 lastObservedLayoutSize;
|
||||
|
||||
private GameObject Root => root != null ? root : gameObject;
|
||||
|
||||
public event Action CellPressStarted;
|
||||
public event Action CellPressEnded;
|
||||
public event Action PauseRequested;
|
||||
public event Action<int, int> CellOpenRequested;
|
||||
public event Action<int, int> CellFlagRequested;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (root == null)
|
||||
{
|
||||
root = gameObject;
|
||||
}
|
||||
|
||||
if (boardPanel == null)
|
||||
{
|
||||
boardPanel = transform as RectTransform;
|
||||
}
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
TrackResize();
|
||||
}
|
||||
|
||||
public void BindConfig(MinesweeperUiConfig config)
|
||||
{
|
||||
uiConfig = config;
|
||||
}
|
||||
|
||||
public void Show()
|
||||
{
|
||||
Root.SetActive(true);
|
||||
ResetResizeTracking();
|
||||
}
|
||||
|
||||
public void Hide()
|
||||
{
|
||||
Root.SetActive(false);
|
||||
}
|
||||
|
||||
public void Rebuild(IReadOnlyList<BoardCellData> cells, int width, int height, ICellViewFactory cellViewFactory, bool revealUnflaggedMines)
|
||||
{
|
||||
Clear();
|
||||
currentBoardWidth = width;
|
||||
currentBoardHeight = height;
|
||||
currentCells = cells;
|
||||
currentRevealUnflaggedMines = revealUnflaggedMines;
|
||||
ConfigureGrid(width, height);
|
||||
|
||||
for (var i = 0; i < cells.Count; i++)
|
||||
{
|
||||
CreateCell(cells[i], cellViewFactory);
|
||||
}
|
||||
|
||||
Refresh(cells, revealUnflaggedMines);
|
||||
}
|
||||
|
||||
public void Refresh(IReadOnlyList<BoardCellData> cells, bool revealUnflaggedMines)
|
||||
{
|
||||
currentCells = cells;
|
||||
currentRevealUnflaggedMines = revealUnflaggedMines;
|
||||
|
||||
for (var i = 0; i < cells.Count; i++)
|
||||
{
|
||||
var cell = cells[i];
|
||||
if (cellsByCoordinate.TryGetValue(ToKey(cell.X, cell.Y), out var view))
|
||||
{
|
||||
view.Render(cell, uiConfig, currentPixelsPerUnitMultiplier, currentContentPadding, revealUnflaggedMines);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SetInputEnabled(bool enabled)
|
||||
{
|
||||
inputEnabled = enabled;
|
||||
foreach (var cell in cellsByCoordinate.Values)
|
||||
{
|
||||
cell.SetInputEnabled(enabled);
|
||||
}
|
||||
}
|
||||
|
||||
private void TrackResize()
|
||||
{
|
||||
if (boardPanel == null || !boardPanel.gameObject.activeInHierarchy || currentCells == null || currentBoardWidth <= 0 || currentBoardHeight <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var layoutSize = GetLayoutSourceSize();
|
||||
if (layoutSize.x <= 0f || layoutSize.y <= 0f)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (HasSizeChanged(layoutSize, lastObservedLayoutSize))
|
||||
{
|
||||
lastObservedLayoutSize = layoutSize;
|
||||
resizeStableAt = Time.unscaledTime + ResizeRefreshDelaySeconds;
|
||||
resizeRefreshPending = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (resizeRefreshPending && Time.unscaledTime >= resizeStableAt)
|
||||
{
|
||||
resizeRefreshPending = false;
|
||||
RefreshLayout();
|
||||
}
|
||||
}
|
||||
|
||||
private void RefreshLayout()
|
||||
{
|
||||
ConfigureGrid(currentBoardWidth, currentBoardHeight);
|
||||
Refresh(currentCells, currentRevealUnflaggedMines);
|
||||
}
|
||||
|
||||
private void ConfigureGrid(int width, int height)
|
||||
{
|
||||
if (gridLayoutGroup == null || boardPanel == null || uiConfig == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Canvas.ForceUpdateCanvases();
|
||||
|
||||
var layoutSize = GetLayoutSourceSize();
|
||||
var panelWidth = layoutSize.x > 0f ? layoutSize.x : uiConfig.ReferenceCellSize * width;
|
||||
var panelHeight = layoutSize.y > 0f ? layoutSize.y : uiConfig.ReferenceCellSize * height;
|
||||
var cellSize = CalculateCellSize(panelWidth, panelHeight, width, height);
|
||||
var padding = cellSize * uiConfig.BoardPaddingRatio;
|
||||
var spacing = cellSize * uiConfig.GridSpacingRatio;
|
||||
|
||||
boardPanel.anchorMin = Vector2.zero;
|
||||
boardPanel.anchorMax = Vector2.one;
|
||||
boardPanel.offsetMin = new Vector2(padding, padding);
|
||||
boardPanel.offsetMax = new Vector2(-padding, -padding);
|
||||
|
||||
gridLayoutGroup.constraint = GridLayoutGroup.Constraint.FixedColumnCount;
|
||||
gridLayoutGroup.constraintCount = width;
|
||||
gridLayoutGroup.padding = new RectOffset();
|
||||
gridLayoutGroup.spacing = new Vector2(spacing, spacing);
|
||||
gridLayoutGroup.cellSize = new Vector2(cellSize, cellSize);
|
||||
currentPixelsPerUnitMultiplier = Mathf.Min(MaximumCellPixelsPerUnitMultiplier, uiConfig.ReferenceCellSize / cellSize);
|
||||
currentContentPadding = CalculateContentPadding(cellSize);
|
||||
lastObservedLayoutSize = layoutSize;
|
||||
}
|
||||
|
||||
private Vector2 GetLayoutSourceSize()
|
||||
{
|
||||
var parentRect = boardPanel.parent as RectTransform;
|
||||
var rect = parentRect != null ? parentRect.rect : boardPanel.rect;
|
||||
return rect.size;
|
||||
}
|
||||
|
||||
private void ResetResizeTracking()
|
||||
{
|
||||
resizeRefreshPending = false;
|
||||
if (boardPanel != null)
|
||||
{
|
||||
lastObservedLayoutSize = GetLayoutSourceSize();
|
||||
}
|
||||
}
|
||||
|
||||
private float CalculateCellSize(float panelWidth, float panelHeight, int width, int height)
|
||||
{
|
||||
var widthUnits = width + 2f * uiConfig.BoardPaddingRatio + Mathf.Max(0, width - 1) * uiConfig.GridSpacingRatio;
|
||||
var heightUnits = height + 2f * uiConfig.BoardPaddingRatio + Mathf.Max(0, height - 1) * uiConfig.GridSpacingRatio;
|
||||
var cellByWidth = panelWidth / widthUnits;
|
||||
var cellByHeight = panelHeight / heightUnits;
|
||||
return Mathf.Max(uiConfig.MinimumCellSize, Mathf.Floor(Mathf.Min(cellByWidth, cellByHeight)));
|
||||
}
|
||||
|
||||
private void CreateCell(BoardCellData cell, ICellViewFactory cellViewFactory)
|
||||
{
|
||||
if (gridLayoutGroup == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var view = cellViewFactory.CreateCell(cell, gridLayoutGroup.transform);
|
||||
if (view == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
view.SetInputEnabled(inputEnabled);
|
||||
view.OpenRequested += OnCellOpenRequested;
|
||||
view.FlagRequested += OnCellFlagRequested;
|
||||
view.PressStarted += OnCellPressStarted;
|
||||
view.PressEnded += OnCellPressEnded;
|
||||
cellsByCoordinate[ToKey(cell.X, cell.Y)] = view;
|
||||
}
|
||||
|
||||
private void Clear()
|
||||
{
|
||||
foreach (var cell in cellsByCoordinate.Values)
|
||||
{
|
||||
if (cell != null)
|
||||
{
|
||||
cell.OpenRequested -= OnCellOpenRequested;
|
||||
cell.FlagRequested -= OnCellFlagRequested;
|
||||
cell.PressStarted -= OnCellPressStarted;
|
||||
cell.PressEnded -= OnCellPressEnded;
|
||||
}
|
||||
}
|
||||
|
||||
cellsByCoordinate.Clear();
|
||||
|
||||
if (gridLayoutGroup == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (var i = gridLayoutGroup.transform.childCount - 1; i >= 0; i--)
|
||||
{
|
||||
Destroy(gridLayoutGroup.transform.GetChild(i).gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnCellOpenRequested(int x, int y)
|
||||
{
|
||||
CellOpenRequested?.Invoke(x, y);
|
||||
}
|
||||
|
||||
private void OnCellFlagRequested(int x, int y)
|
||||
{
|
||||
CellFlagRequested?.Invoke(x, y);
|
||||
}
|
||||
|
||||
private void OnCellPressStarted()
|
||||
{
|
||||
CellPressStarted?.Invoke();
|
||||
}
|
||||
|
||||
private void OnCellPressEnded()
|
||||
{
|
||||
CellPressEnded?.Invoke();
|
||||
}
|
||||
|
||||
private void OnPauseClicked()
|
||||
{
|
||||
PauseRequested?.Invoke();
|
||||
}
|
||||
|
||||
private static float CalculateContentPadding(float cellSize)
|
||||
{
|
||||
return Mathf.Max(MinimumContentPadding, cellSize * ContentPaddingReferencePadding / ContentPaddingReferenceCellSize);
|
||||
}
|
||||
|
||||
private static bool HasSizeChanged(Vector2 current, Vector2 previous)
|
||||
{
|
||||
return Mathf.Abs(current.x - previous.x) > ResizeSizeEpsilon || Mathf.Abs(current.y - previous.y) > ResizeSizeEpsilon;
|
||||
}
|
||||
|
||||
private static int ToKey(int x, int y)
|
||||
{
|
||||
return (y << 16) ^ x;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8e5eb8dfe520e3b40af304e66728dcfb
|
||||
@@ -0,0 +1,147 @@
|
||||
using System;
|
||||
using Minesweeper.Core;
|
||||
using Minesweeper.Config;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace Minesweeper.Presentation.Views
|
||||
{
|
||||
public sealed class CellView : MonoBehaviour, IPointerClickHandler, IPointerDownHandler, IPointerUpHandler
|
||||
{
|
||||
[SerializeField] private Button button;
|
||||
[SerializeField] private Image backgroundImage;
|
||||
[SerializeField] private RectTransform contentRoot;
|
||||
[SerializeField] private Image contentImage;
|
||||
[SerializeField] private TMP_Text label;
|
||||
|
||||
private int x;
|
||||
private int y;
|
||||
private bool inputEnabled = true;
|
||||
private bool isOpened;
|
||||
|
||||
public event Action<int, int> OpenRequested;
|
||||
public event Action<int, int> FlagRequested;
|
||||
public event Action PressStarted;
|
||||
public event Action PressEnded;
|
||||
|
||||
public void Bind(Button button, Image backgroundImage, RectTransform contentRoot, Image contentImage, TMP_Text label)
|
||||
{
|
||||
this.button = button;
|
||||
this.backgroundImage = backgroundImage;
|
||||
this.contentRoot = contentRoot;
|
||||
this.contentImage = contentImage;
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
public void Initialize(int x, int y)
|
||||
{
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public void SetInputEnabled(bool enabled)
|
||||
{
|
||||
inputEnabled = enabled;
|
||||
if (button != null)
|
||||
{
|
||||
button.interactable = enabled && !isOpened;
|
||||
}
|
||||
}
|
||||
|
||||
public void Render(BoardCellData cell, MinesweeperUiConfig config, float pixelsPerUnitMultiplier, float contentPadding, bool revealUnflaggedMines)
|
||||
{
|
||||
gameObject.name = $"bt_{cell.X}_{cell.Y}_{cell.DisplayValue}";
|
||||
isOpened = cell.IsOpened;
|
||||
var revealMine = revealUnflaggedMines && cell.IsMine && !cell.IsFlagged;
|
||||
|
||||
if (contentRoot != null)
|
||||
{
|
||||
contentRoot.offsetMin = new Vector2(contentPadding, contentPadding);
|
||||
contentRoot.offsetMax = new Vector2(-contentPadding, -contentPadding);
|
||||
}
|
||||
|
||||
if (backgroundImage != null)
|
||||
{
|
||||
backgroundImage.pixelsPerUnitMultiplier = pixelsPerUnitMultiplier;
|
||||
backgroundImage.color = cell.IsOpened || revealMine ? config.OpenedCellColor : config.ClosedCellColor;
|
||||
}
|
||||
|
||||
if (contentImage != null)
|
||||
{
|
||||
contentImage.pixelsPerUnitMultiplier = pixelsPerUnitMultiplier;
|
||||
}
|
||||
|
||||
RenderContent(cell, config, revealMine);
|
||||
|
||||
if (button != null)
|
||||
{
|
||||
button.interactable = inputEnabled && !cell.IsOpened;
|
||||
}
|
||||
}
|
||||
|
||||
private void RenderContent(BoardCellData cell, MinesweeperUiConfig config, bool revealMine)
|
||||
{
|
||||
var showFlag = cell.IsFlagged && !cell.IsOpened;
|
||||
var showMine = (cell.IsOpened && cell.IsMine) || revealMine;
|
||||
var showMineAsText = showMine && config.MineSprite == null;
|
||||
var showNumber = cell.IsOpened && !cell.IsMine && cell.NeighborMines > 0;
|
||||
|
||||
if (contentImage != null)
|
||||
{
|
||||
contentImage.gameObject.SetActive(showFlag || (showMine && !showMineAsText));
|
||||
if (showFlag)
|
||||
{
|
||||
contentImage.sprite = config.FlagSprite;
|
||||
}
|
||||
else if (showMine)
|
||||
{
|
||||
contentImage.sprite = config.MineSprite;
|
||||
}
|
||||
|
||||
contentImage.color = Color.white;
|
||||
}
|
||||
|
||||
if (label != null)
|
||||
{
|
||||
label.gameObject.SetActive(showNumber || showMineAsText);
|
||||
label.text = showMineAsText ? "M" : showNumber ? cell.NeighborMines.ToString() : string.Empty;
|
||||
label.color = config.GetNumberTextColor(cell.NeighborMines);
|
||||
}
|
||||
}
|
||||
|
||||
public void OnPointerClick(PointerEventData eventData)
|
||||
{
|
||||
if (!inputEnabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (eventData.button == PointerEventData.InputButton.Left)
|
||||
{
|
||||
OpenRequested?.Invoke(x, y);
|
||||
}
|
||||
else if (eventData.button == PointerEventData.InputButton.Right)
|
||||
{
|
||||
FlagRequested?.Invoke(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
public void OnPointerDown(PointerEventData eventData)
|
||||
{
|
||||
if (inputEnabled && eventData.button == PointerEventData.InputButton.Left)
|
||||
{
|
||||
PressStarted?.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
public void OnPointerUp(PointerEventData eventData)
|
||||
{
|
||||
if (eventData.button == PointerEventData.InputButton.Left)
|
||||
{
|
||||
PressEnded?.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2904d462d22809c499afe1842f6e6239
|
||||
@@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Minesweeper.Core;
|
||||
using Minesweeper.Presentation.Factories;
|
||||
|
||||
namespace Minesweeper.Presentation.Views
|
||||
{
|
||||
public interface IBoardView : IView
|
||||
{
|
||||
event Action CellPressStarted;
|
||||
event Action CellPressEnded;
|
||||
event Action PauseRequested;
|
||||
event Action<int, int> CellOpenRequested;
|
||||
event Action<int, int> CellFlagRequested;
|
||||
|
||||
void Show();
|
||||
void Hide();
|
||||
void Rebuild(IReadOnlyList<BoardCellData> cells, int width, int height, ICellViewFactory cellViewFactory, bool revealUnflaggedMines);
|
||||
void Refresh(IReadOnlyList<BoardCellData> cells, bool revealUnflaggedMines);
|
||||
void SetInputEnabled(bool enabled);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cfdc53be4df29994fa56373d71a3b43a
|
||||
@@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using Minesweeper.Core;
|
||||
|
||||
namespace Minesweeper.Presentation.Views
|
||||
{
|
||||
public interface IMainMenuView : IView
|
||||
{
|
||||
event Action StartClicked;
|
||||
event Action SizeChanged;
|
||||
|
||||
GameSettingsValue SelectedSettings { get; }
|
||||
|
||||
void Show();
|
||||
void Hide();
|
||||
void ConfigureSizeX(int min, int max, int value);
|
||||
void ConfigureSizeY(int min, int max, int value);
|
||||
void ConfigureMines(int min, int max, int value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 66cad179080f23a479c3418932137653
|
||||
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
|
||||
namespace Minesweeper.Presentation.Views
|
||||
{
|
||||
public interface IPauseView : IView
|
||||
{
|
||||
event Action RestartRequested;
|
||||
event Action ResumeRequested;
|
||||
event Action GoToMenuRequested;
|
||||
|
||||
void Show();
|
||||
void Hide();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 68d5d80ca9e50564b8616608563e8d73
|
||||
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using Minesweeper.Core;
|
||||
|
||||
namespace Minesweeper.Presentation.Views
|
||||
{
|
||||
public interface IResultView : IView
|
||||
{
|
||||
event Action RestartRequested;
|
||||
event Action GoToMenuRequested;
|
||||
|
||||
void Show(GameState state);
|
||||
void Hide();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ab5a37a62d4a8284ea45b6d2c835a4d1
|
||||
@@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using Minesweeper.Config;
|
||||
|
||||
namespace Minesweeper.Presentation.Views
|
||||
{
|
||||
public interface ITopPanelView : IView
|
||||
{
|
||||
event Action SmileClicked;
|
||||
|
||||
void SetActive(bool active);
|
||||
void SetRemainingMines(int remainingMines);
|
||||
void SetTimer(float seconds);
|
||||
void SetSmile(SmileFaceState state);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e0c8cae3d1ad4d7a9ca3e2f8f435cd7b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Minesweeper.Presentation.Views
|
||||
{
|
||||
public interface IView
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 66a8b79ae5812744680f9e386b007144
|
||||
@@ -0,0 +1,97 @@
|
||||
using System;
|
||||
using Minesweeper.Core;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace Minesweeper.Presentation.Views
|
||||
{
|
||||
public sealed class MainMenuView : MonoBehaviour, IMainMenuView
|
||||
{
|
||||
[SerializeField] private GameObject root;
|
||||
[SerializeField] private Button startButton;
|
||||
[SerializeField] private MenuSliderView sizeXSlider = new MenuSliderView();
|
||||
[SerializeField] private MenuSliderView sizeYSlider = new MenuSliderView();
|
||||
[SerializeField] private MenuSliderView minesSlider = new MenuSliderView();
|
||||
|
||||
public event Action StartClicked;
|
||||
public event Action SizeChanged;
|
||||
|
||||
public GameSettingsValue SelectedSettings => new GameSettingsValue(sizeXSlider.Value, sizeYSlider.Value, minesSlider.Value);
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (root == null)
|
||||
{
|
||||
root = gameObject;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
if (startButton != null)
|
||||
{
|
||||
startButton.onClick.AddListener(OnStartClicked);
|
||||
}
|
||||
|
||||
sizeXSlider.ValueChanged += OnSizeSliderChanged;
|
||||
sizeYSlider.ValueChanged += OnSizeSliderChanged;
|
||||
sizeXSlider.AddListeners();
|
||||
sizeYSlider.AddListeners();
|
||||
minesSlider.AddListeners();
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
if (startButton != null)
|
||||
{
|
||||
startButton.onClick.RemoveListener(OnStartClicked);
|
||||
}
|
||||
|
||||
sizeXSlider.RemoveListeners();
|
||||
sizeYSlider.RemoveListeners();
|
||||
minesSlider.RemoveListeners();
|
||||
sizeXSlider.ValueChanged -= OnSizeSliderChanged;
|
||||
sizeYSlider.ValueChanged -= OnSizeSliderChanged;
|
||||
}
|
||||
|
||||
public void Show()
|
||||
{
|
||||
root.SetActive(true);
|
||||
}
|
||||
|
||||
public void Hide()
|
||||
{
|
||||
root.SetActive(false);
|
||||
}
|
||||
|
||||
public void ConfigureSizeX(int min, int max, int value)
|
||||
{
|
||||
sizeXSlider.Configure(min, max, value, "Size X");
|
||||
}
|
||||
|
||||
public void ConfigureSizeY(int min, int max, int value)
|
||||
{
|
||||
sizeYSlider.Configure(min, max, value, "Size Y");
|
||||
}
|
||||
|
||||
public void ConfigureMines(int min, int max, int value)
|
||||
{
|
||||
minesSlider.Configure(min, max, value, "Mines Count");
|
||||
}
|
||||
|
||||
private void OnStartClicked()
|
||||
{
|
||||
StartClicked?.Invoke();
|
||||
}
|
||||
|
||||
public void BindRoot(GameObject root)
|
||||
{
|
||||
this.root = root != null ? root : gameObject;
|
||||
}
|
||||
|
||||
private void OnSizeSliderChanged(int value)
|
||||
{
|
||||
SizeChanged?.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bb899c7e47cd4e341b0258dac3f7a238
|
||||
@@ -0,0 +1,89 @@
|
||||
using System;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace Minesweeper.Presentation.Views
|
||||
{
|
||||
[Serializable]
|
||||
public sealed class MenuSliderView
|
||||
{
|
||||
[SerializeField] private Slider slider;
|
||||
[SerializeField] private TMP_Text minText;
|
||||
[SerializeField] private TMP_Text maxText;
|
||||
[SerializeField] private TMP_Text valueText;
|
||||
[SerializeField] private string valueLabel;
|
||||
|
||||
public event Action<int> ValueChanged;
|
||||
|
||||
public int Value => slider != null ? Mathf.RoundToInt(slider.value) : 0;
|
||||
|
||||
public void Bind(Slider slider, TMP_Text minText, TMP_Text maxText, TMP_Text valueText)
|
||||
{
|
||||
RemoveListeners();
|
||||
this.slider = slider;
|
||||
this.minText = minText;
|
||||
this.maxText = maxText;
|
||||
this.valueText = valueText;
|
||||
AddListeners();
|
||||
}
|
||||
|
||||
public void AddListeners()
|
||||
{
|
||||
if (slider != null)
|
||||
{
|
||||
slider.onValueChanged.AddListener(OnValueChanged);
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveListeners()
|
||||
{
|
||||
if (slider != null)
|
||||
{
|
||||
slider.onValueChanged.RemoveListener(OnValueChanged);
|
||||
}
|
||||
}
|
||||
|
||||
public void Configure(int min, int max, int value, string label)
|
||||
{
|
||||
if (slider == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
valueLabel = label;
|
||||
var clampedMax = Mathf.Max(min, max);
|
||||
var clampedValue = Mathf.Clamp(value, min, clampedMax);
|
||||
slider.wholeNumbers = true;
|
||||
slider.minValue = min;
|
||||
slider.maxValue = clampedMax;
|
||||
slider.SetValueWithoutNotify(clampedValue);
|
||||
SetText(minText, min);
|
||||
SetText(maxText, clampedMax);
|
||||
SetValueText(clampedValue);
|
||||
}
|
||||
|
||||
private void OnValueChanged(float value)
|
||||
{
|
||||
var intValue = Mathf.RoundToInt(value);
|
||||
SetValueText(intValue);
|
||||
ValueChanged?.Invoke(intValue);
|
||||
}
|
||||
|
||||
private void SetValueText(int value)
|
||||
{
|
||||
if (valueText != null)
|
||||
{
|
||||
valueText.text = string.IsNullOrEmpty(valueLabel) ? value.ToString() : $"{valueLabel}: {value}";
|
||||
}
|
||||
}
|
||||
|
||||
private static void SetText(TMP_Text text, int value)
|
||||
{
|
||||
if (text != null)
|
||||
{
|
||||
text.text = value.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 15be53f58e067f944a33854111083046
|
||||
@@ -0,0 +1,22 @@
|
||||
namespace Minesweeper.Presentation.Views
|
||||
{
|
||||
public readonly struct MinesweeperScreenRefs
|
||||
{
|
||||
public MinesweeperScreenRefs(
|
||||
MainMenuView mainMenuView,
|
||||
BoardView boardView,
|
||||
PauseView pauseView,
|
||||
ResultView resultView)
|
||||
{
|
||||
MainMenuView = mainMenuView;
|
||||
BoardView = boardView;
|
||||
PauseView = pauseView;
|
||||
ResultView = resultView;
|
||||
}
|
||||
|
||||
public MainMenuView MainMenuView { get; }
|
||||
public BoardView BoardView { get; }
|
||||
public PauseView PauseView { get; }
|
||||
public ResultView ResultView { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8a411cd19a61afa45851795dc2794651
|
||||
@@ -0,0 +1,21 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Minesweeper.Core;
|
||||
using Minesweeper.Presentation.Factories;
|
||||
|
||||
namespace Minesweeper.Presentation.Views
|
||||
{
|
||||
public sealed class NullBoardView : IBoardView
|
||||
{
|
||||
public event Action CellPressStarted { add { } remove { } }
|
||||
public event Action CellPressEnded { add { } remove { } }
|
||||
public event Action PauseRequested { add { } remove { } }
|
||||
public event Action<int, int> CellOpenRequested { add { } remove { } }
|
||||
public event Action<int, int> CellFlagRequested { add { } remove { } }
|
||||
public void Show() { }
|
||||
public void Hide() { }
|
||||
public void Rebuild(IReadOnlyList<BoardCellData> cells, int width, int height, ICellViewFactory cellViewFactory, bool revealUnflaggedMines) { }
|
||||
public void Refresh(IReadOnlyList<BoardCellData> cells, bool revealUnflaggedMines) { }
|
||||
public void SetInputEnabled(bool enabled) { }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0e79bb89d6efdcb4a8c7462de1871790
|
||||
@@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using Minesweeper.Core;
|
||||
|
||||
namespace Minesweeper.Presentation.Views
|
||||
{
|
||||
public sealed class NullMainMenuView : IMainMenuView
|
||||
{
|
||||
public event Action StartClicked
|
||||
{
|
||||
add { }
|
||||
remove { }
|
||||
}
|
||||
|
||||
public event Action SizeChanged
|
||||
{
|
||||
add { }
|
||||
remove { }
|
||||
}
|
||||
|
||||
public GameSettingsValue SelectedSettings => default;
|
||||
|
||||
public void Show()
|
||||
{
|
||||
}
|
||||
|
||||
public void Hide()
|
||||
{
|
||||
}
|
||||
|
||||
public void ConfigureSizeX(int min, int max, int value)
|
||||
{
|
||||
}
|
||||
|
||||
public void ConfigureSizeY(int min, int max, int value)
|
||||
{
|
||||
}
|
||||
|
||||
public void ConfigureMines(int min, int max, int value)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6b41dd95488a1db42adccef0225d2f89
|
||||
@@ -0,0 +1,13 @@
|
||||
using System;
|
||||
|
||||
namespace Minesweeper.Presentation.Views
|
||||
{
|
||||
public sealed class NullPauseView : IPauseView
|
||||
{
|
||||
public event Action RestartRequested { add { } remove { } }
|
||||
public event Action ResumeRequested { add { } remove { } }
|
||||
public event Action GoToMenuRequested { add { } remove { } }
|
||||
public void Show() { }
|
||||
public void Hide() { }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a2128d569219f1240ba7bb7c146fa1fd
|
||||
@@ -0,0 +1,13 @@
|
||||
using System;
|
||||
using Minesweeper.Core;
|
||||
|
||||
namespace Minesweeper.Presentation.Views
|
||||
{
|
||||
public sealed class NullResultView : IResultView
|
||||
{
|
||||
public event Action RestartRequested { add { } remove { } }
|
||||
public event Action GoToMenuRequested { add { } remove { } }
|
||||
public void Show(GameState state) { }
|
||||
public void Hide() { }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b1db865929a8fc24097435b51a80e818
|
||||
@@ -0,0 +1,30 @@
|
||||
using System;
|
||||
using Minesweeper.Config;
|
||||
|
||||
namespace Minesweeper.Presentation.Views
|
||||
{
|
||||
public sealed class NullTopPanelView : ITopPanelView
|
||||
{
|
||||
public event Action SmileClicked
|
||||
{
|
||||
add { }
|
||||
remove { }
|
||||
}
|
||||
|
||||
public void SetActive(bool active)
|
||||
{
|
||||
}
|
||||
|
||||
public void SetRemainingMines(int remainingMines)
|
||||
{
|
||||
}
|
||||
|
||||
public void SetTimer(float seconds)
|
||||
{
|
||||
}
|
||||
|
||||
public void SetSmile(SmileFaceState state)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c8372ef8aa2747d7af12fce4f1324baf
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,99 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace Minesweeper.Presentation.Views
|
||||
{
|
||||
public sealed class PauseView : MonoBehaviour, IPauseView
|
||||
{
|
||||
[SerializeField] private GameObject root;
|
||||
[SerializeField] private Button restartButton;
|
||||
[SerializeField] private Button resumeButton;
|
||||
[SerializeField] private Button mainMenuButton;
|
||||
|
||||
public event Action RestartRequested;
|
||||
public event Action ResumeRequested;
|
||||
public event Action GoToMenuRequested;
|
||||
|
||||
private GameObject Root => root != null ? root : gameObject;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (root == null)
|
||||
{
|
||||
root = gameObject;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
AddListeners();
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
RemoveListeners();
|
||||
}
|
||||
|
||||
public void Show()
|
||||
{
|
||||
Root.SetActive(true);
|
||||
}
|
||||
|
||||
public void Hide()
|
||||
{
|
||||
Root.SetActive(false);
|
||||
}
|
||||
|
||||
private void AddListeners()
|
||||
{
|
||||
if (restartButton != null)
|
||||
{
|
||||
restartButton.onClick.AddListener(OnRestartClicked);
|
||||
}
|
||||
|
||||
if (resumeButton != null)
|
||||
{
|
||||
resumeButton.onClick.AddListener(OnResumeClicked);
|
||||
}
|
||||
|
||||
if (mainMenuButton != null)
|
||||
{
|
||||
mainMenuButton.onClick.AddListener(OnMainMenuClicked);
|
||||
}
|
||||
}
|
||||
|
||||
private void RemoveListeners()
|
||||
{
|
||||
if (restartButton != null)
|
||||
{
|
||||
restartButton.onClick.RemoveListener(OnRestartClicked);
|
||||
}
|
||||
|
||||
if (resumeButton != null)
|
||||
{
|
||||
resumeButton.onClick.RemoveListener(OnResumeClicked);
|
||||
}
|
||||
|
||||
if (mainMenuButton != null)
|
||||
{
|
||||
mainMenuButton.onClick.RemoveListener(OnMainMenuClicked);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnRestartClicked()
|
||||
{
|
||||
RestartRequested?.Invoke();
|
||||
}
|
||||
|
||||
private void OnResumeClicked()
|
||||
{
|
||||
ResumeRequested?.Invoke();
|
||||
}
|
||||
|
||||
private void OnMainMenuClicked()
|
||||
{
|
||||
GoToMenuRequested?.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 548c3a1ddca35cc4d823c260a88dcecf
|
||||
@@ -0,0 +1,89 @@
|
||||
using System;
|
||||
using Minesweeper.Core;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace Minesweeper.Presentation.Views
|
||||
{
|
||||
public sealed class ResultView : MonoBehaviour, IResultView
|
||||
{
|
||||
[SerializeField] private GameObject root;
|
||||
[SerializeField] private Button restartButton;
|
||||
[SerializeField] private Button mainMenuButton;
|
||||
[SerializeField] private TMP_Text resultText;
|
||||
|
||||
public event Action RestartRequested;
|
||||
public event Action GoToMenuRequested;
|
||||
|
||||
private GameObject Root => root != null ? root : gameObject;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (root == null)
|
||||
{
|
||||
root = gameObject;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
AddListeners();
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
RemoveListeners();
|
||||
}
|
||||
|
||||
public void Show(GameState state)
|
||||
{
|
||||
Root.SetActive(true);
|
||||
if (resultText != null)
|
||||
{
|
||||
resultText.text = state == GameState.Won ? "YOU WIN" : "GAME OVER";
|
||||
}
|
||||
}
|
||||
|
||||
public void Hide()
|
||||
{
|
||||
Root.SetActive(false);
|
||||
}
|
||||
|
||||
private void AddListeners()
|
||||
{
|
||||
if (restartButton != null)
|
||||
{
|
||||
restartButton.onClick.AddListener(OnRestartClicked);
|
||||
}
|
||||
|
||||
if (mainMenuButton != null)
|
||||
{
|
||||
mainMenuButton.onClick.AddListener(OnMainMenuClicked);
|
||||
}
|
||||
}
|
||||
|
||||
private void RemoveListeners()
|
||||
{
|
||||
if (restartButton != null)
|
||||
{
|
||||
restartButton.onClick.RemoveListener(OnRestartClicked);
|
||||
}
|
||||
|
||||
if (mainMenuButton != null)
|
||||
{
|
||||
mainMenuButton.onClick.RemoveListener(OnMainMenuClicked);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnRestartClicked()
|
||||
{
|
||||
RestartRequested?.Invoke();
|
||||
}
|
||||
|
||||
private void OnMainMenuClicked()
|
||||
{
|
||||
GoToMenuRequested?.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b0b04ab8a2ef00b4e8d36a96e4f034d8
|
||||
@@ -0,0 +1,91 @@
|
||||
using System;
|
||||
using Minesweeper.Config;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace Minesweeper.Presentation.Views
|
||||
{
|
||||
public sealed class TopPanelView : MonoBehaviour, ITopPanelView
|
||||
{
|
||||
[SerializeField] private GameObject root;
|
||||
[SerializeField] private TMP_Text mineText;
|
||||
[SerializeField] private TMP_Text timerText;
|
||||
[SerializeField] private Button smileButton;
|
||||
[SerializeField] private Image smileImage;
|
||||
[SerializeField] private MinesweeperUiConfig uiConfig;
|
||||
|
||||
public event Action SmileClicked;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (root == null)
|
||||
{
|
||||
root = gameObject;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
if (smileButton != null)
|
||||
{
|
||||
smileButton.onClick.AddListener(OnSmileClicked);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
if (smileButton != null)
|
||||
{
|
||||
smileButton.onClick.RemoveListener(OnSmileClicked);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetActive(bool active)
|
||||
{
|
||||
root.SetActive(active);
|
||||
}
|
||||
|
||||
public void SetRemainingMines(int remainingMines)
|
||||
{
|
||||
if (mineText != null)
|
||||
{
|
||||
mineText.text = Mathf.Max(0, remainingMines).ToString("00000");
|
||||
}
|
||||
}
|
||||
|
||||
public void SetTimer(float seconds)
|
||||
{
|
||||
if (timerText != null)
|
||||
{
|
||||
timerText.text = Mathf.FloorToInt(seconds).ToString("00000");
|
||||
}
|
||||
}
|
||||
|
||||
public void SetSmile(SmileFaceState state)
|
||||
{
|
||||
if (smileImage == null || uiConfig == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var sprite = uiConfig.GetSmileSprite(state);
|
||||
if (sprite != null)
|
||||
{
|
||||
smileImage.sprite = sprite;
|
||||
}
|
||||
|
||||
smileImage.color = Color.white;
|
||||
}
|
||||
|
||||
public void BindConfig(MinesweeperUiConfig config)
|
||||
{
|
||||
uiConfig = config;
|
||||
}
|
||||
|
||||
private void OnSmileClicked()
|
||||
{
|
||||
SmileClicked?.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cb4efc57f8404c98bff81ed5db093d81
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user