Исходник Гайд Первая научная наводка на координаты

THERION

Известный
Автор темы
Проверенный
88
324
К сожалению в общем доступе не встречал никогда корректно работающего алгоритма наводки на координаты в GTA:SA. В основном все копируют вот это.
И у всех одна и таже проблема - прицел улетает в разные стороны если цель чуть ниже или чуть выше.

aimtop.png
aimbotom.png

Поэтому вместо '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


В нашем случае в качестве начала координат (точки O) мы будем использовать игровую камеру.

Далее о работе камеры

1679271906354.png


На изображении выше мы видим луч "Camera direction", он начинается в камере и проходит через центр экрана пользователя. В сферической системе координат (с центром - камерой) у любой точки на этом луче φ и θ совпадают.
Именно эти углы φ и θ обозначаются в структуре CCam как fHorizontalAngle и fVerticalAngle
C++:
class CCam {
    // ...
    float fHorizontalAngle;
    // ...
    float fVerticalAngle;
    // ...
}

class CCamera {
    // ...
    CCam aCams[3];
    // ...
}
Поэтому для того чтобы точка оказалась в центре камеры игрока нам достаточно задать такие fHorizontalAngle и fVerticalAngle, чтоб они совпадали с соответстующими φ и θ точки, представленной в сферической системе координат.
Чтобы представить точку в сферической системе координат будем использовать следующую формулу:

%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


Но не факт что в полях 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

При этом формула рассчитана на такие

%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


Добавляем дополнительный переход.
%D0%BF%D0%B5%D1%80%D0%B5%D1%85%D1%96%D0%B4.jpg


Получаем следующий алгоритм перехода к сферической системе координат:
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


Теперь нам нужно узнать φ и θ точек луча проходящего через прицел, сделать это можно следующим образом:
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
Теперь у вас есть нужные знания чтобы написать первый рабочий аимбот, желаю удачи
UPD: исправил неточности и ошибки
 
Последнее редактирование:

Abdulla228

Участник
57
11
говорят же: что бы создать игру-шутер ты должен знать физико-математическое направление.Афигеть ты все перечитал,обдумал,разъяснил но многие не поняли XD
 

lorgon

Известный
657
268
К сожалению в общем доступе не встречал никогда корректно работающего алгоритма наводки на координаты в GTA:SA. В основном все копируют вот это.
И у всех одна и таже проблема - прицел улетает в разные стороны если цель чуть ниже или чуть выше.

Посмотреть вложение 194272Посмотреть вложение 194273
Поэтому вместо '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


В нашем случае в качестве начала координат (точки O) мы будем использовать игровую камеру.

Далее о работе камеры

Посмотреть вложение 194275

На изображении выше мы видим луч "Camera direction", он начинается в камере и проходит через центр экрана пользователя. В сферической системе координат (с центром - камерой) у любой точки на этом лучше φ и θ совпадают.
Именно эти углы φ и θ обозначаются в структуре CCam как fHorizontalAngle и fVerticalAngle
C++:
class CCam {
    // ...
    float fHorizontalAngle;
    // ...
    float fVerticalAngle;
    // ...
}

class CCamera {
    // ...
    CCam aCams[3];
    // ...
}
Поэтому для того чтобы точка оказалась в центре камеры игрока нам достаточно задать такие fHorizontalAngle и fVerticalAngle, чтоб они совпадали с соответстующими φ и θ точки, представленной в сферической системе координат.
Чтобы представить точку в сферической системе координат будем использовать следующую формулу:

%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


Но не факт что в полях 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

При этом формула рассчитана на такие

%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


Добавляем дополнительный переход.
%D0%BF%D0%B5%D1%80%D0%B5%D1%85%D1%96%D0%B4.jpg


Получаем следующий алгоритм перехода к сферической системе координат:
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


Теперь нам нужно узнать φ и θ точек луча проходящего через прицел, сделать это можно следующим образом:
Lua:
local function getCrosshairPositionOnScreen()
      local resolutionX, resolutionY = getScreenResolution()
      local onScreenX = x * 0.5299999714
      local onScreenY = y * 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
Теперь у вас есть нужные знания чтобы написать первый рабочий аимбот, желаю удачи
UPD: исправил неточности и ошибки
Очень люблю такие разборы реальных задач с использованием математики! Особенно порадовало, что каждый этап проиллюстрирован и описан, чтобы каждый человек мог увидеть и понять. Побольше бы подобного контента.

Дякуємо за розвиток україномовного контенту
 

Corenale

Известный
147
151
  • Нравится
  • Вау
Реакции: why ega и ChromiusJ

sergey petrov

Новичок
5
1
К сожалению в общем доступе не встречал никогда корректно работающего алгоритма наводки на координаты в GTA:SA. В основном все копируют вот это.
И у всех одна и таже проблема - прицел улетает в разные стороны если цель чуть ниже или чуть выше.

Посмотреть вложение 194272Посмотреть вложение 194273
Поэтому вместо '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


В нашем случае в качестве начала координат (точки O) мы будем использовать игровую камеру.

Далее о работе камеры

Посмотреть вложение 194275

На изображении выше мы видим луч "Camera direction", он начинается в камере и проходит через центр экрана пользователя. В сферической системе координат (с центром - камерой) у любой точки на этом луче φ и θ совпадают.
Именно эти углы φ и θ обозначаются в структуре CCam как fHorizontalAngle и fVerticalAngle
C++:
class CCam {
    // ...
    float fHorizontalAngle;
    // ...
    float fVerticalAngle;
    // ...
}

class CCamera {
    // ...
    CCam aCams[3];
    // ...
}
Поэтому для того чтобы точка оказалась в центре камеры игрока нам достаточно задать такие fHorizontalAngle и fVerticalAngle, чтоб они совпадали с соответстующими φ и θ точки, представленной в сферической системе координат.
Чтобы представить точку в сферической системе координат будем использовать следующую формулу:

%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


Но не факт что в полях 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

При этом формула рассчитана на такие

%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


Добавляем дополнительный переход.
%D0%BF%D0%B5%D1%80%D0%B5%D1%85%D1%96%D0%B4.jpg


Получаем следующий алгоритм перехода к сферической системе координат:
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


Теперь нам нужно узнать φ и θ точек луча проходящего через прицел, сделать это можно следующим образом:
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
Теперь у вас есть нужные знания чтобы написать первый рабочий аимбот, желаю удачи
UPD: исправил неточности и ошибки
что именно вставлять в луа ?
 

sergey petrov

Новичок
5
1
я вставил . Но ничего не происходит .

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

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

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

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

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
 
  • Клоун
  • Эм
Реакции: percheklii и Corenale