Пермещение по сферической поверхности (2 стр)
Автор: Александр Здрогов
Текст программы
Теперь, когда все пояснения сделаны, пора перейти к тексту самой программы. Предполагается, что все настройки среды программирования уже сделаны, указаны все пути.
#include <irrlicht.h> #include <deque> using namespace std; using namespace irr; #pragma comment(lib, "Irrlicht.lib") typedef core::vector3df vec; // Переопределяем тип, чтобы попроще было писать #define SPHERE_RADIUS 10 // Радиус планеты #define OBJECT 10 // Количество объектов scene::IAnimatedMeshSceneNode* sphere = 0; // Меш планеты scene::IAnimatedMeshSceneNode* sphere2 = 0; // Меш спутника IrrlichtDevice* device = 0; video::IVideoDriver* driver; scene::ISceneManager* smgr; irr::scene::IBillboardSceneNode *sun; // Билбоард солнца #define DEG ( 3.14/180) // константа для перевода из градусов в радианы и наоборот
Тут вопросов не должно возникнуть, просто добавляем библиотеки, создаем переменные. Далее создадим класс нашего объектика
class Object { public: scene::ISceneNode* node; // Меш самого объекта scene::ISceneNode* cSys; // Корневая нода, которая определяет положение объекта Object() { cSys = smgr->addEmptySceneNode( ); node = smgr->addAnimatedMeshSceneNode( smgr->getMesh( "obj1.3ds")); node->setMaterialTexture( 0, driver->getTexture( "tex1.jpg")); node->setMaterialFlag( video::EMF_LIGHTING, false); node->setPosition( vec( 0,SPHERE_RADIUS,0)); cSys->addChild( node); cSys->setRotation( vec( rand( )%360,rand( )%360,rand( )%360)); } };
Об этом уже было подробно расписано выше. Создаем пустую ноду, создаем ноду с мешем объекта, к пустой ноде приделываем ноду с объектом. Ноде с мешем задаем координаты. А пустой ноде задаем случайную ориентацию.
Далее создаем класс камеры, в которой опишем все создаваемые ноды и обработку перемещений камеры.
class Camera { public: float x, y, xt, yt, z, zt; scene::ICameraSceneNode *node; scene::ISceneNode *cSys, *target; core::matrix4 mat; vec pos; Camera() { x = 0; y = 0; z = 0; xt = 0; yt = 0; zt = 0; node = smgr->addCameraSceneNode( NULL, vec( 0,15,-2), vec( 0,0,0)); cSys = smgr->addEmptySceneNode( ); target = smgr->addEmptySceneNode( ); target->setPosition( vec( 0, 10, 3)); cSys->addChild( node); cSys->addChild( target); mat.makeIdentity( ); } void move( ) { vec v; core::matrix4 m; x+=xt; y+=yt; z+=zt; x*=0.99f; y*=0.99f; z*=0.99f; m.setRotationDegrees( vec( x,0,0)); mat *= m; m.setRotationDegrees( vec( 0,y,0)); mat *= m; m.setRotationDegrees( vec( 0,0,z)); mat *= m; v = mat.getRotationDegrees( ); cSys->setRotation( v); pos = target->getAbsolutePosition( ); node->setUpVector( pos); node->setTarget( pos); } };
Переменная mat – это наша самая главная матрица, которая хранит положение нашей камеры, а точнее ориентацию корневой ноды.
Переменные xt, yt, zt - это что-то вроде ускорения в определенном направлении. Они равны чему-то если соответствующая клавиша нажата и равны 0 если отпущена. Переменные x, y, z - это текущая скорость. Конструкция типа
x*=0.99f;
введена для того, чтобы создать эффект инерции. Далее следует
m.setRotationDegrees(vec(x,0,0));
mat *= m;
Здесь мы создаем матрицу поворота вокруг определенной оси и умножаем нашу самую главную матрицу на только что созданную.
v = mat.getRotationDegrees();
cSys->setRotation(v);
В этом фрагменте мы преобразуем нашу супер-матрицу в углы Эйлера и задаем ориентацию корневой ноды с помощью этих углов. Все это делается для потому, что в IrrLicht нельзя задать ориентацию объекта непосредственно из матрицы (во всяком случае я не нашел такой функции). Вот и приходится делать одно лишнее преобразование.
pos = target->getAbsolutePosition();
node->setUpVector(pos);
node->setTarget(pos);
Об этом уже было сказано выше. Мы определяем глобальные координаты целевой ноды, и задаем этот вектор в качестве цели для камеры. Затем задаем вертикальный вектор для камеры, для чего идеально подходит тот же самый вектор pos.
Что происходит в конструкторе поясню вкратце. Создаем ноду камеры, корневую пустую ноду, и пустую ноду цели. Ноду камеры и ноду цели прикрепляем к корневой пустой ноде. Задаем им координаты.
class MyEventReceiver : public IEventReceiver { public: Camera *camera; MyEventReceiver() { camera = NULL; } void init( Camera *c) { camera = c; } virtual bool OnEvent( SEvent event) { if( event.EventType == EET_KEY_INPUT_EVENT) if( event.KeyInput.PressedDown) switch( event.KeyInput.Key) { case KEY_KEY_W: camera->xt=.0009f; break; case KEY_KEY_S: camera->xt=-.0006f; break; case KEY_KEY_Q: camera->zt=.0009f; break; case KEY_KEY_E: camera->zt=-.0006f; break; case KEY_KEY_A: camera->yt=-.0016f; break; case KEY_KEY_D: camera->yt=.0016f; break; } else switch( event.KeyInput.Key) { case KEY_KEY_Q: case KEY_KEY_E: camera->zt = 0; break; case KEY_KEY_A: case KEY_KEY_D: camera->yt = 0; break; case KEY_KEY_W: case KEY_KEY_S: camera->xt = 0; break; } return false; } };
Здесь мы создаем класс, который будет обрабатывать все наши нажатия клавишь. Значения скоростей он будет записывать непосредственно в объект класса Camera. Тут все просто, нажали клавшу - придали ускорение. Отпустили – сбросили ускорение.
И последний фрагмент на сегодня. Он побольше, но не на много сложнее. Читайте комментарии.