Современные веб-фреймворки в основном используются для написания корпоративных приложений, но они давно уже достаточно гибки и функциональны и для других областей. Попробуем написать логическую казуальную игру на ASP.NET Core 2. Рассмотрим процесс создания игрового проекта, а так же новшества фреймворка и сопутствующих инструментов.

ДЕМО
Исходники

Идея


Как было описано выше: игра логическая и казуальная, то есть никакой супер графики и сложных элементов. Наш игровой мир состоит из множества комнат, в каждой из них нас ждет специальное задание, выполнив которое можно перейти в следующую комнату. Соответственно между комнатами есть двери, которые нужно открыть для того, чтобы перейти из одной комнаты в другую. В общем-то все. Каждое задание — это логическая загадка или какой-то интерактивный элемент.

Реализация


Создаем проект


Последняя версия ASP.NET Core вышла совсем недавно (в середине августа), поэтому если вам интересно пройти путь создания проекта с нуля, не забудьте обновить как минимум .NET Core (http://dot.net).
Для создания проект можно использовать как IDE (Visual Studio, Visual Studio for Mac, Rider). В последнем обновлении Visual Studio диалог создания нового веб приложения был немного переделан:



Или же создать проект можно в обычной консоли:



и открыть его в том редакторе что вам нравится.

Из консоли теперь можно также выбрать шаблон проекта и, например, добавить авторизацию:



Создадим обычное пустое приложение без авторизации.

dotnet new web
И откроем его в Visual Studio (или вашем любимом редакторе). Если посмотреть на структуру проекта



то можно заметить, что вместо кучи стандартных nuget пакетов, сейчас добавлен лишь один — Microsoft.AspNetCore.All, который является неким контейнером всего. Это очень удобно во время разработки, так как нет надобности постоянно проверять, подключен ли пакет что нам нужен, искать как он сегодня называется и т.д.

Если запустить проект, результатом будет фраза «Hello World!» в браузере.
GitHub Чек-поинт 0

Настраиваем MVC


Большинство ASP.NET проектов пишутся с помощью набора библиотек ASP.NET MVC, так как они добавляют значительную гибкость при разработке. Начнем с того, что добавим папку Controllers в проект и попробуем добавить новый контроллер из контекстного меню.



В отличии от предыдущих версий, теперь при первом добавлении контроллера появляется диалог:



Поскольку мы впервые попробовали добавить элемент по шаблону(scaffold) Visual Studio предлагает нам настроить шаблонизацию. Выберем минимальные зависимости для того, чтобы лучше контролировать что происходит с кодом. После автоматической настройки шаблонизатора нам подсказывают как добавить MVC в проект. Воспользуемся подсказкой и модифицируем класс Startup.cs
GitHub Чек-поинт 1

При запуске проекта, получаем в ответ 404, потому что маршрут по умолчанию ищет контроллер Home и метод Index внутри него. Добавим стартовую страницу, создав контроллер Home и представление в новой папке Views.
GitHub Чек-поинт 2

Добавляем базу данных


Как было сказано выше: структурные единицы нашей игры — это комнаты. Добавим класс, что будет отвечать за предоставление данных о комнате. Для начала ограничимся следующими данными:

namespace TheRooms.Models
{
    public class Room
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Task { get; set; }
        public string Answer { get; set; }

        [InverseProperty("RoomTo")]
        public ICollection<Door> DoorsIn { get; set; }

        [InverseProperty("RoomFrom")]
        public ICollection<Door> DoorsOut { get; set; }
    }
}


Для перехода между комнатами опишем класс дверь:
namespace TheRooms.Models
{
    public class Door
    {
        public int Id { get; set; }

        [ForeignKey("RoomFrom")]
        public int RoomFromId { get; set; }
        public Room RoomFrom { get; set; }

        [ForeignKey("RoomTo")]
        public int RoomToId { get; set; }
        public Room RoomTo { get; set; }
    }
}

В классе Door мы используем атрибуты ForeignKey, которые подсказывают зависимости между дверьми и комнатами. В классе Room добавлены атрибуты InverseProperty, которые так же показывают к какому свойству другой сущности относится эта коллекция. InverseProperty нужен только в случае нескольких «похожих» отношений (в данном случае у комнаты есть два типа дверей — для входа в комнату и для выхода).
GitHub Чек-поинт 3

Для работы с базой данных попробуем Entity Framework Core. Для этого нам надо добавить контекст данных (связь между кодом и базой).

using Microsoft.EntityFrameworkCore;
using TheRooms.Models;

namespace TheRooms.Data
{
    public class DataContext : DbContext
    {
        public DbSet<Room> Rooms { get; set; }
        public DbSet<Door> Doors { get; set; }

        public DataContext(DbContextOptions<DataContext> options) : base(options)
        {
        }

        protected override void OnModelCreating(ModelBuilder builder)
        {
            base.OnModelCreating(builder);

            // disable cascade delete
            foreach (var relationship in builder.Model.GetEntityTypes().SelectMany(e => e.GetForeignKeys()))
            {
                relationship.DeleteBehavior = DeleteBehavior.Restrict;
            }
        }
    }
}

