- 88
- 327
И у всех одна и таже проблема - прицел улетает в разные стороны если цель чуть ниже или чуть выше.
Поэтому вместо 'weird shit' которое еще и не работает, опишу то как оно должно быть
Для начала нужно ознакомиться с понятием сферической системой координат. Любую точку P: (x, y, z) можно задать как P: (r, φ, θ), где:
r - длина отрезка OP
φ - угол между осью OX и проэкцией отрезка OP на плоскость XY
θ - угол между отрезком OP и плоскостью XY
В нашем случае в качестве начала координат (точки O) мы будем использовать игровую камеру.
Далее о работе камеры
На изображении выше мы видим луч "Camera direction", он начинается в камере и проходит через центр экрана пользователя. В сферической системе координат (с центром - камерой) у любой точки на этом луче φ и θ совпадают.
Именно эти углы φ и θ обозначаются в структуре CCam как fHorizontalAngle и fVerticalAngle
C++:
class CCam {
// ...
float fHorizontalAngle;
// ...
float fVerticalAngle;
// ...
}
class CCamera {
// ...
CCam aCams[3];
// ...
}
Чтобы представить точку в сферической системе координат будем использовать следующую формулу:
Но не факт что в полях fVerticalAngle и fHorizontalAngle данные хранятся в таком же формате под которые была написана данная формула. Поэтому исследуем значения которые принимают эти поля. В этом нам поможет библиотека SA Memory
Lua:
local SAMemory = require("SAMemory")
SAMemory.require("CCamera")
local function getCameraRotation()
local theCamera = SAMemory.camera
local phi = theCamera.aCams[0].fHorizontalAngle
local theta = theCamera.aCams[0].fVerticalAngle
return phi, theta
end
При этом формула рассчитана на такие
Добавляем дополнительный переход.
Получаем следующий алгоритм перехода к сферической системе координат:
Lua:
local vector3D = require("vector3d")
local function convertCartesianCoordinatesToSpherical(point)
local camera = vector3D(getActiveCameraCoordinates())
local vector = point - camera
-- стандартная формула
local r = vector:length()
local phi = math.atan2(vector.y, vector.x)
local theta = math.acos(vector.z / r)
--
-- дополнительный переход
if phi > 0 then
phi = phi - math.pi
else
phi = phi + math.pi
end
theta = math.pi / 2 - theta
--
return phi, theta
end
Полученной информации достаточно для того чтобы написать алгоритм наведения для снайперской винтовки, т.к ее прицел находится в центре экрана, в отличии от прицела обычного (об этом далее)
Lua:
local function setCameraRotation(phi, theta)
local theCamera = SAMemory.camera
theCamera.aCams[0].fHorizontalAngle = phi
theCamera.aCams[0].fVerticalAngle = theta
end
function aimAtPointWithSniperScope(point)
local pointPhi, pointTheta = convertCartesianCoordinatesToSpherical(point)
setCameraRotation(pointPhi, pointTheta)
end
Для того чтобы навести обычный прицел нам нужно найти разность между φ и θ точки на которую мы хотим навестись и φ и θ точек луча проходящего через прицел (начинающегося в камере). далее эти значения добавить к fHorizontalAngle и fVerticalAngle:
Теперь нам нужно узнать φ и θ точек луча проходящего через прицел, сделать это можно следующим образом:
Lua:
local function getCrosshairPositionOnScreen()
local resolutionX, resolutionY = getScreenResolution()
local onScreenX = resolutionX * 0.5299999714
local onScreenY = resolutionY * 0.4
-- коэффициенты взяты из функции отрисовки прицела (CHud::Draw_Что-то_там)
return onScreenX, onScreenY
end
local function getCrosshairRotation(distance)
distance = distance or 5
local crosshairOnScreenX, crosshairOnScreenY = getCrosshairPositionOnScreen()
local crosshair = vector3D(convertScreenCoordsToWorld3D(crosshairOnScreenX, crosshairOnScreenY, distance))
-- находим прицел на экране -> переводим в 3D координаты
return convertCartesianCoordinatesToSpherical(crosshair)
end
Lua:
function aimAtPointWithM16(point)
local pointPhi, pointTheta = convertCartesianCoordinatesToSpherical(point)
local cameraPhi, cameraTheta = getCameraRotation()
local crosshairPhi, crosshairTheta = getCrosshairRotation()
local rotationPhi = cameraPhi + (pointPhi - crosshairPhi)
local rotationTheta = cameraTheta + (pointTheta - crosshairTheta)
setCameraRotation(rotationPhi, rotationTheta)
end
Последнее редактирование: