Раньше игры были сделаны так, чтобы анимировать графику основываясь на обработке каждого кадра. Для того чтобы анимация все время выполнялась на одной и той же скорости, эти игры иногда ограничивали количество кадров, обрабатываемых в секунду. Конечно, старые игры были сделаны для компьютеров, которые не могли обрабатывать более 20-30 кадров в секунду, так что было разумно предполагать, что ограничение кадров никогда не будет превосходить 20 или 30 в секунду.
Но это было тогда, а сейчас есть сейчас. Современные компьютеры могут бегать кругами вокруг своих предшественников, и ограничение количества кадров для управления анимацией определенно устарело. Вам необходимо основываться на скорости анимации, на количестве времени, которое прошло с момента начала анимации. Реализовать это не составляет никакого труда, т. к. вы уже знаете, как записывать время начала анимации. Кроме того, для каждого обновляемого кадра вы можете считывать текущее время и вычитать начало анимации. Полученное время является смещением в анимации.
Предположим, вы используете ключевые кадры, основанные на синхронизации по времени, для вашего анимационного движка. Вы можете использовать простую структуру ключевых кадров для хранения времени и матрицы преобразования, как например:
typedef struct sKeyframe { DWORD Time;
D3DMATRIX matTransformation; } sKeyframe;
Что типично для ключевых кадров, вы можете хранить массив матриц, каждая из которых ассоциирована со своим уникальным временем. Эти матрицы хранятся в хронологическом порядке, с меньшими временами вначале. Поэтому вы можете создать небольшую последовательность преобразований для ориентирования объекта во времени. (Смотри рис. 2.1).

Рис. 2.1. Ключевые кадры отображают ориентацию куба. Кадры разделены между собой 400 миллисекундами, и для определения промежуточных ориентации производится интерполяция
Для отображения ключевых кадров, показанных на рис. 2.1, я создал массив:
sKeyframe Keyframes[4] = {
{ 0, 1.00000f, 0.00000f, 0.00000f, 0.00000f, 0.00000f, 1.00000f, 0.00000f, 0.00000f, 0.00000f, 0.00000f, 1.00000f, 0.00000f, 0.00000f, 0.00000f, 0.00000f, 1.00000f; }, { 400, 0.000796f, 1.00000f, 0.00000f, 0.00000f, -1.00000f, 0.000796f, 0.00000f, 0.00000f, 0.00000f, 0.00000f, 1.00000f, 0.00000f, 50.00000f, 0.00000f, 0.00000f, 1.00000f; }, { 800, -0.99999f, 0.001593f, 0.00000f, 0.00000f,
-0.001593f, -0.99999f, 0.00000f, 0.00000f, 0.00000f, 0.00000f, 1.00000f, 0.00000f, 25.00000f, 25.00000f, 0.00000f, 1.00000f; }, { 1200, 1.00000f, 0.00000f, 0.00000f, 0.00000f,
0.00000f, 1.00000f, 0.00000f, 0.00000f,
0.00000f, 0.00000f, 1.00000f, 0.00000f,
0.00000f, 0.00000f, 0.00000f, 1.00000f; }
};
А теперь самая веселая часть. Используя методы синхронизации, о которых вы читали ранее, вы можете сохранять время начала анимации. И для каждого кадра, обновляющего анимацию, вы можете посчитать время, прошедшее с начала анимации (используя его для нахождения смещения ключевого кадра). Создайте простую функцию обновления кадров, которая будет определять используемое преобразование на основе времени, прошедшего с первого ее вызова.
void FrameUpdate( ) {
static DWORD StartTime = timeGetTime(); DWORD Elapsed = timeGetTime() - StartTime;
Имея значение прошедшего времени, вы можете просмотреть ключевые кадры для нахождения двух, в пределах которых оно лежит. Например, если текущее время 60 миллисекунд, то анимация находится между нулевым кадром (0 миллисекунд) и кадром #1 (400 миллисекунд). Быстро просмотрев ключевые кадры, используя прошедшее время, определяем какие из них использовать.
DWORD Keyframe =0 ; // Начнем с первого кадра for(DWORD i=0;i<4;i++) {
// Если время больше или равно времени ключевого кадра,
// то обновить используемый ключевой кадр
if(Time >= Keyframes[i].Time) Keyframe = i;
}
В конце цикла в переменной Keyframe будет храниться первый из двух кадров, между которыми находится анимационное время. Если Keyframe не последний ключевой кадр в массиве (в котором всего четыре ключевых кадра), то для получения второго ключевого кадра необходимо добавить 1 к Keyframe. Если же Keyframe является последним кадром в массиве, то можно использовать это же самое значение для ваших вычислений.
Намного лучшим решением является использование второй переменной для хранения значения следующего ключевого кадра. Помните, что если Keyframe является последним ключевым кадром в массиве, то новому ключу необходимо присвоить то же самое значение.
DWORD Keyframe2 = (Keyframe==3) ? Keyframe:Keyframe + 1;
Теперь вам необходимо, используя значения времени, вычислить скаляр на основании разности ключей и расположения ключевых кадров между ними.
DWORD TimeDiff = Keyframes[Keyframe2].Time -Keyframes[Keyframe].Time;
// Убедиьтся, что существует разница во времени // для исключения деления на 0 if(!TimeDiff) TimeDiff=1;
float Scalar = (Time -Keyframes[Keyframe].Time)/TimeDiff;
Теперь у вас есть значение скаляра (находящегося в диапазоне от 0 до 1), который используется для интерполяции ключевых матриц преобразования. Чтобы облегчить работу с матрицами преобразований, они приводятся к типу D3DXMATRIX, так что D3DX может выполнить всю работу за вас.
// Вычислить разность преобразований D3DXMATRIX matInt = \
D3DXMATRIX(Keyframes[Keyframe2].matTransformation) - \ D3DXMATRIX(Keyframes[Keyframe].matTransformation); matInt *= Scalar; // Scale the difference
// Прибавить масштабированную матрицу преобразования к матрице // первого ключевого кадра.
matInt += D3DXMATRIX(Keyframes[Keyframe].matTransformation);
На данном этапе у вас есть корректно анимированная матрица преобразования, хранимая в matInt. Для просмотра результатов вашей работы установите матрицу matInt в качестве матрицы преобразования мира и визуализируйте ваш анимированный меш.
Как вы видите, использовать анимацию, основанную на синхронизации по времени, достаточно просто. Даже если вы не используете ключевые кадры, вам все равно могут пригодиться некоторые методы работы со временем в ваших программах. После того как вы уже увидели насколько просто использовать анимацию на основе синхронизации по времени, посмотрите, как просто использовать движение на основе синхронизации по времени.
⇐Считывание времени в Windows || Оглавление || Перемещение, синхронизированное со временем⇒