Иван Андреев

andreev. *****@***com

XNA для начинающих. Практика. Перемещение объектов в 2D пространстве

Целью данной работы является получение базовых навыков работы с 2D графикой.

Задание на работу:

Создать XNA приложение, установить размеры окна. Нарисовать в левом верхнем углу экрана спрайт произвольного размера (лучше установить достаточно большой размер). При прохождении некоторого количества времени (либо при нажатии на кнопку на клавиатуре) спрайт должен переместиться в правый верхний угол, затем в правый нижний угол, левый нижний угол и, наконец, в центр экрана, причем центр спрайта должен совпасть с центром экрана. Далее, можно либо зациклить перемещение, либо оставить спрайт в центре экрана.

Перед тем как перейти к работе следует вспомнить теоретические основы. В двумерной графике каждый пиксель характеризуется координатами и цветом. На экране монитора (а также в любом компьютерном изображении, например, картинке, созданной в Paint) началом координат является левый верхний угол, ось X направлена слева направо, а ось Y сверху вниз. Координаты пикселя отсчитываются от 0, соответственно левый верхний угол экрана имеет координаты {0,0}, а правый нижний – {MaxX-1, MaxY-1}, где MaxX, MaxY – разрешение экрана.

Для того, чтобы установить разрешение окна в XNA Framework необходимо написать следующий код:

public Game1()

{

graphics = new GraphicsDeviceManager(this);

Content. RootDirectory = "Content";

graphics. PreferredBackBufferWidth = 640;

graphics.PreferredBackBufferHeight = 480;

НЕ нашли? Не то? Что вы ищете?

}

В данном примере ширина устанавливается равной 640, а высота – 480.

Цвет пикселя составляется из трех компонент: красной, синей и зеленой (также имеется альфа-канал, который отвечает за прозрачность данного пикселя для изображений, для пикселя монитора альфа составляющая не имеет смысла). Значения цвета по каждой из этих компонент лежат в диапазоне от 0 до 255 либо от 0 до 1. Так, если значения каждой из компонент равняются 255, получается белый цвет, а если значения равняются 0, то получается черный свет.

Для работы с цветами в XNA существует класс Color, который поддерживает огромное количество стандартных цветов (например, Color. Red – красный, Color. Black - черный), а также позволяет создавать собственные цвета.

Следующий пример кода заполняет все окно приложения пикселями со случайно выбранным цветом:

using System;

using System. Collections. Generic;

using System. Linq;

using Microsoft. Xna. Framework;

using Microsoft. Xna. Framework. Audio;

using Microsoft. Xna. Framework. Content;

using Microsoft. Xna. Framework. GamerServices;

using Microsoft. Xna. Framework. Graphics;

using Microsoft. Xna. Framework. Input;

using Microsoft. Xna. Framework. Media;

using Microsoft. Xna. ;

using Microsoft. Xna. Framework. Storage;

namespace BlendModeTest

{

/// <summary>

/// This is the main type for your game

/// </summary>

public class Game1 : Microsoft. Xna. Framework. Game

{

GraphicsDeviceManager graphics;

SpriteBatch spriteBatch;

Texture2D tex;

public Game1()

{

graphics = new GraphicsDeviceManager(this);

Content. RootDirectory = "Content";

graphics. PreferredBackBufferWidth = 640;

graphics. PreferredBackBufferHeight = 480;

}

/// <summary>

/// Allows the game to perform any initialization it needs to before starting to run.

/// This is where it can query for any required services and load any non-graphic

/// related content. Calling base. Initialize will enumerate through any components

/// and initialize them as well.

/// </summary>

protected override void Initialize()

{

// TODO: Add your initialization logic here

Color[] colors = new Color[640 * 480];

Random rand = new Random();

for (int i = 0; i < colors. Length; i++)

{

byte r = (byte)rand. Next(255);

byte g = (byte)rand. Next(255);

byte b = (byte)rand. Next(255);

colors[i] = new Color(r, g, b);

}

tex = new Texture2D(GraphicsDevice, 640, 480);

tex. SetData<Color>(colors);

base. Initialize();

}

/// <summary>

/// LoadContent will be called once per game and is the place to load

/// all of your content.

/// </summary>

protected override void LoadContent()

{

// Create a new SpriteBatch, which can be used to draw textures.

spriteBatch = new SpriteBatch(GraphicsDevice);

// TODO: use this. Content to load your game content here

}

/// <summary>

/// UnloadContent will be called once per game and is the place to unload

/// all content.

/// </summary>

protected override void UnloadContent()

{

// TODO: Unload any non ContentManager content here

}

/// <summary>

/// Allows the game to run logic such as updating the world,

/// checking for collisions, gathering input, and playing audio.

/// </summary>

/// <param name="gameTime">Provides a snapshot of timing values.</param>

protected override void Update(GameTime gameTime)

{

// Allows the game to exit

if (GamePad. GetState(PlayerIndex. One).Buttons. Back == ButtonState. Pressed)

this. Exit();

// TODO: Add your update logic here

base. Update(gameTime);

}

/// <summary>

/// This is called when the game should draw itself.

/// </summary>

/// <param name="gameTime">Provides a snapshot of timing values.</param>

protected override void Draw(GameTime gameTime)

{

GraphicsDevice. Clear(Color. CornflowerBlue);

// TODO: Add your drawing code here

spriteBatch. Begin();

spriteBatch. Draw(tex, new Vector2(0, 0), Color. White);

spriteBatch. End();

base. Draw(gameTime);

}

}

}

