Настало время добавить на экран движений. В этом уроке рассматривается самый простой вариант анимации – движения и вращения объектов, которые сами по-себе остаются неизменяемыми, статическими. Изменениям подвергаются только объекты Место, к которым эти 3D-объекты присоединены.
Мы заставим игрушечный самолётик двигаться на экране по окружности. Он состоит из двух объектов: собственно корпуса самолёта с крыльями и, отдельным объектом, винта. Каждый из этих объектов будет присоединён к своему Месту, и каждое из них будет двигаться по-своему.
Создайте новый пустой файл scena.d вместо того, что мы использовали в предыдущих уроках. Небольшую часть оттуда мы здесь почти повторим, но и её проще вписать заново, чем разбираться, что удалить, а что исправить.
Добавим в модуль необходимые импорты:
import std.math, std.conv; import ddd, ddd.mesto, ddd.lamp, ddd.vector, ddd.quaternion, ddd.ddd_object;
Добавим пару констант, которые будут управлять скоростью движения самолётика и скоростью вращения его винта:
const float СКОРОСТЬ_САМОЛЁТА = 1f; const float СКОРОСТЬ_ВИНТА = 10f;
Определим переменные для хранения объектов Место, которые мы будем изменять в каждом кадре:
Место центральное_место, место_винта;
Снова создайте функцию сцена и добавьте туда код, задающий цвет фона и создающий освещение. Этот код почти целиком (за исключением координат расположения лампы и цвета фона) повторяет начало функции сцена из четвёртого урока (и последующих):
void сцена() {
менеджер.визуализатор.задать_цвет_фона([0.5, 0.8, 1, 1]); // Голубой цвет
auto лампа0 = new Лампа("свет0", 0);
лампа0.задать_диффузный_свет([1,1,1,1]); // Белый цвет
auto место_лампы0 = менеджер.начальное_место.создать_ребёнка("Место лампы0",
Вектор3(2,2,6),
Кватернион.НОЛЬ);
место_лампы0.присоединить_объект(лампа0);
}
Создадим объект Места, которое будет родительским по отношению к местам самолётика и (косвенно) винта, будет участвовать в движении этих объектов, но к нему самому мы 3D-объекты крепить не будем:
центральное_место = менеджер.начальное_место.создать_ребёнка("Центральное место", Вектор3(0, 0, 1), Кватернион(0, Вектор3(0, 0, 1)));
Это центральное_место будет центром всей сцены, и именно оно будет задавать общее вращение всей сцене.
Теперь приступим к рисованию самолёта.
Получим объект самолётика из ресурсов:
auto объект_самолётик = менеджер.получить_объект("самолётик");
Создадим объект Места, к которому будет крепиться самолётик:
auto место_самолётика = центральное_место.создать_ребёнка("Место самолётика", Вектор3(0, -1, 0), Кватернион(-PI/2, Вектор3(0, 1, 0)));
Передаваемые в конструктор координаты задают сдвиг от центра на одну единицу расстояния по координате Y (вниз, т. к. стоит -1). Кроме того, задаётся поворот на 90 градусов вокруг вертикальной оси, т. к. меш самолёта смоделирован с видом «сзади», а нам сейчас нужен вид «сбоку».
Осталось присоединить полученный объект к Месту:
место_самолётика.присоединить_объект(объект_самолётик);
Теперь проделаем всё тоже самое для объекта винта, родительским для его Места будет только что созданное Место самолётика:
auto объект_винт = менеджер.получить_объект("винт самолётика"); место_винта = место_самолётика.создать_ребёнка("Место винта", Вектор3(0, 0, 0), Кватернион.НОЛЬ); место_винта.присоединить_объект(объект_винт);
В данный момент мы здесь не делаем никаких сдвигов и поворотов относительно родительского Места.
Теперь, если вы скомпилируете и запустите ваше приложение, то должны получить такую картинку с готовым к старту самолётиком:
Чтобы заставить его двигаться, создайте в модуле scena.d новую функцию обновление_сцены с одним аргументом длительность_кадра типа float. Она будет вызываться каждый кадр, в её аргументе будет находиться время, прошедшее после предыдущего кадра в секундах (обычно это число сильно меньше единицы).
void обновление_сцены(float длительность_кадра) { }
Внутрь этой функции добавьте команды, которые будут задавать поворот объектов центральное_место и место_винта вокруг их локальной оси Z:
центральное_место.крен(длительность_кадра * СКОРОСТЬ_САМОЛЁТА); место_винта.крен(длительность_кадра * СКОРОСТЬ_ВИНТА);
Осталось последнее действие – мы должны указать менеджеру DDD, что наша новая функция является функцией обновления сцены. Откройте модуль urok.d и вставьте такую команду перед вызовом функции запустить_визуализацию:
менеджер.задать_функцию_обновления_сцены(&обновление_сцены);
Если вы все сделали правильно, то после компиляции в окне вашей программы самолётик должен двигаться по круговой орбите вокруг центра окна, а его винт самостоятельно вращаться:
Вы можете попробовать поизменять значение констант, определённых в шаге 2, и это должно влиять на скорость движения самолётика и скорость вращения его винта. Если вы не пропускали шестой урок про настройки программы, то можете попробовать преобразовать эти константы в настройки, чтобы можно было влиять на эти две скорости без перекомпиляции программы.