Создание приложений XNA
Презентацию к данной лекции Вы можете скачать здесь.
19.1. Основные сведения о технологии XNA
Технология XNA является библиотекой объектов C#, которая используется для создания игровых программ. XNA позволяет разработчикам игр использовать C# для создания высокопроизводительных игр для различных платформ, включая компьютеры под управлением Windows, Xbox 360 и Windows Phone. При грамотном проектировании структуры программы возможно повторное использование большой части кода для портирования игр под эти три платформы.
Игры могут быть двухмерными (2D) (изображения, представленные в одной плоскости), или трёхмерными (3D) (визуальное моделирование трёхмерной окружающей среды). XNA позволяет создавать игры обоих типов, и аппаратное ускорение Windows Phone способствует реалистичному изображению трёхмерных игровых миров. В этой лекции мы ограничимся рассмотрением 2D игр, основанных на спрайтах.
При создании проекта приложения для Windows Phone можно выбрать тип приложения: Silverlight или XNA. Visual Studio использует соответствующий шаблон и создаёт решение с необходимыми элементами для создания программы. Шаблоны для создания приложений XNA собраны в группу XNA Game Studio 4.0 в диалоговом окне Создание нового проекта. Здесь представлены шаблоны для создания игр XNA для Windows Phone и Xbox 360. Также можно использовать существующий проект XNA для одной платформы в качестве основы приложения для другой платформы.
Решение XNA похоже на решение Silverlight, но между ними есть некоторые различия. В решении XNA создаётся два проекта, из которых один предназначен для хранения игрового контента. Им управляет контент-менеджер, который предоставляет набор входных фильтров для различных типов ресурсов, например изображения PNG, звуковые файлы WAV и т.д. Эти ресурсы хранятся в проекте и являются частью игры для целевой платформы. При загрузке игры контент-менеджер загружает эти ресурсы для использования в игре. В результате, независимо от целевой платформы управление контентом выполняется одинаково.
Необходимо учитывать, что экран Windows Phone имеет меньший размер по сравнению с компьютером и платформой Xbox 360. Максимальное разрешение игры для Windows Phone составляет 800x480 пикселей. Чтобы игры XNA загружались быстрее и занимали меньше памяти, стоит изменить размеры игровых ресурсов для платформы Windows Phone.
Принципы работы XNA
Программы на основе Silverlight выполняют какие-либо действия обычно только в ответ на события, например, при нажатии на кнопку, или при завершении сетевой операции, или при загрузке новой страницы приложения.
В отличие от приложений Silverlight, программы XNA всегда выполняют какие-либо действия: обновляют игровой мир и перерисовывают экран. Вместо ожидания ввода от устройства, игра XNA проверяет устройства, в которых, возможно, пользователь выполнил ввод, и используют их, чтобы обновить игровую модель и как можно быстрее перерисовать экран. В контексте игры это имеет большое значение. В XNA игровой мир всё время обновляется вокруг игрока, а не игрок инициирует действия.
При запуске игры XNA фактически выполняются следующие действия:
- Загрузка всех необходимых для игры ресурсов. Сюда входят все звуки, текстуры и модели, необходимые для создания игровой среды.
- Периодический запуск игрового движка:
- обновление игрового мира: получение информации с контроллеров ввода, обновление состояния и положения игровых элементов;
- отрисовка игрового мира: обновление информации в игровом мире, который может быть двух- или трёхмерным в зависимости от типа игры.
Эти действия выполняются в трёх методах класса Game, который создаёт Visual Studio как часть нового проекта игры.
partial class Game1 : Microsoft.Xna.Framework.Game { protected override void LoadContent(bool loadAllContent) { } protected override void Update(GameTime gameTime) { } protected override void Draw(GameTime gameTime) { } }
При создании игры нужно добавить в эти методы программный код. Эти методы XNA автоматически вызывает во время работы игры. Метод LoadContent вызывается при запуске игры. Метод Draw вызывается настолько часто, насколько это возможно, а метод Update вызывается с частотой 30 раз в секунду, в отличие от версии игр для компьютеров и Xbox 360, где этот метод вызывается 60 раз в секунду, что позволяет уменьшить потребление электроэнергии.
Рассмотрим пример создания приложения, в котором по экрану будет перемещаться белый шар.
Игровой контент
Под словом контент понимаются все ресурсы игры: все текстуры игры, звуковые эффекты и трёхмерные модели. Система управления контентом XNA может считать элемент контента из файла в память игры, работающей на целевом устройстве, преобразовать их и использовать в игре.
Управление контентом выполняется в Visual Studio. Управление элементами контента выполняется таким же образом, как и файлами кода программы. Их можно добавить в проект и затем просмотреть их и управлять их свойствами.
В нашем примере будет использоваться изображение белого шара, которое хранится в файле WhiteDot.png. Соответственно, в рамках приложения у этого ресурса будет имя WhiteDot. Как и в приложениях Silverlight, все добавленные ресурсы будут являться частью решения Visual Studio. Однако, контент-менеджер предназначен только для игр XNA, а не для Silverlight.
Метод LoadContent вызывается для загрузки контента в игру один раз при запуске игры:
protected override void LoadContent() { // создание группы спрайтов, которая можно использовать для отрисовки текстур spriteBatch = new SpriteBatch(GraphicsDevice); }
Этот метод генерируется автоматически и создаёт новый экземпляр класса SpriteBatch, который будет использоваться для отрисовки элементов на экране. Сюда можно добавить код для загрузки изображения в игру:
Texture2D ballTexture = Content.Load<Texture2D>("WhiteDot");
Метод Load входит в состав контент-менеджера. Для него необходимо указать тип ресурса, который будет загружен (в нашем случае тип Texture2D). При этом вызывается соответствующий метод-загрузчик, который загружает текстуру в игру. Класс XNA Texture2D представляет собой двухмерную текстуру, которую можно выводить на экран.
Создание спрайтов в XNA
В компьютерных играх используется понятие "спрайт", обозначающее изображение, которое может быть отрисовано в заданном месте экрана. В XNA можно создать спрайт из текстуры, которая содержит изображение, и прямоугольника, который определяет позицию на экране.
XNA использует систему координат, в которой начало координат находится в верхнем левом углу экрана, как и во многих других графических инструментах. Соответственно, при увеличении значения координаты Y объекта он будет располагаться ниже.
В большинстве устройств Windows Phone разрешение экрана составляет 800*480 пикселей. Если попытаться вывести объекты за пределами этой области, то XNA их просто не выведет.
Для определения положения и размера области на экране в XNA используется класс Rectangle.
Rectangle ballRectangle = new Rectangle(0, 0, ballTexture.Width, ballTexture.Height);
Этот код создаёт прямоугольник в главном левом углу экрана с заданными размерами, которые совпадают с размерами текстуры шара.
Для вывода текстуры на экран используется метод Draw, который при создании проекта содержит следующий код:
protected override void Draw(GameTime gameTime) { GraphicsDevice.Clear(Color.CornflowerBlue); base.Draw(gameTime); }
Этот метод задаёт синий фон экрана. Необходимо добавить в этот метод код для вывода на экран изображение шара.
В современных устройствах есть специализированные графические аппаратные средства, которые выполняют все операции вывода изображений на экран. В Windows Phone есть графический процессор (GPU), которому нужно указать текстуры и их положение, и затем он выводит изображение на экран. Если программе нужно отобразить объект на экране, она отправляет GPU набор инструкций для отрисовки. Для достижения максимальной эффективности эти инструкции объединяются в пакет, чтобы их можно было передать GPU за одну операцию. Это делается с помощью класса SpriteBatch, который выполняет группировку инструкций:
protected override void Draw(GameTime gameTime) { GraphicsDevice.Clear(Color.CornflowerBlue); spriteBatch.Begin(); // сюда нужно добавить код для отрисовки объектов spriteBatch.End(); base.Draw(gameTime); }
Необходимо помнить, что код в методе Draw должен вызывать методы Begin и End класса SpriteBatch для начала и окончания операций отрисовки, иначе отрисовка не будет выполняться.
Для отрисовки спрайта вызывается метод Draw, которому необходимо указать текстуру, её положение на экране и оттенок, который применяется к текстуре. Если в качестве третьего параметра задать значение Color.White, то оттенок применяться не будет:
spriteBatch.Draw(ballTexture, ballRectangle, Color.White);
Полный код метода будет выглядеть так:
protected override void Draw(GameTime gameTime) { GraphicsDevice.Clear(Color.CornflowerBlue); spriteBatch.Begin(); spriteBatch.Draw(ballTexture, ballRectangle, Color.White); spriteBatch.End(); base.Draw(gameTime); }
При запуске программы шар будет выводиться в верхнем левом углу экрана телефона. При этом, по умолчанию игра XNA ожидает, что игрок будет держать телефон горизонтально, т.е. в альбомной ориентации. При необходимости игра может изменять ориентацию экрана.
В программе можно изменять положение и размер текстуры, и при этом, XNA будет масштабировать текстуру, как показано на рис. 19.1.
При создании игры важно, чтобы она выглядела одинаково, независимо от размера экрана используемого устройства. Устройства Windows Phone используют ограниченный набор разрешений, как и на компьютерах и платформе Xbox 360. Чтобы игра выглядела одинаково на каждом устройстве, она должна определять размеры экрана устройства, и в зависимости от размеров масштабировать объекты.
Игра XNA может узнать размер экрана из свойств окна просмотра, используемого графическим адаптером:
ballRectangle = new Rectangle(0, 0, GraphicsDevice.Viewport.Width / 20, GraphicsDevice.Viewport.Width / 20);
Этот код создает прямоугольную область для шара, размер которого составит 1/20 часть ширины экрана, независимо от его размера.
Обновление игрового процесса
При перемещении игровых объектов их положение на экране изменяется перед перерисовкой экрана. Положение объектов нужно обновлять в методе Update, который вызывается с частотой 30 раз в секунду во время работы игры. Для обновления положения шара можно использовать следующий код:
protected override void Update(GameTime gameTime) { ballRectangle.X++; ballRectangle.Y++; base.Update(gameTime); }
Этот метод увеличивает значения координат X и Y прямоугольника шара на один пиксель при каждом вызове. При этом, шар спускается вниз и в сторону на 30 пикселей каждую секунду. Через 15 секунд шар выходит за пределы экрана, но продолжает перемещаться и дальше.
Если нужно, чтобы шар перемещался по экрану медленнее, для задания положения шара можно использовать вещественные переменные, которые могут хранить дробные числа. При этом, перед выводом шара эти переменные необходимо преобразовать в целые числа, так как свойства, определяющие положение, имеют целочисленный тип:
float ballX; float ballY; // значения скорости шара по соответствуюзей координате float ballXSpeed = 3; float ballYSpeed = 3; // новые координаты шара ballRectangle.X = (int)(ballX + ballXSpeed); ballRectangle.Y = (int)(ballY + ballYSpeed);
В этом коде используются вещественные значения в форме с плавающей точкой, которые округляются до целых чисел.
Теперь необходимо сделать так, чтобы шар отлетал от краёв экрана. Игра должна обнаружить, когда шар достигает края экрана, и обновить направление его движения. Если шар касается края экрана в горизонтальном направлении, игра должна изменить значение скорости шара по оси X, а если шар касается верхней или нижней части экрана — значение скорости шара по оси Y. Для того чтобы шар двигался в обратном направлении, достаточно изменить знак значения скорости по соответствующей координате. Программый код, выполняющий эти действия, может выглядеть так:
if (ballX < 0 || ballX + ballRectangle.Width > GraphicsDevice.Viewport.Width) { ballXSpeed = -ballXSpeed; } if (ballY < 0 || ballY + ballRectangle.Height > GraphicsDevice.Viewport.Height) { ballYSpeed = -ballYSpeed; }