В статье будут рассмотрены двухмерные и трехмерные случаи перемещения и поворотов. Начну я, пожалуй, с очень важной функции - приведение длинны вектора к единичной.
Vector Normalize( Vector vInc )
{
Vector vRes = vInc;
// Вычисление длины вектора
float fLen = sqrt( vInc.x * vInc.x + vInc.y * vInc.y + vInc.z * vInc.z );
// Нормализация вектора, то есть длина вектора становится единичной
vRes.x /= fLen;
vRes.y /= fLen;
vRes.z /= fLen;
// Возвращение результата
return vRes;
}
|
Для двухмерного случая координату z просто нужно опустить. В данном примере функция существует сама по себе, но лучше ее включить в класс для работы с векторами.
Перемещение и поворот можно реализовать разными способами, я рассмотрю несколько. Допустим существует переменная fAngle, в которой хранится угол поворота персонажа. Этот угол можно менять, например, при нажатии на клавиши VK_LEFT, VK_RIGHT, либо на любые другие. Тогда при нажатии на VK_UP, VK_DOWN, персонаж должен двигаться вперед либо назад, с учетом угла поворота. Это легко реализуемо.
VK_LEFT: // Персонаж поворачивается налево
...
fAngle += 0.1f; // Изменение угла, значение может быть любым
...
VK_RIGHT: // Персонаж поворачивается направо
...
fAngle -= 0.1f;
...
VK_UP: // Персонаж идет вперед
...
Player.x += cos( fAngle );
Player.y += sin( fAngle );
...
VK_DOWN: // Персонаж идет назад
...
Player.x -= cos( fAngle );
Player.y -= sin( fAngle );
...
|
Так же угол fAngle, можно менять с помощью движений мыши, при всем этом сам процесс перемещения остается неизменным. Для этого поэкспериментируйте с функциями GetCursorPos( POINT ), SetCursorPos( int, int ). Эти функции будут востребованы, при работе в трехмерном пространстве.
Но что делать если мы мышкой управляем положением точки, в которую игрок должен постоянно быть направлен? Я столкнулся с этой проблемой, при разработке игры RedGutS, и решил ее там довольно странным способом. Можно конечно находить угол при помощи функции арксинуса или аркосинуса, но это слишком громоздко и медленно, в своей игре я сделал так - поворачивал единичный вектор( vDir ) на определенный угол, до тех пор, пока косинус угла между vDir и вектором, разности координат точки направления и игрока, не стал приблизительно равным 1. Такой способ можно использовать для плавного поворота игроков, но есть более простой способ( я не испытывал его ), направление вычисляется очень просто:
Vector vDir; // Направление игрока
Vector vPlr; // Координаты игрока
Vector vTar; // Координаты точки направления
vDir.x = vTar.x - vPlr.x;
vDir.y = vTar.y - vPlr.y;
vDir = Normalize( vDir ); // Вот мы и имеем единичный вектор направления
|
Теперь не нужен никакой угол fAngle, а перемещение организовано так:
float fVel; // Скорость персонажа
VK_UP:
...
vPlr.x += vDir.x * fVel;
vPlr.y += vDir.y * fVel;
...
VK_DOWN:
...
vPlr.x -= vDir.x * fVel;
vPlr.y -= vDir.y * fVel;
...
VK_RIGHT:
...
vPlr.x += vDir.y * fVel;
vPlr.y -= vDir.x * fVel;
...
VK_LEFT:
...
vPlr.x -= vDir.y * fVel;
vPlr.y += vDir.x * fVel;
...
|
В данном случае vDir является нормалью игрока.
Теперь я приведу формулы перемещения в трехмерном пространстве. Ниже используются два угла : fAngleX - угол поворота по оси X, и fAngleY - угол поворота по оси Y.
VK_UP:
...
vPlr.x -= sin( fAngleY ) * cos( fAngleX );
vPlr.y += sin( fAngleX );
vPlr.z += cos( fAngleY ) * cos( fAngleX );
...
VK_DOWN:
...
vPlr.x += sin( fAngleY ) * cos( fAngleX );
vPlr.y -= sin( fAngleX );
vPlr.z -= cos( fAngleY ) * cos( fAngleX );
...
// При перемещении налево или направо координата y не должна меняться,
// так как движемся только в одной плоскости
VK_LEFT:
...
vPlr.x += sin( fAngleY );
vPlr.z += cos( fAngleY );
...
VK_RIGHT:
...
vPlr.x -= sin( fAngleY );
vPlr.z -= cos( fAngleY );
...
|
Вот и все, что нужно для создания простенькой игры.
|