А так же добавим файл настроек со строкой подключения к базе данных и свяжем его с контекстом в методе ConfigureServices.

services.AddDbContext<DataContext>(options =>
                options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

GitHub Чек-поинт 4

Следующим шагом создадим саму базу из классов, что мы описали выше. Для этого нужно выполнить 2 команды в Package Manger Console:

Add-Migration Initial
Update-Database


Первая команда добавит код для миграции базы данных из предыдущего состояния (когда её не существовало) до последнего состояния (где у нас есть 2 таблицы — Rooms и Doors). Соответственно, вторая команда обновит базу данных с помощью скриптов миграций.
GitHub Чек-поинт 5
База данных готова.

Показываем комнату


Для того, чтобы показать комнату, надо, чтобы контроллер вытянул детали комнаты из базы и передал их на представление. Начнем с контроллера. Cоздадим новый класс — RoomsController с методом, который будет доставать нужные данные и отправлять в браузер.

public async Task<IActionResult> Show(int id)
        {
            var room = await _context.Rooms.SingleAsync(r => r.Id == id);
            return View(room);
        }

GitHub Чек-поинт 6

Но для того, чтобы зайти в комнату, нужно сначала её создать. Добавим контроллеры для управления комнатами и дверьми с помощью шаблонизатора (scaffolding):





GitHub Чек-поинт 7

Добавляем стили, кнопочки, надписи.
GitHub Чек-поинт 8

У нас готов некий прототип, теперь надо наполнить его жизнью.

Описываем игроков


Каждый пользователь нашего сайта должен быть уникальным образом идентифицирован. Например, для того, чтобы знать кто какие комнаты уже прошел и может двигаться дальше. Для того, чтобы запоминать игроков, создадим класс Player и будем добавлять уникальный идентификатор в Cookies для каждого игрока. К нему в придачу, добавим сущность CompletedRooms, где будем хранить информацию об уже пройденных комнатах.

Для того, чтобы эти классы можно было использовать, их также надо добавить в контекст данных и добавить миграцию для нашей базы.
GitHub Чек-поинт 8

Добавим логику для проверки пользователя.
GitHub Чек-поинт 9

Ну и несколько мелочей для того, чтобы все это выглядело не совсем страшно. Первая версия игры готова. К сожалению корованы грабить пока нельзя.

Выводы


Как и ожидалось ASP.NET Core 2 отлично справился с заданием. Конечно полноценной игрой это назвать сложно и хочется еще проверить возможности интерактивности и взаимодействий в реальном времени. Но, похоже что современные веб фреймворки уже очень близко к тому рубежу где не так уж важно какая тематика проекта. Можно заметить что с новыми версиями Visual Studio во время разработки появляется все больше диалогов, которые автоматически генерируют код. Уже сейчас это используется для создания проекта, настройки шаблонизатора, автоматического создания «админки». Этот подход может со временем эволюционировать все больше и можно будет кодить мышкой.

ДЕМО
Исходники

Комментарии (12)


  1. Lure_of_Chaos
    01.09.2017 09:42
    +1

    Наш игровой мир состоит из множества комнат, в каждой из них нас ждет специальное задание, выполнив которое можно перейти в следующую комнату.

    Собственно, самое сложное — задания и их реализация — «вышли за рамки данной статьи», хнык :(


    1. Gbdrm Автор
      01.09.2017 10:14

      На данный момент задания довольно просты, в формате вопрос-ответ. Реализация так же элементарна, можно посмотреть в методе Submit
      github.com/gbdrm/TheRooms/blob/master/Controllers/RoomsController.cs#L53
      и следующим за ним методе проверки правильности ответа.


      1. Lure_of_Chaos
        01.09.2017 10:18

        Планируете добавить комнаты посложнее, например, миниигры типа connect-all, и всё такое?


        1. Gbdrm Автор
          01.09.2017 13:14

          Да, возможно что-то попроще для начала


  1. AliasVeter
    01.09.2017 10:09

    Спасибо за квест. Было интересно.


  1. try1975
    01.09.2017 10:09

    Мне понравилось, заодно и core 2 поставил и powershell 3


  1. LifeAct
    01.09.2017 15:31

    Полезно и не скучно, ждём продолжений. Пс может влиться в интерактивный курс по core


    1. Gbdrm Автор
      01.09.2017 16:42

      Это, кстати, интересный вариант, можно попробовать запилить цепочку с вопросами по технологиям.


  1. LoadRunner
    01.09.2017 17:21

    Вопрос по ДЕМО
    5 комната
    Опечатки в слове нет? Это намёк на разгадку?


    1. Gbdrm Автор
      01.09.2017 18:01

      В пятой комнате все что нужно для разгадки уже в комнате


      1. Gbdrm Автор
        01.09.2017 18:22

        LoadRunner Простите, в предыдущем комментарии не правильно понял вопрос. Опечатка — не часть задания, исправим, спасибо


    1. Gradarius
      01.09.2017 18:11

      +
      Вообще не плохо было бы объяснять суть вопроса