Создание простого приложения для телефона на 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
}
Результат:






