PDA

Просмотр полной версии : [Урок] Углы и оси



Osetin
15.08.2013, 10:05
Аналитическая геометрия - прекрасная вещь, особенно для использования в играх. Но вот незадача - почему использование обычных общепринятых определений и теорем при работе с осями и углами на плоскости работают не так, как следовало бы работать?

Дело в том, что стандартная ось и ось GTA SA хоть и схожы, но имеют различие. 0 градусов не 0, и 180 тоже не 180. Почему же?

http://img405.imageshack.us/img405/9520/izs8.png

Как видно, углы смещены путём поворота осей на 90 градусов против часовой стрелки.

http://img545.imageshack.us/img545/5998/gq6o.png

Из этого следует, что уже X не связан с cos, а Y не связан с sin. X уже будет связан с sin, а Y будет уже связан с cos.

Как пример, попробуем понять, почему именно так.
Создадим два рисунка с осями без названий. Один рисунок - для Y, второй - для X.

http://imageshack.us/a/img802/2247/m92.png

Узнаем, как должны изменяться координаты относительно поворота.

http://imageshack.us/a/img27/1289/tu47.png

А теперь повернем эти рисунки на 90 градусов по часовой стрелке.

http://imageshack.us/a/img35/7294/gh4p.png

Как мы видим, Y связан с cos, а X связан с -sin. В итоге, получаем, что если мы хотим создать какой-либо элемент впереди игрока, то:

new Float:p[4];
new Float:dist = 5.0; //дистанция, на котором будет создан объект
GetPlayerPos(playerid,p[0],p[1],p[2]);
GetPlayerFacingAngle(playerid,p[3]);
CreateObject(modelid,p[0]+dist*-floatsin(p[3],degrees),p[1]+dist*floatcos(p[3],degrees),p[2],0.0,0.0,0.0,300.0);
Хотите создать элемент где-то сбоку игрока, или даже сзади? Просто добавьте к текущей ротации игрока требуемый угол.

new Float:p[4];
new Float:dist = 5.0; //дистанция, на которой будет создан объект
GetPlayerPos(playerid,p[0],p[1],p[2]);
GetPlayerFacingAngle(playerid,p[3]);
p[3] = p[3] + 45.0; //прибавление угла; можно и отнимать
CreateObject(modelid,p[0]+dist*-floatsin(p[3],degrees),p[1]+dist*floatcos(p[3],degrees),p[2],0.0,0.0,0.0,300.0);
Задается вопрос: А зачем все эти синусы и косинусы? Нет другого способа? Ответ: нет, нету. Синус и косинус позволяют нам делать создание элемента именно с наиточнейшим расстоянием от игрока.

http://img405.imageshack.us/img405/8434/8bf.png

Все эти отрезки (L1,...,L8) равны между собой, т.к. являются радиусами. Таким образом, синус и косинус помогают вычислить нам расстояния, которые нужно изменить по X и Y, чтобы получить такой радиус.

А теперь перейдем к трехмерному пространству, особенно к функции GetPlayerCameraFrontVector.
Как ни странно, эта функция ведет себя, как в стандартном пространстве и с учетом игрового одновременно. Но она уже возвращает данные, преобразованные косинусом и синусом, то есть уже использовать угол поворота игрока, в принципе, не совсем нужно. Ан нет, он всё равно потребуется в каком-нибудь случае, так как обновление данных о камере идет куда не так часто, как обновление ротации игрока по Z.

http://img585.imageshack.us/img585/1641/5b8.png

Таким образом, красная зона отвечает за значения по Y и X, а синяя зона - за значение по Z.

http://img7.imageshack.us/img7/4550/3w7.png

А каков же угол по Z у камеры? Z связан с sin, поэтому достаточно легко понять, что для узнавания угла наклона нужно использовать asin:


new Float:p[3],Float:ang;
GetPlayerCameraFrontVector(playerid,p[0],p[1],p[2]);
ang = asin(p[2]);

Изменение угла - от -90 до 90.

Как пример, сделаем так, чтобы создавался объект именно там, куда смотрит игрок.


new Float:p[3],Float:pp[3];
new Float:dist = 5.0;
GetPlayerCameraFrontVector(playerid,p[0],p[1],p[2]);
GetPlayerCameraPos(playerid,pp[0],pp[1],pp[2]);
CreateObject(3798,pp[0]+dist*p[0],pp[1]+dist*p[1],pp[2]+dist*p[2],0,0,0);

Напомню, что здесь мы не используем sin и cos, так как GetPlayerCameraFrontVector уже высчитала нам различие.
Использовать позицию игрока будет неверным способом, так как камера смотрит не точно на позицию игрока.

http://img42.imageshack.us/img42/95/w2o4.png

Автор темы и рисунков: Quantra