/
Landilf
/
2413_Ryumin_CourseWork
Обзор
Документация
Войти
/
Landilf
/
2413_Ryumin_CourseWork
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
CourseWork/GUI/ViewModels/GameViewModel.cs
238 строк
6 KB
Landilf
add project
27 янв 2026, 13:57
27 янв 2026, 13:57
753b3e7
Код
Авторство
О чём код?
using Avalonia.Threading; using GameCore.Engine; using GameCore.Entities; using GameCore.Enums; using ReactiveUI; namespace GUI.ViewModels; /// <summary> /// Модель представления игрового процесса. /// </summary> public class GameViewModel : ViewModelBase { #region Поля /// <summary> /// Ссылка на главную модель. /// </summary> private readonly MainViewModel _mainViewModel; #endregion #region Свойства /// <summary> /// Игровой движок (через контроллер). /// </summary> public GameEngine Engine => _mainViewModel.Controller.Engine; /// <summary> /// Значение обратного отсчета для отображения (сек). /// </summary> public int CountdownValue => Engine.Session.CountdownValue; /// <summary> /// Активен ли сейчас обратный отсчет. /// </summary> public bool IsCountdownActive => Engine.Session.IsCountdownActive; /// <summary> /// Событие запроса отрисовки. /// </summary> public event Action? RequestRender; /// <summary> /// Список игроков, отсортированный по очкам. /// </summary> public IEnumerable<Player> SortedPlayers { get { lock (Engine.SyncRoot) { return Engine.Players.OrderByDescending(p => p.PercentCaptured).ToList(); } } } /// <summary> /// Игрок-человек. /// </summary> public Player? HumanPlayer { get { lock (Engine.SyncRoot) { return Engine.Players.FirstOrDefault(p => !p.IsBot); } } } #endregion #region Конструкторы /// <summary> /// Конструктор. /// </summary> /// <param name="parMainViewModel">Главная модель.</param> public GameViewModel(MainViewModel parMainViewModel) { _mainViewModel = parMainViewModel; // Подписка на события движка через контроллер Engine.OnStateChanged += OnGameStateChanged; // Подписка на события цикла _mainViewModel.Controller.OnGameUpdated += OnGameUpdated; _mainViewModel.Controller.OnRenderFrame += OnRenderFrame; } #endregion #region Методы /// <summary> /// Запускает игру. /// </summary> /// <param name="parPlayerName">Имя игрока.</param> public void StartGame(string parPlayerName) { _mainViewModel.Controller.StartGame(parPlayerName); } /// <summary> /// Останавливает игру. /// </summary> public void StopGame() { _mainViewModel.Controller.StopGame(); } /// <summary> /// Обработчик обновления логики (вызывается из контроллера). /// </summary> private void OnGameUpdated() { // Если нужно обновить UI-свойства, зависящие от логики // В данном случае CountdownValue обновляется здесь или в Render, // но RaisePropertyChanged лучше делать, когда данные изменились. // Однако SortedPlayers и Countdown лучше дергать в UI потоке перед отрисовкой // или через Dispatcher здесь. } /// <summary> /// Обработчик кадра (вызывается из контроллера). /// </summary> private void OnRenderFrame() { Dispatcher.UIThread.Post(() => { // Обновляем свойства для UI if (IsCountdownActive) { this.RaisePropertyChanged(nameof(CountdownValue)); this.RaisePropertyChanged(nameof(IsCountdownActive)); } // SortedPlayers может меняться каждый тик this.RaisePropertyChanged(nameof(SortedPlayers)); // Запрос отрисовки canvas RequestRender?.Invoke(); }); } /// <summary> /// Обработчик изменения состояния игры. /// </summary> private void OnGameStateChanged() { if (Engine.State == GameState.GameOver) { StopGame(); Dispatcher.UIThread.Post(() => _mainViewModel.GoToGameOver()); } else if (Engine.State == GameState.Victory) { StopGame(); var duration = Engine.Session.GetDuration(); Dispatcher.UIThread.Post(() => _mainViewModel.GoToVictory(duration)); } // Лишний рендер для обновления статуса Dispatcher.UIThread.Post(() => RequestRender?.Invoke()); } /// <summary> /// Обрабатывает пользовательский ввод. /// </summary> /// <param name="parDirection">Направление движения.</param> public void HandleInput(Direction parDirection) { if (IsCountdownActive) { return; // Блокируем ввод во время отсчета } lock (Engine.SyncRoot) { _mainViewModel.Controller.HandleInput(parDirection); } } /// <summary> /// Активирует чит на мгновенную победу. /// </summary> public void CheatVictory() { lock (Engine.SyncRoot) { _mainViewModel.Controller.CheatVictory(); } } /// <summary> /// Ставит игру на паузу. /// </summary> public void PauseGame() { if (IsCountdownActive) { return; // Нельзя ставить на паузу во время отсчета } // Блокировка теперь внутри контроллера, но Pause - это отдельный метод // В контроллере Pause просто меняет стейт. lock (Engine.SyncRoot) { _mainViewModel.Controller.Pause(); } StopGame(); _mainViewModel.GoToPauseMenu(); } /// <summary> /// Возобновляет игру. /// </summary> public void ResumeGame() { lock (Engine.SyncRoot) { _mainViewModel.Controller.Resume(); } } /// <summary> /// Возвращается в главное меню. /// </summary> public void GoBack() { StopGame(); _mainViewModel.GoToMenu(); } #endregion }