Результирующее изображение

Теперь вспомним основы работы с игровым временем в XNA Framework. Методы Update и Draw получают в качестве параметра единственный объект GameTime, который отвечает за игровое время.

Рассмотрим основые свойства объекта GameTime:

ElapsedGameTime

Игровое время, прошедшее с предыдущего вызова метода Draw/Update

ElapsedRealTime

Реальное время, прошедшее с предыдущего вызова метода Draw/Update

IsRunningSlowly

Если это свойство имеет значение true, то время проходящее между последовательными вызовами метода Update/Draw больше значения, указанного в TargetElapsedTime. Это означает, что игра работает медленнее, чем требуется. Если IsRunningSlowly равняется true, то стоит задуматься над оптимизацией

TotalGameTime

Игровое время, прошедшее с запуска игры

TotalRealTime

Реальное время, прошедшее с запуска игры

Для нас наиболее важными свойствами являются ElapsedGameTime и TotalGameTime. Они возвращают объект типа TimeSpan, который имеет множество различных свойств. Рассмотрим лишь наиболее важные:

Days

Целое количество дней

Hours

Целое количество часов

Milliseconds

Целое количество миллисекунд

Minutes

Целое количество минут

Seconds

Целое количество секунд

Ticks

Целое количество системных «тиков»

TotalDays

Вещественное значение дней

TotalHours

Вещественное значение часов

TotalMilliseconds

Вещественное значение миллисекунд

TotalMinutes

Вещественное значение минут

TotalSeconds

Вещественное значение секунд

Обратите внимание на то, что свойства, название которых не начинается с Total возвращают целое число, то есть, например, Days будет иметь значение 0 до тех пор пока не пройдет целый день. В то же время значение TotalDays будет постоянно увеличиваться и по прошествии дня примет значение 1.

В следующем примере кода на консоль вывода отборажаются значения всех описанных свойств. Для того, чтобы увидеть окно вывода в Visual Studio нужно выбрать в меню View пункт Output.

protected override void Update(GameTime gameTime)

{

// Allows the game to exit

if (GamePad. GetState(PlayerIndex. One).Buttons. Back == ButtonState. Pressed)

this. Exit();

// TODO: Add your update logic here

System. Diagnostics. Debug. WriteLine("Total game time: days " + gameTime. TotalGameTime. Days);

System. Diagnostics. Debug. WriteLine("Total game time: hours " + gameTime. TotalGameTime. Hours);

System. Diagnostics. Debug. WriteLine("Total game time: minutes " + gameTime. TotalGameTime. Minutes);

System. Diagnostics. Debug. WriteLine("Total game time: seconds " + gameTime. TotalGameTime. Seconds);

System. Diagnostics. Debug. WriteLine("Total game time: milliseconds " + gameTime. TotalGameTime. Milliseconds);

System. Diagnostics. Debug. WriteLine("Total game time: total days " + gameTime. TotalGameTime. TotalDays);

System. Diagnostics. Debug. WriteLine("Total game time: total hours " + gameTime. TotalGameTime. TotalHours);

System. Diagnostics. Debug. WriteLine("Total game time: total minutes " + gameTime. TotalGameTime. TotalMinutes);

System. Diagnostics. Debug. WriteLine("Total game time: total seconds " + gameTime. TotalGameTime. TotalSeconds);

System. Diagnostics. Debug. WriteLine("Total game time: total milliseconds " + gameTime. TotalGameTime. TotalMilliseconds);

System. Diagnostics. Debug. WriteLine("Elapsed game time: days " + gameTime. ElapsedGameTime. Days);

System. Diagnostics. Debug. WriteLine("Elapsed game time: hours " + gameTime. ElapsedGameTime. Hours);

System. Diagnostics. Debug. WriteLine("Elapsed game time: minutes " + gameTime. ElapsedGameTime. Minutes);

System. Diagnostics. Debug. WriteLine("Elapsed game time: seconds " + gameTime. ElapsedGameTime. Seconds);

System. Diagnostics. Debug. WriteLine("Elapsed game time: milliseconds " + gameTime. ElapsedGameTime. Milliseconds);

System. Diagnostics. Debug. WriteLine("Elapsed game time: total days " + gameTime. ElapsedGameTime. TotalDays);

System. Diagnostics. Debug. WriteLine("Elapsed game time: total hours " + gameTime. ElapsedGameTime. TotalHours);

System. Diagnostics. Debug. WriteLine("Elapsed game time: total minutes " + gameTime. ElapsedGameTime. TotalMinutes);

System. Diagnostics. Debug. WriteLine("Elapsed game time: total seconds " + gameTime. ElapsedGameTime. TotalSeconds);

System. Diagnostics. Debug. WriteLine("Elapsed game time: total milliseconds " + gameTime. ElapsedGameTime. TotalMilliseconds);

base. Update(gameTime);

}

При запуске приложения в окне вывода появляются записи о текущем состоянии игрового времени, в следующем фрагменте приведена часть этих записей:

Total game time: days 0

Total game time: hours 0

Total game time: minutes 0

Total game time: seconds 0

Total game time: milliseconds 0

Total game time: total days 0

Total game time: total hours 0

Total game time: total minutes 0

Total game time: total seconds 0

Total game time: total milliseconds 0

Elapsed game time: days 0

Elapsed game time: hours 0

Elapsed game time: minutes 0

Elapsed game time: seconds 0

Elapsed game time: milliseconds 0

Elapsed game time: total days 0

Elapsed game time: total hours 0

Elapsed game time: total minutes 0

Elapsed game time: total seconds 0

Elapsed game time: total milliseconds 0

Total game time: days 0

Total game time: hours 0

Total game time: minutes 0

Total game time: seconds 0

Total game time: milliseconds 0

Total game time: total days 0

Total game time: total hours 0

Total game time: total minutes 0

Total game time: total seconds 0

Total game time: total milliseconds 0

Elapsed game time: days 0

Elapsed game time: hours 0

Elapsed game time: minutes 0

Elapsed game time: seconds 0

Elapsed game time: milliseconds 16

Elapsed game time: total days 1,9290162037037E-07

Elapsed game time: total hours 4,62963888888889E-06

Elapsed game time: total minutes 0,000277778333333333

Elapsed game time: total seconds 0,0166667

Elapsed game time: total milliseconds 16,6667

Total game time: days 0

Total game time: hours 0

Total game time: minutes 0

Total game time: seconds 0

Total game time: milliseconds 16

Total game time: total days 1,9290162037037E-07

Total game time: total hours 4,62963888888889E-06

Total game time: total minutes 0,000277778333333333

Total game time: total seconds 0,0166667

Total game time: total milliseconds 16,6667

Elapsed game time: days 0

Elapsed game time: hours 0

Elapsed game time: minutes 0

Elapsed game time: seconds 0

Elapsed game time: milliseconds 16

Elapsed game time: total days 1,9290162037037E-07

Elapsed game time: total hours 4,62963888888889E-06

Elapsed game time: total minutes 0,000277778333333333

Elapsed game time: total seconds 0,0166667

Elapsed game time: total milliseconds 16,6667

Total game time: days 0

Total game time: hours 0

Total game time: minutes 0

Total game time: seconds 0

Total game time: milliseconds 33

Total game time: total days 3,85803240740741E-07

Total game time: total hours 9,25927777777778E-06

Total game time: total minutes 0,000555556666666667

Total game time: total seconds 0,0333334

Total game time: total milliseconds 33,3334

Elapsed game time: days 0

Elapsed game time: hours 0

Elapsed game time: minutes 0

Elapsed game time: seconds 0

Elapsed game time: milliseconds 16

Elapsed game time: total days 1,9290162037037E-07

Elapsed game time: total hours 4,62963888888889E-06

Elapsed game time: total minutes 0,000277778333333333

Elapsed game time: total seconds 0,0166667

Elapsed game time: total milliseconds 16,6667

Total game time: days 0

Total game time: hours 0

Total game time: minutes 0

Total game time: seconds 0

Total game time: milliseconds 50

Total game time: total days 5,78704861111111E-07

Total game time: total hours 1,38889166666667E-05

Total game time: total minutes 0,000833335

Total game time: total seconds 0,0500001

Total game time: total milliseconds 50,0001

Elapsed game time: days 0

Elapsed game time: hours 0

Elapsed game time: minutes 0

Elapsed game time: seconds 0

Elapsed game time: milliseconds 16

Elapsed game time: total days 1,9290162037037E-07

Elapsed game time: total hours 4,62963888888889E-06

Elapsed game time: total minutes 0,000277778333333333

Elapsed game time: total seconds 0,0166667

Elapsed game time: total milliseconds 16,6667