- 88
- 327
![gitlab.com](/proxy.php?image=https%3A%2F%2Fgitlab.com%2Fuploads%2F-%2Fsystem%2Fproject%2Favatar%2F36398195%2F1.png&hash=aff1d27dfad876f127b6ad44146bb3d3&return_error=1)
И у всех одна и таже проблема - прицел улетает в разные стороны если цель чуть ниже или чуть выше.
Поэтому вместо 'weird shit' которое еще и не работает, опишу то как оно должно быть
Для начала нужно ознакомиться с понятием сферической системой координат. Любую точку P: (x, y, z) можно задать как P: (r, φ, θ), где:
r - длина отрезка OP
φ - угол между осью OX и проэкцией отрезка OP на плоскость XY
θ - угол между отрезком OP и плоскостью XY
![%D1%81%D1%84%D0%B5%D1%80%D0%B8%D1%87%D0%BD%D1%96-%D0%BA%D0%BE%D0%BE%D1%80%D0%B4%D0%B8%D0%BD%D0%B0%D1%82%D0%B8.jpg](/proxy.php?image=https%3A%2F%2Fgitlab.com%2Fmodarnya%2Fmoonloader%2Faim-algorithm%2F-%2Fraw%2Fmain%2Fimages%2F%25D1%2581%25D1%2584%25D0%25B5%25D1%2580%25D0%25B8%25D1%2587%25D0%25BD%25D1%2596-%25D0%25BA%25D0%25BE%25D0%25BE%25D1%2580%25D0%25B4%25D0%25B8%25D0%25BD%25D0%25B0%25D1%2582%25D0%25B8.jpg&hash=da2829ce5e29e4fbe6f91f1b4fb36669)
В нашем случае в качестве начала координат (точки O) мы будем использовать игровую камеру.
Далее о работе камеры
На изображении выше мы видим луч "Camera direction", он начинается в камере и проходит через центр экрана пользователя. В сферической системе координат (с центром - камерой) у любой точки на этом луче φ и θ совпадают.
Именно эти углы φ и θ обозначаются в структуре CCam как fHorizontalAngle и fVerticalAngle
C++:
class CCam {
// ...
float fHorizontalAngle;
// ...
float fVerticalAngle;
// ...
}
class CCamera {
// ...
CCam aCams[3];
// ...
}
Чтобы представить точку в сферической системе координат будем использовать следующую формулу:
![%D1%81%D1%84%D0%B5%D1%80%D0%B8%D1%87%D0%BD%D1%96-%D0%BA%D0%BE%D0%BE%D1%80%D0%B4%D0%B8%D0%BD%D0%B0%D1%82%D0%B8-%D1%84%D0%BE%D1%80%D0%BC%D1%83%D0%BB%D0%B0.jpg](/proxy.php?image=https%3A%2F%2Fgitlab.com%2Fmodarnya%2Fmoonloader%2Faim-algorithm%2F-%2Fraw%2Fmain%2Fimages%2F%25D1%2581%25D1%2584%25D0%25B5%25D1%2580%25D0%25B8%25D1%2587%25D0%25BD%25D1%2596-%25D0%25BA%25D0%25BE%25D0%25BE%25D1%2580%25D0%25B4%25D0%25B8%25D0%25BD%25D0%25B0%25D1%2582%25D0%25B8-%25D1%2584%25D0%25BE%25D1%2580%25D0%25BC%25D1%2583%25D0%25BB%25D0%25B0.jpg&hash=9ac4961ad06a8cfe1d69c15621084f97)
Но не факт что в полях 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
![%D1%96%D0%B3%D1%80%D0%BE%D0%B2%D0%B0-%D0%BA%D0%B0%D0%BC%D0%B5%D1%80%D0%B0.jpg](/proxy.php?image=https%3A%2F%2Fgitlab.com%2Fmodarnya%2Fmoonloader%2Fsmoothie%2F-%2Fraw%2Fmain%2Fimages%2F%25D1%2596%25D0%25B3%25D1%2580%25D0%25BE%25D0%25B2%25D0%25B0-%25D0%25BA%25D0%25B0%25D0%25BC%25D0%25B5%25D1%2580%25D0%25B0.jpg&hash=053db21364e7d84a28c4b415a765e972)
При этом формула рассчитана на такие
![%D1%81%D1%82%D0%B0%D0%BD%D0%B4%D0%B0%D1%80%D1%82%D0%BD%D0%B0-%D0%BA%D0%B0%D0%BC%D0%B5%D1%80%D0%B0.jpg](/proxy.php?image=https%3A%2F%2Fgitlab.com%2Fmodarnya%2Fmoonloader%2Fsmoothie%2F-%2Fraw%2Fmain%2Fimages%2F%25D1%2581%25D1%2582%25D0%25B0%25D0%25BD%25D0%25B4%25D0%25B0%25D1%2580%25D1%2582%25D0%25BD%25D0%25B0-%25D0%25BA%25D0%25B0%25D0%25BC%25D0%25B5%25D1%2580%25D0%25B0.jpg&hash=da9737519b8787a345014367b1ea62ba)
Добавляем дополнительный переход.
![%D0%BF%D0%B5%D1%80%D0%B5%D1%85%D1%96%D0%B4.jpg](/proxy.php?image=https%3A%2F%2Fgitlab.com%2Fmodarnya%2Fmoonloader%2Fsmoothie%2F-%2Fraw%2Fmain%2Fimages%2F%25D0%25BF%25D0%25B5%25D1%2580%25D0%25B5%25D1%2585%25D1%2596%25D0%25B4.jpg&hash=8258e352f95a266365fd4b00da3c97f5)
Получаем следующий алгоритм перехода к сферической системе координат:
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:
![%D1%80%D1%83%D1%85-%D0%BA%D0%B0%D0%BC%D0%B5%D1%80%D0%B8.jpg](/proxy.php?image=https%3A%2F%2Fgitlab.com%2Fmodarnya%2Fmoonloader%2Fsmoothie%2F-%2Fraw%2Fmain%2Fimages%2F%25D1%2580%25D1%2583%25D1%2585-%25D0%25BA%25D0%25B0%25D0%25BC%25D0%25B5%25D1%2580%25D0%25B8.jpg&hash=8c0a1eafcd2c7010b224ebc3a6edc07a)
Теперь нам нужно узнать φ и θ точек луча проходящего через прицел, сделать это можно следующим образом:
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
Последнее редактирование: