Для начала работы создадим простейший проект. В качестве типа проекта выберем MonoGame Windows Project, то есть создадим проект для десктопной версии Windows, чтобы проект можно было запустить и на Win 7, и на Win 8/8.1, и на Win 10.
Итак, при создании проекта как-нибудь его назовем, например, Game1:
Сразу после создания проект уже будет иметь некоторую структуру:
Во-первых, как и в любом другом приложении на C#, здесь также есть файл Program.cs, с которого начинается работа приложения. По умолчанию он выглядит следующим образом:
using System; namespace Game1 { #if WINDOWS || LINUX ////// The main class. /// public static class Program { ////// The main entry point for the application. /// [STAThread] static void Main() { using (var game = new Game1()) game.Run(); } } #endif }
Обычный класс Program с методом Main - входной точкой в программу, в котором создается объект класса Game1 и вызывается его метод Run. То есть по сути запускается игра.
Во-вторых, более важный класс - это класс Game1, который собственно и содержит всю логику игры:
using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; namespace Game1 { public class Game1 : Game { GraphicsDeviceManager graphics; SpriteBatch spriteBatch; public Game1() { graphics = new GraphicsDeviceManager(this); Content.RootDirectory = "Content"; } // Выполняет начальную инициализацию игры protected override void Initialize() { base.Initialize(); } // Загружает ресурсы игры protected override void LoadContent() { spriteBatch = new SpriteBatch(GraphicsDevice); } // Вызывается при завершении игры для выгрузки использованных ресурсов protected override void UnloadContent() { } // Обновляет состояние игры, управляет ее логикой protected override void Update(GameTime gameTime) { if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape)) Exit(); base.Update(gameTime); } // Выполняет отрисовку на экране protected override void Draw(GameTime gameTime) { GraphicsDevice.Clear(Color.CornflowerBlue); base.Draw(gameTime); } } }
Более подробно все методы, переменные и их использование мы рассмотрим далее. Но важно понимать, что это тот каркас, из которого потом будет состоять игра. Рассмотрим их пока вкратце.
Глобальная переменнная GraphicsDeviceManager graphics
позволяет получить доступ к графическому устройству компьютера, смартфона, планшета, игровой консоли.
Объект GraphicsDeviceManager является проводником между игрой и видеокартой, и вся отрисовка в игре будет проходить через этот объект.
Другой глобальный объект - SpriteBatch spriteBatch
служит для отрисовки спрайтов - изображений, которые используются в игре.
В конструкторе класса Game1 и методе Initialize
происходит начальная инициализации используемых переменных и объектов.
Метод LoadContent
предназначен для загрузки ресурсов, которые применяются в игре - аудиофайлов, файлов изображений и так далее. Метод
UnloadContent()
, наоборот, предназначен для выгрузки и освобождения ресурсов.
Методы Update()
и Draw()
представляют игровой цикл. Большинство игр построенны вокруг игрового цикла, когда
с некоторой периодичностью (например, 60 раз в секунду) вызывается перерисовка и какие-то вычисления. За счет этого возникае иллюзия движения персонажей,
каких-то других событий в игре. Оба метода принимают в качестве параметра объект GameTime
- он хранит вемя, прошедшее с начала игры.
Метод Update()
отвечает за логику игры, производит вычисления: обновляет позиции персонажей и так далее. По умолчанию
все его действие сводится к проверке нажатой пользователем клавишы:
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape)) Exit();
Если пользователь нажал кнопку Back на геймпаде или клавишу Esc на кливиатуре, то срабатывает метод Exit()
.
Метод Draw()
выполняет перерисовку экрана. Например, в методе Update обновляется позиция персонажа, а в методе Draw() происходит перерисовка персонажа
на основе новой позиции. При этом важно учитывать, что все вычисления должны находиться в методе Update. Задача метода Draw - только перерисовка.
По умолчанию в методе Draw()
прописана лишь заливка фона экрана синим цветом (точнее цветом Color.CornflowerBlue
):
protected override void Draw(GameTime gameTime) { // заливка фона GraphicsDevice.Clear(Color.CornflowerBlue); base.Draw(gameTime); }
Метод GraphicsDevice.Clear()
очищает экран, закрашивая его определенным цветом.
И еще в проекте находится папка Content, которая предназначена для хранения ресурсов игры - файлов аудио, изображений, моделей и так далее. Здесь по умолчанию имеется только файл Content.mgcb, который служит для построения ресурсов в приложении.
Вобщем вся необходимая структура проекта у нас уже есть, хоть он фактически ничего и не делает, и мы можем его запустить. При запуске проекта для декстопной версии Windows для DirectX может возникнуть ошибка:
Так как данный тип проекта для обработки пользовательского ввода требует файл xinput1_3.dll, а в DirectX 11, который по умолчанию встроен в Windows 8.1, данный файл отсутствует, за ввод пользователя отвечают другие файлы, то поэтому мы можем получить ошибку. Чтобы ее исправить, мы можем загрузить DirectX 9 с официфльного сайта: www.microsoft.com/en-us/download/details.aspx?id=35
После установки DirectX 9 и посторного запуска приложения мы увидим синий фон, поскольку никакой другой логики отрисовки в методе Draw на даный момент не происходит:
И после компиляции в папке проекта в каталоге bin\Windows\Debug (если мы скомпилировали проект в режиме отладки) мы увидим файл Game1.exe, который будет представлять игру, и который мы можем переносить на другие компьютеры и запускать.
Это было вводное первое приложение, структура других типов проектов для MonoGame будет отличаться, где-то больше файлов, но суть или каркас останется тем же - есть класс Program, который запускает класс игры Game, и в этом классе определены те методы, которые мы выше рассматривали.
И теперь мы можем перейти к более подробному изучению платформы.