Текстовая игра на C#
Приветствую! Здесь вы наверняка найдете, что ищете. Примеры в лаборатории рассчитаны на то, что мы разбираем что-то конкретное.
Текущая статья посвящена текстовой игре на C# — состояние, сцены, ввод пользователя и циклы.
Поэтому за теорией по текущей теме вам — в энциклопедию. Если ещё не погружались, то маршрут прост:
- Основы
- Система и сеть
- Данные и разметка
- Код и разработка
- Языки
- Искусственный интеллект
- Проект
- Инфраструктура и безопасность
- Спин-офф
Обязательно пройдитесь.
А теперь приступим к нашему предмету.
Текстовая игра на C#
Текстовая игра — это классический формат интерактивного программного обеспечения, в котором взаимодействие с пользователем происходит исключительно через текстовый ввод и вывод. Такие игры не требуют графического интерфейса, а игровой процесс строится на описаниях, выборе действий и логике принятия решений. В среде обучения программированию текстовые игры часто используются как практический способ освоить базовые конструкции языка: циклы, условия, методы, коллекции и работу с пользовательским вводом.
В данном примере реализуется консольная текстовая игра на C# с использованием современных возможностей .NET: асинхронности, объектно-ориентированного подхода, инкапсуляции логики и модульной структуры кода. Игра демонстрирует принципы проектирования небольших приложений, которые можно легко расширять и модифицировать.
Архитектура игры
Текстовая игра состоит из следующих ключевых компонентов:
- GameLoop — основной цикл игры, управляющий последовательностью событий;
- GameState — объект, хранящий текущее состояние игры (здоровье героя, уровень, инвентарь и т.д.);
- Narrator — компонент, отвечающий за вывод текстовых сообщений;
- PlayerInput — обработчик пользовательского ввода;
- Scene — абстракция игровой сцены или локации;
- Choice — вариант действия, доступный игроку в текущей сцене.
Такая структура позволяет отделить логику игры от её представления и упрощает добавление новых сцен, персонажей или механик.
Базовые классы и модели
Класс GameState
public class GameState
{
public string PlayerName { get; set; } = "Игрок";
public int Health { get; set; } = 100;
public int Score { get; set; } = 0;
public List<string> Inventory { get; set; } = new();
public string CurrentSceneId { get; set; } = "start";
}
Этот класс содержит всё, что определяет текущее положение игрока в мире игры. Он передаётся между сценами и изменяется по мере развития сюжета.
Класс Choice
public class Choice
{
public string Text { get; set; } = string.Empty;
public string TargetSceneId { get; set; } = string.Empty;
public Action<GameState>? OnSelect { get; set; }
}
Каждый выбор содержит:
- текст, который видит игрок;
- идентификатор следующей сцены;
- необязательное действие, которое выполняется при выборе (например, изменение здоровья или добавление предмета в инвентарь).
Абстрактный класс Scene
public abstract class Scene
{
public string Id { get; init; } = string.Empty;
public abstract string Description { get; }
public abstract List<Choice> GetChoices(GameState state);
}
Каждая конкретная сцена наследуется от этого класса и реализует два метода:
Description— возвращает описание локации;GetChoices— возвращает доступные действия в зависимости от состояния игры.
Реализация конкретных сцен
Стартовая сцена
Сцена красной комнаты
Обратите внимание: при открытии сундука выполняется действие OnSelect, которое проверяет наличие предмета и добавляет его, если его ещё нет. Это предотвращает дублирование и обеспечивает согласованность состояния.
Сцена инвентаря
Здесь используется простой приём: описание генерируется динамически на основе текущего состояния. Это позволяет отображать актуальную информацию без необходимости хранить её отдельно.
Компонент Narrator
Narrator отвечает только за вывод. Он не знает ничего о логике игры — это соответствует принципу разделения ответственности.
Обработка ввода
Метод ReadChoiceAsync запрашивает у пользователя число, проверяет его корректность и возвращает индекс выбранного варианта. Использование async/await делает код совместимым с потенциально асинхронными источниками ввода (например, сетевыми клиентами в будущем).
Основной игровой цикл
Цикл игры:
- Запрашивает имя игрока.
- Пока здоровье больше нуля:
- загружает текущую сцену;
- выводит описание;
- показывает варианты выбора;
- читает ввод;
- выполняет действие (если есть);
- обновляет текущую сцену.
- Завершает игру при достижении финальной сцены или смерти.
Запуск игры
// Program.cs
var game = new GameLoop();
await game.RunAsync();
В проекте .NET 6+ или выше достаточно поместить этот код в файл Program.cs. Приложение будет работать как полноценная консольная программа.
Расширяемость и модификация
Такая архитектура легко расширяется:
- Добавление новых сцен: создаётся новый класс, наследующий
Scene, и регистрируется вGameLoop. - Сложные условия: в
GetChoicesможно добавлять проверки (if (state.Inventory.Contains("ключ"))). - Случайные события: использование
Randomдля генерации разных исходов. - Сохранение прогресса: сериализация
GameStateв JSON и запись в файл. - Локализация: вынос текстов в ресурсы или словари.
Пример сохранения:
public static void SaveGame(GameState state, string path)
{
var json = JsonSerializer.Serialize(state, new JsonSerializerOptions { WriteIndented = true });
File.WriteAllText(path, json);
}
Преимущества подхода
- Читаемость: каждая сцена — самостоятельный класс.
- Тестируемость: можно писать unit-тесты для
GetChoices. - Гибкость: логика выбора полностью отделима от вывода.
- Поддерживаемость: изменения в одной сцене не влияют на другие.
Текстовая игра на C# — это не просто развлечение, а учебный проект, демонстрирующий фундаментальные принципы разработки: инкапсуляцию, абстракцию, управление состоянием и проектирование взаимодействия с пользователем.