Опубликован: 01.11.2011 | Доступ: свободный | Студентов: 1424 / 63 | Оценка: 3.84 / 3.44 | Длительность: 15:38:00
Специальности: Программист
Практическая работа 7:

Создание простого приложения для телефона на XNA

Аннотация: В предлагаемом примере мы также выведем отформатированный текст на экран, но на этот раз, уже с помощью технологии XNA. Мы познакомимся с понятиями "спрайт", "игровой цикл", с методами Update, Draw.

Дополнительные материалы к занятию можно скачать здесь.

На сегодняшний день большой популярностью пользуются приложения, использующие трехмерную графику. Наиболее очевидным примером таких приложений являются игры. Мы уже давно привыкли к тому, что игры для персональных компьютеров потрясают нас реалистичной трехмерной графикой и красотой визуальных эффектов, в то время как игры для мобильных телефонов пока значительно уступают своим старшим собратьям в визуальном плане [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>&#32;</Start>
        <End>&#126;</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>&#32;</Start>
        <End>&#126;</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);
        }
    }
}
    
Листинг .

И в файл Program.cs:

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
}
    

Результат: