Иван Андреев
andreev. *****@***com
XNA для начинающих. Практика. Основы 2Д. Работа со SpriteBatch. Масштабирование, повороты, отражения
Целью данной работы является освоение основного объекта для работы с двумерной графикой в XNA – класса SpriteBatch. В ходе работы мы рассмотрим различные преобразования над двумерным изображением, которые позволяет выполнять SpriteBatch.
Задание на работу:
Создать в графическом редакторе растровое изображение в одном из форматов, используемом в XNA Game Studio.
Отобразить нарисованное изображение в центре экрана с оригинальным размером так, чтобы центр изображения совпадал с центром экрана.
Отобразить нарисованное изображение в центре экрана с масштабом 2:1, то есть размер должен быть увеличен в два раза.
Реализовать анимацию изменения размера изображения (увеличение до определенного размера, затем уменьшение, коэффициенты масштабирования должны изменяться от 1/2 до 2).
Реализовать эффект поворота изображения относительно:
А. Левого верхнего угла изображения
Б. Центра изображения
В. Правого нижнего угла
Реализовать отражение изображения в горизонтальном и вертикальном направлениях.
Теоретическая часть:
В классе SpriteBatch имеется большое количество перегруженных методов Draw. Рассмотрим вариант вызова, содержащий наибольшее количество параметров. Такой вариант вызова позволяет задать различные параметры эффектов отображения изображений на экран:
public void Draw ( Texture2D texture, Vector2 position, Nullable<Rectangle> sourceRectangle, Color color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects effects, float layerDepth ) |
Название параметра | Значение | ||||||
texture | Ссылка на изображение, которое необходимо нарисовать | ||||||
position | Позиция изображения на экране | ||||||
sourceRectange | Участок изображения, который необходимо нарисовать. Использование этого параметра удобно, например, при работе со спрайтовой анимацией. Если нужно нарисовать изображения целиком, следует передать null | ||||||
color | Цвет для смешивания. Обычно имеет значение Color. White. | ||||||
rotation | Угол поворота изображения относительно точки вращения. Задается в радианах. | ||||||
origin | Позиция точки вращения в локальных координатах изображения. | ||||||
scale | Коэффициенты масштабирования по обеим осям | ||||||
effects | Набор эффектов, может принимать значения:
| ||||||
layerDepth | «Глубина» изображения на экране. Принимает значения от 0 (наиболее близко) до 1 (наиболее далеко). Используется лишь в некоторых режимах отображения. |
Реализация
В следующем листинге приводится реализация задания с использованием игровых состояний и обработкой пользовательского ввода.
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 Lab2
{
/// <summary>
/// This is the main type for your game
/// </summary>
public class Game1 : Microsoft. Xna. Framework. Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Texture2D sprite;
int width;
int height;
/// <summary>
/// Текущее игровое состояние
/// </summary>
int currentState = 0;
KeyboardState oldState;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content. RootDirectory = "Content";
width = graphics. PreferredBackBufferWidth = 800;
height = graphics. PreferredBackBufferHeight = 600;
}
/// <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
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
sprite = Content. Load<Texture2D>("hero");
}
/// <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
KeyboardState state = Keyboard. GetState();
if (state. IsKeyDown(Keys. Space) && oldState. IsKeyUp(Keys. Space))
{
// смена текущего игрового состояния при нажатии на пробел
// значение этой переменной изменяется от 0 до 7
currentState = (currentState + 1) % 8;
}
oldState = state;
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
if (currentState == 0)
{
spriteBatch. Begin();
// Центр изображения совпадает с центром экрана
spriteBatch. Draw(sprite, new Vector2(width / 2 - sprite. Width / 2, height / 2 - sprite. Height / 2), Color. White);
spriteBatch. End();
}
if (currentState == 1)
{
float scale = 2;
spriteBatch. Begin();
// Центр изображения совпадает с центром экрана с учетом масштаба изображения
spriteBatch. Draw(sprite, new Vector2(width / 2 - scale * sprite. Width / 2, height / 2 - (scale * sprite. Height / 2)), null, Color. White, 0, Vector2.Zero, scale, SpriteEffects. None, 0);
spriteBatch. End();
}
if (currentState == 2)
{
// Масштаб изображения меняется от 1/2 до 2 в зависимости от времени
float scale = MathHelper. Lerp(0.5f, 2, (float)Math. Abs(Math. Sin(gameTime. TotalGameTime. TotalSeconds)));
spriteBatch. Begin();
spriteBatch. Draw(sprite, new Vector2(width / 2 - (scale * sprite. Width / 2), height / 2 - (scale * sprite. Height / 2)), null, Color. White, 0, Vector2.Zero, scale, SpriteEffects. None, 0);
spriteBatch. End();
}
if (currentState == 3)
{
float scale = 2;
float rotation = (float)gameTime. TotalGameTime. TotalSeconds;
spriteBatch. Begin();
// Центр вращения совпадает с центром экрана
spriteBatch. Draw(sprite, new Vector2(width / 2, height / 2), null, Color. White, rotation, Vector2.Zero, scale, SpriteEffects. None, 0);
spriteBatch. End();
}
if (currentState == 4)
{
float scale = 2;
float rotation = (float)gameTime. TotalGameTime. TotalSeconds;
// Центр вращения изображения находится в середине изображения
Vector2 origin = new Vector2(sprite. Width/2, sprite. Height/2);
spriteBatch. Begin();
// Центр вращения совпадает с центром экрана
spriteBatch. Draw(sprite, new Vector2(width / 2, height / 2), null, Color. White, rotation, origin, scale, SpriteEffects. None, 0);
spriteBatch. End();
}
if (currentState == 5)
{
float scale = 2;
float rotation = (float)gameTime. TotalGameTime. TotalSeconds;
// Центр вращения изображения находится в правом нижнем углу изображения
Vector2 origin = new Vector2(sprite. Width, sprite. Height);
spriteBatch. Begin();
// Центр вращения совпадает с центром экрана
spriteBatch. Draw(sprite, new Vector2(width / 2, height / 2), null, Color. White, rotation, origin, scale, SpriteEffects. None, 0);
spriteBatch. End();
}
if (currentState == 6)
{
float scale = 2;
spriteBatch. Begin();
// Отражения изображения по горизонтали
spriteBatch. Draw(sprite, new Vector2(width / 2 - scale * sprite. Width / 2, height / 2 - (scale * sprite. Height / 2)), null, Color. White, 0, Vector2.Zero, scale, SpriteEffects. FlipHorizontally, 0);
spriteBatch. End();
}
if (currentState == 7)
{
float scale = 2;
spriteBatch. Begin();
// Отражения изображения по вертикали
spriteBatch. Draw(sprite, new Vector2(width / 2 - scale * sprite. Width / 2, height / 2 - (scale * sprite. Height / 2)), null, Color. White, 0, Vector2.Zero, scale, SpriteEffects. FlipVertically, 0);
spriteBatch. End();
}
base. Draw(gameTime);
}
}
}


