Экономическая стратегия «Сахалинская колония»

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





Когда-то давно, мне очень нравилась экономическая стратегия «Сахалинская колония» Григория Жмулевского. Сейчас именно с нее я решил написать свою первую доведенную до конца игру, и заодно изучить различные аспекты C#. Получив от автора лаконичное «Конечно» на вопрос о копировании его игры, я приступил к работе.
Исходники на C доступны на сайте автора, и я обращался к ним для копирования данных объектов — стоимость, сколько объект живет, в каких ситуациях разрушается сильнее или слабее и т.п. В остальном я старался полагаться только на себя.
Вместе с хромом размер оригинала — 640Х480. Я выбрал те же размеры приложения, но без хрома. За счет этого, а так же более оптимального использования пространства удалось увеличить размер ячейки карты на 2 пикселя. Немного, но тоже хорошо. 
Внутренняя логика игры сохранена почти полностью. Добавлена краткая справка.

Краткая информация о ходе разработки.

Общее
Делать игру было решено на XNA в частности потому что для него у меня уже были наработки по gui.
Для реализации была выбрана довольно простая архитектура:
Игровые классы без использования специфических XNA классов, для простоты возможного порта на другой движок в будущем:
  • Класс игры со ссылкой на карту
  • Класс карты со ссылкой на массив ячеек
  • Ячейка со своими данными и ссылкой на строение
  • Строение со своими данными и индексом ячейки
  • Статичный класс содержащий все неизменные данные, в т.ч. перечисления.

Xna класс Game:
  • В update() — открытие / закрытие диалоговых форм, вызов update контролов.
  • В draw() — отрисовка игровых элементов, вызов draw контролов.

Класс event_handlers:
  • Класс-прослойка между Game и игровыми классами. Вызов игровых методов осуществляется только через него. Опять же для простоты возможного порта на другой движок. В нем же — работа с потоками.

Класс xml:
  • Работа по сохранению, чтению данных.


Сериализация
Сериализация в теории могла помочь отказаться от громоздкого класса сохранения / чтения данных с использованием XmlDocument.
Однако на практике при внедрении функционала сериализации я столкнулся с рядом задач без которых она не могла работать.
В частности пришлось большую часть статичных классов сделать публичными. В итоге получился статичный класс верхнего уровня, содержащий ссылку на публичный класс игры. Данный подход позволил с одной стороны сохранить простоту обращения к необходимым данным, с другой — использовать сериализацию. Во время программирования и промежуточных тестов я столкнулся со странным поведением программы при открытии и сохранении данных — на комьютере разработки все работало, но на другом игра все время вылетала на сериализации. Добавив в игру конструкции try catch удалось получить и вывести информацию о ошибках в файл. Выяснилось что сериализатор (только!) на клиентском компьютере не мог разобрать некие статичные классы. Выяснилось что проблема в полях — перечислениях, которые объявлены во вспомогательном статичном классе. После долгих поисков мне посоветовали исключить их из сериализации атрибутом [XmlIgnore]. Тем не менее эти поля необходимы в логике, поэтому было принято решение дублировать их в строковые поля, и после чтения xml сразу парсить строковое представление в соответствующее перечисление. Это сработало.

Контент
Поначалу я планировал заполнить игру изображениями с пометкой free из интернета, т.к. сам никогда рисовать не умел, однако поиски подходящих картинок 
оказались на удивление сложными. В итоге попробовав нарисовать иконки самостоятельно я увидел что получается нормально (на мой взгляд), и по времени быстрее чем искать их в интернете. На данный момент в игре лишь три картинки из интернета — деньги, еда, золото. Остальные нарисованы в пайнте. Постобработки в более серьезном редакторе довольно мало. Все иконки земли и строений по факту вдвое больше чем отображаются в игре — так их было проще рисовать. К тому же иконки такого размера проще будет использовать в дальнейшем. Уменьшать проще чем увеличивать.



Текстурные карты
Изначально весь графический контент был разбит — каждой кнопке один файл. Причем встроенный механизм контента XNA не использовался — все текстуры загружались в игру стандартным для C# способом и затем конвертировались в Texture2d через Stream. Хранились текстуры в именованном массиве. Большое количество файлов и сложности с публикацией заставили задуматься о текстурных картах. Собрав (почти) все 
текстуры в карты удалось уменьшить потребление памяти приложением почти на 10 мегабайт (Значение колонки «выделенная память» в диспетчере уменьшалось с 69 до 60 мб). Именованный массив так же был заменен на n отдельных переменных.

Интерфейс
К сожалению в XNA нет своего графического интерфейса. Подключение win form или wpf накладывает свои ограничения. Т.к. одна из целей проекта — обучение программированию в C# в целом и конкретно в игровой среде, было принято решение вспомнить относительно старый велосипед — гуи под XNA.
Изначально этот гуи задумывался как очень мощный механизм — конструктор интерфейсов. Его мощь обратилась огромными блоками кода с трудно находимыми ошибками и медленной работой. Пришлось обрезать очень много кода, упростить работу, сократить количество вызовов вспомогательных функций в update.
Так же был написан контрол edit — принимающий только цифры, десятичную точку, знаки плюс и минус (исключая плюс и минус на дополнительной клавиатуре — не нашел их в списке клавиш XNA). Средствами гуи при необходимости происходит создание дополнительных текстур — нажатия, наведения, недоступного состояния. Получился небольшой, но вполне рабочий gui.



Потоки
Приложение использует окна, в т.ч. модальные. Окна-вопросы, сообщения, а так же форма торговли, должны пересылать в программу некую информацию, которая будет обрабатываться. 
В ходе работы было найдено следующее решение: при активизации окна в отдельном потоке происходит вызов целевого метода, например ремонт строения. Идет расчет стоимости ремонта, в статичный класс вопроса передается флаг активации окна, текст самого вопроса.
Метод ремонта строения (вызванный поток) входит в цикл по флагу — признаку получению ответа пользователя. Параллельно исполнению этого цикла, в методе Update (главный поток) происходит открытие окна — диалога, исполнение gui, по нажатию пользователем клавиши да или нет происходит установка соответствующих флагов в статичном классе вопроса. Дочерний поток выходит из цикла, и продолжает исполнение метода ремонта строения ориентируясь уже на полученный ответ пользователя.
Для того что бы не порождать много параллельных потоков и экранировать другие возможные проблемы, все игровые кнопки блокируются при активации вопроса. Системные кнопки не блокируются, в частности потому что они используют стандартные диалоги windows, которые и так полностью блокируют приложение.

Приложение
Написано под win 7, требует установленных компонентов XNA, фреймворк .net 4.0 — все необходимое скачивается автоматически в процессе установки.

Exe: rusfolder.com/35736586

Setup: rusfolder.com/35736588

http://habrahabr.ru/post/174349/

YouTube Facebook G+ Twitter ВКонтакте