Создание простого приложения для телефона на XNA
Дополнительные материалы к занятию можно скачать здесь.
На сегодняшний день большой популярностью пользуются приложения, использующие трехмерную графику. Наиболее очевидным примером таких приложений являются игры. Мы уже давно привыкли к тому, что игры для персональных компьютеров потрясают нас реалистичной трехмерной графикой и красотой визуальных эффектов, в то время как игры для мобильных телефонов пока значительно уступают своим старшим собратьям в визуальном плане [27].
С развитием мобильных технологий появилась возможность помещать мощные комплектующие в миниатюрные корпуса телефонов, из-за чего современные мобильные телефоны могут неплохо справляться с задачей рендеринга достаточно сложных трехмерных сцен [27].
XNA Framework позволяет разрабатывать приложения для платформ Windows, Xbox 360 и Windows Phone 7. Причем эта технология специально создана таким образом, чтобы сделать разработку приложений под различные платформы максимально простой и удобной [27].
Следующая схема описывает принцип работы XNA Framework:
XNA Framework для Windows базируется на .NET Framework и на .NET Compact Framework для Xbox 360 и Windows Phone 7. Разработка ведется в Visual Studio 2010, для этих целей существует надстройка XNA Game Studio, которая добавляет в Visual Studio новые элементы, такие как шаблоны проектов XNA Framework [27].
На следующем рисунке показаны основные элементы XNA Framework.
XNA Framework содержит в себе элементы, которые необходимы для разработки игр, например, библиотека функций для работы с матрицами и векторами, библиотека для унифицированной работы с устройствами ввода и т.д. Более того, XNA Framework содержит дополнительные элементы (Extended Framework), которые решают многие вопросы, возникающие в процессе разработки игры [27].
Extended Framework состоит из Application Model и Content Pipeline.
Application Model - каркас приложения. Каждый новый проект XNA Game уже содержит в себе класс Game1, которые имеет набор методов, каждый из которых имеет свое предназначение. Разработчику не нужно задумываться над такими вопросами как:
Как создать игровой цикл? |
Когда обрабатывать пользовательский ввод? |
Когда формировать изображение на экране? |
Следующая схема описывается последовательность вызовов методов каркаса приложения:
Content Pipeline - средство, которое унифицирует работу с игровыми ресурсами (текстуры, модели, музыка и т.д.). Все игровые ресурсы помещаются в единое хранилище, а их обработкой занимаются заранее подготовленные импортеры. Таким образом, разработчику не нужно тратить свое время на создание классов, которые бы загружали ресурсы в игру [27].
В предлагаемом примере мы также выведем отформатированный текст на экран, но на этот раз, уже с помощью технологии XNA. Мы познакомимся с понятиями "спрайт", "игровой цикл", с методами Update, Draw.
В данной работе мы разработаем приложение XNA с анимированным текстом. За основу мы взяли пример, описанный в книге Чарльза Петзольда Programming Windows Phone 7 и немного изменили параметры шрифта.
Создаем новое приложение Windows Game: Microsoft Visual Studio 2010 Express for Windows Phone -> File -> New Project -> Windows Game(4.0).
В XNA нет встроенных шрифтов, поэтому нам потребуется его добавить: Имя проектаContent -> Правая кнопка мыши -> Add -> New Item.
Далее, выбираем пункт Sprite Font -> Name -> ComicSansMs
В результате мы получаем xml-файл, описывающий характеристики шрифта (комментарии удалены):
<?xml version="1.0" encoding="utf-8"?> <XnaContent xmlns:Graphics="Microsoft.Xna.Framework.Content.Pipeline.Graphics"> <Asset Type="Graphics:FontDescription"> <FontName>Segoe UI Mono</FontName> <Size>14</Size> <Spacing>0</Spacing> <UseKerning>true</UseKerning> <Style>Regular</Style> <CharacterRegions> <CharacterRegion> <Start> </Start> <End>~</End> </CharacterRegion> </CharacterRegions> </Asset> </XnaContent>
Заменим некоторые атрибуты шрифта. В результате получим:
<?xml version="1.0" encoding="utf-8"?> <XnaContent xmlns:Graphics="Microsoft.Xna.Framework.Content.Pipeline.Graphics"> <Asset Type="Graphics:FontDescription"> <FontName>Comic Sans Ms</FontName> <Size>32</Size> <Spacing>0</Spacing> <UseKerning>true</UseKerning> <Style>Bold</Style> <CharacterRegions> <CharacterRegion> <Start> </Start> <End>~</End> </CharacterRegion> </CharacterRegions> </Asset> </XnaContent>
После этого нам потребуется внести изменения в файл Game1.cs:
using System; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; namespace TextCrawl { public class Game1 : Microsoft.Xna.Framework.Game { const float SPEED = 0.1f; // циклов в секунду const string TEXT = "Animated Text"; GraphicsDeviceManager graphics; SpriteBatch spriteBatch; SpriteFont ComicSansMs; Viewport viewport; Vector2 textSize; Vector2 textPosition; float tCorner; // высота / периметр float tLap; float angle; public Game1() { graphics = new GraphicsDeviceManager(this); Content.RootDirectory = "Content"; // В Windows Phone стандартной является кадровая частота 30 Гц TargetElapsedTime = TimeSpan.FromTicks(333333); } protected override void Initialize() { base.Initialize(); } protected override void LoadContent() { spriteBatch = new SpriteBatch(GraphicsDevice); viewport = this.GraphicsDevice.Viewport; tCorner = 0.5f * viewport.Height / (viewport.Width + viewport.Height); ComicSansMs = this.Content.Load<SpriteFont>("ComicSansMs"); textSize = ComicSansMs.MeasureString(TEXT); } protected override void UnloadContent() { } protected override void Update(GameTime gameTime) { if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) this.Exit(); tLap = (tLap + SPEED * (float)gameTime.ElapsedGameTime.TotalSeconds) % 1; if (tLap < tCorner) // вниз по левой части экрана { textPosition.X = 0; textPosition.Y = (tLap / tCorner) * viewport.Height; angle = -MathHelper.PiOver2; if (textPosition.Y < textSize.X) angle += (float)Math.Acos(textPosition.Y / textSize.X); } else if (tLap < 0.5f) // поперек нижней части экрана { textPosition.X = ((tLap - tCorner) / (0.5f - tCorner)) * viewport.Width; textPosition.Y = viewport.Height; angle = MathHelper.Pi; if (textPosition.X < textSize.X) angle += (float)Math.Acos(textPosition.X / textSize.X); } else if (tLap < 0.5f + tCorner) // вверх по правой части экрана { textPosition.X = viewport.Width; textPosition.Y = (1 - (tLap - 0.5f) / tCorner) * viewport.Height; angle = MathHelper.PiOver2; if (textPosition.Y + textSize.X > viewport.Height) angle += (float)Math.Acos((viewport.Height - textPosition.Y) / textSize.X); } else // поперек верхней части экрана { textPosition.X = (1 - (tLap - 0.5f - tCorner) / (0.5f - tCorner)) * viewport.Width; textPosition.Y = 0; angle = 0; if (textPosition.X + textSize.X > viewport.Width) angle += (float)Math.Acos((viewport.Width - textPosition.X) / textSize.X); } base.Update(gameTime); } protected override void Draw(GameTime gameTime) { GraphicsDevice.Clear(Color.CornflowerBlue); GraphicsDevice.Clear(Color.White); spriteBatch.Begin(); spriteBatch.DrawString(ComicSansMs, TEXT, textPosition, Color.Red, angle, Vector2.Zero, 1, SpriteEffects.None, 0); spriteBatch.End(); base.Draw(gameTime); } } }Листинг .
using System; namespace TextCrawl { #if WINDOWS || XBOX static class Program { /// <summary> /// The main entry point for the application. /// </summary> static void Main(string[] args) { using (Game1 game = new Game1()) { game.Run(); } } } #endif }
Результат: