Невозможно пройти тесты, в окне с вопросами пусто |
Спрайтовая анимация
17.2. Анимация спрайтов
Для того, чтобы создать анимированный спрайт, нужно подготовить подходящий исходный материал. Как правило, исходные файлы для анимированных спрайтов включают в себя несколько последовательно расположенных изображений. Каждое из этих изображений представляет собой отдельный кадр анимации. Задача создания анимированных спрайтов заключается в разработке механизма, который позволит менять изображения с определенной скоростью.
Создадим спрайт, который будем анимировать. Мы использовали для анимации спрайт, состоящий из двух изображений (рис. 17.2). При его анимации будет создан эффект мигания – черный цвет будет сменяться зеленым.
Создадим стандартный игровой проект, назовем его P11_2. В листинге 17.2 приведен код класса Game1. В этом проекте мы обошлись без создания дополнительных игровых компонентов, реализовав всю необходимую функциональность в основном игровом классе.
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.Input.Touch; using Microsoft.Xna.Framework.Media; namespace P11_2 { /// <summary> /// Это главный тип игры /// </summary> public class Game1 : Microsoft.Xna.Framework.Game { GraphicsDeviceManager graphics; SpriteBatch spriteBatch; Texture2D texture; //Количество кадров в изображении const int frames = 2; //Частота анимации - кадров в секунду const int framesPerSec =10; //Текущий кадр для вывода на экран int numberOfFrame=0; //Время, в течение которого отображается один кадр float timePerFrame; //Время, которое прошло с начала отображения текущего кадра float totalElapsed; //Позиция вывода спрайта Vector2 position; //Прямоугольник для задания позиции кадра в изображении Rectangle sprRec; //Ширина кадра int widthFrame = 64; public Game1() { graphics = new GraphicsDeviceManager(this); Content.RootDirectory = "Content"; graphics.IsFullScreen = true; // Частота кадра на Windows Phone по умолчанию — 30 кадров в секунду. TargetElapsedTime = TimeSpan.FromTicks(333333); // Дополнительный заряд аккумулятора заблокирован. InactiveSleepTime = TimeSpan.FromSeconds(1); } /// <summary> /// Позволяет игре выполнить инициализацию, необходимую перед запуском. /// Здесь можно запросить нужные службы и загрузить неграфический /// контент. Вызов base.Initialize приведет к перебору всех компонентов и /// их инициализации. /// </summary> protected override void Initialize() { position = new Vector2(100, 100); //Время для одного кадра вычисляется как результат деления 1 секунды //на заданное количество кадров в секунду timePerFrame = (float)1 / framesPerSec; sprRec = new Rectangle(0, 0, 64, 64); base.Initialize(); } /// <summary> /// LoadContent будет вызываться в игре один раз; здесь загружается /// весь контент. /// </summary> protected override void LoadContent() { // Создайте новый SpriteBatch, который можно использовать для отрисовки текстур. spriteBatch = new SpriteBatch(GraphicsDevice); texture = Content.Load<Texture2D>("animation"); // ЗАДАЧА: используйте здесь this.Content для загрузки контента игры } /// <summary> /// UnloadContent будет вызываться в игре один раз; здесь выгружается /// весь контент. /// </summary> protected override void UnloadContent() { // ЗАДАЧА: выгрузите здесь весь контент, не относящийся к ContentManager } //Эта процедура используется для анимации спрайта //Она принимает количество секунд, прошедших с предыдущего вызова //процедуры Update void ChangeFrame(float elpT) { //Увеличим общее время отображения спрайта на //время, прошедшее с последнего вызова процедуры totalElapsed += elpT; //если общее время отображения спрайта больше времени, //выделенного на один спрайт if (totalElapsed > timePerFrame) { //Если номер кадра равен количеству кадров-1 if (numberOfFrame == frames-1) { //установим номер кадра в 0 numberOfFrame = 0; } //иначе увеличим номер кадра на 1 else numberOfFrame++; //создадим новый прямоугольник //Его координата X соответствует координате левого верхнего угла //кадра, Y равно 0, длина и ширина всегда равны 64 sprRec = new Rectangle((int)widthFrame * numberOfFrame, 0, 64, 64); //сбросим totalElapsed в 0 totalElapsed = 0; } } /// <summary> /// Позволяет игре запускать логику обновления мира, /// проверки столкновений, получения ввода и воспроизведения звуков. /// </summary> /// <param name="gameTime">Предоставляет моментальный снимок значений времени.</param> protected override void Update(GameTime gameTime) { // Позволяет выйти из игры if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) this.Exit(); ChangeFrame((float)gameTime.ElapsedGameTime.TotalSeconds); base.Update(gameTime); } /// <summary> /// Вызывается, когда игра отрисовывается. /// </summary> /// <param name="gameTime">Предоставляет моментальный снимок значений времени.</param> protected override void Draw(GameTime gameTime) { GraphicsDevice.Clear(Color.CornflowerBlue); spriteBatch.Begin(); spriteBatch.Draw(texture, position, sprRec, Color.White); spriteBatch.End(); base.Draw(gameTime); } } }Листинг 17.2. Код класса Game1
Если кратко описать последовательность работы этого проекта, получится следующее: в цикле Update() мы вызываем процедуру ChangeFrame(), которой передаем время, прошедшее после последнего вызова Update(). Внутри этой процедуры мы проверяем, достаточно ли времени текущий кадр отображался на экране, и если его время вышло – меняем на следующий.
Можно заметить, что здесь мы анимировали спрайт, который состоит лишь из двух кадров. Для того, чтобы анимировать спрайт, состоящий из большего количества кадров, достаточно модифицировать соответствующие параметры вышеприведенного кода.
Для применения подобного приема на практике лучше всего включить код анимации спрайтов в код игровых компонентов.
Рассмотрим анимацию фона, в частности – создание фона со скроллингом.