feat: expose aim smooth as 0-100
This commit is contained in:
parent
fcb1f599a4
commit
6fc8d8c16b
|
|
@ -36,6 +36,38 @@ namespace
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float Clamp01(float value)
|
||||||
|
{
|
||||||
|
if (value < 0.f) return 0.f;
|
||||||
|
if (value > 1.f) return 1.f;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
float FrameScale()
|
||||||
|
{
|
||||||
|
float deltaTime = ImGui::GetIO().DeltaTime;
|
||||||
|
if (!(deltaTime > 0.f) || deltaTime > 0.2f)
|
||||||
|
deltaTime = 1.f / 60.f;
|
||||||
|
|
||||||
|
float scale = deltaTime * 60.f;
|
||||||
|
if (scale < 0.5f) scale = 0.5f;
|
||||||
|
if (scale > 2.f) scale = 2.f;
|
||||||
|
return scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Distance-adaptive response:
|
||||||
|
// far target -> catch up; near target -> settle without a large final snap.
|
||||||
|
float AimResponse(float error, float smooth, float referenceError)
|
||||||
|
{
|
||||||
|
smooth = Clamp01(smooth * 0.01f);
|
||||||
|
const float nearResponse = 0.06f + (1.f - smooth) * 0.10f;
|
||||||
|
const float farResponse = 0.28f + (1.f - smooth) * 0.26f;
|
||||||
|
const float weight = Clamp01(error / (referenceError > 0.001f ? referenceError : 1.f));
|
||||||
|
const float perFrame = nearResponse + (farResponse - nearResponse) * weight;
|
||||||
|
|
||||||
|
return 1.f - powf(1.f - perFrame, FrameScale());
|
||||||
|
}
|
||||||
|
|
||||||
// IsKeyDown は Framework/Input/Input.h のグローバル関数を使用
|
// IsKeyDown は Framework/Input/Input.h のグローバル関数を使用
|
||||||
// (GetAsyncKeyState はマウスボタンを検知できない環境があるため、WH_MOUSE_LL フックで捕捉)
|
// (GetAsyncKeyState はマウスボタンを検知できない環境があるため、WH_MOUSE_LL フックで捕捉)
|
||||||
|
|
||||||
|
|
@ -80,7 +112,12 @@ void CFramework::AimAll()
|
||||||
|
|
||||||
// ---- 自瞄 ----
|
// ---- 自瞄 ----
|
||||||
if (!g.g_Aim)
|
if (!g.g_Aim)
|
||||||
|
{
|
||||||
|
m_aimLastTarget = 0;
|
||||||
|
m_aimResidualX = 0.f;
|
||||||
|
m_aimResidualY = 0.f;
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// FOV 円はキーを押していなくても表示
|
// FOV 円はキーを押していなくても表示
|
||||||
Vector2 Center = Vector2(GameSize.x * 0.5f, GameSize.y * 0.5f);
|
Vector2 Center = Vector2(GameSize.x * 0.5f, GameSize.y * 0.5f);
|
||||||
|
|
@ -91,7 +128,12 @@ void CFramework::AimAll()
|
||||||
// ※ GetAsyncKeyState / 低级钩子 在本环境(管理员+RawInput独占)都检测不到按键,
|
// ※ GetAsyncKeyState / 低级钩子 在本环境(管理员+RawInput独占)都检测不到按键,
|
||||||
// g_AimForce 是绕过按键检测的替代方案
|
// g_AimForce 是绕过按键检测的替代方案
|
||||||
if (!g.g_AimForce && !IsKeyDown(g.g_AimKey0) && !IsKeyDown(g.g_AimKey1) && !IsKeyDown(g.g_AimKey2))
|
if (!g.g_AimForce && !IsKeyDown(g.g_AimKey0) && !IsKeyDown(g.g_AimKey1) && !IsKeyDown(g.g_AimKey2))
|
||||||
|
{
|
||||||
|
m_aimLastTarget = 0;
|
||||||
|
m_aimResidualX = 0.f;
|
||||||
|
m_aimResidualY = 0.f;
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// カメラ位置 (ローカル頭部を優先、無ければ origin)
|
// カメラ位置 (ローカル頭部を優先、無ければ origin)
|
||||||
local.UpdateBone();
|
local.UpdateBone();
|
||||||
|
|
@ -179,13 +221,31 @@ void CFramework::AimAll()
|
||||||
m_diagBestDist = bestDist;
|
m_diagBestDist = bestDist;
|
||||||
|
|
||||||
if (bestAddr == 0)
|
if (bestAddr == 0)
|
||||||
|
{
|
||||||
|
m_aimLastTarget = 0;
|
||||||
|
m_aimResidualX = 0.f;
|
||||||
|
m_aimResidualY = 0.f;
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bestAddr != m_aimLastTarget)
|
||||||
|
{
|
||||||
|
m_aimLastTarget = bestAddr;
|
||||||
|
m_aimResidualX = 0.f;
|
||||||
|
m_aimResidualY = 0.f;
|
||||||
|
}
|
||||||
|
|
||||||
// 2. 照準適用
|
// 2. 照準適用
|
||||||
if (g.g_AimMethod == 0)
|
if (g.g_AimMethod == 0)
|
||||||
|
{
|
||||||
|
m_aimResidualX = 0.f;
|
||||||
|
m_aimResidualY = 0.f;
|
||||||
AimMemory(bestPoint, localPos);
|
AimMemory(bestPoint, localPos);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
AimMouse(bestScreen, Center);
|
AimMouse(bestScreen, Center);
|
||||||
|
}
|
||||||
|
|
||||||
// 3. ターゲット線
|
// 3. ターゲット線
|
||||||
if (g.g_AimDrawTarget)
|
if (g.g_AimDrawTarget)
|
||||||
|
|
@ -268,32 +328,54 @@ Vector3 CFramework::GetAimBone(CPlayer* pEntity)
|
||||||
// Mouse モード: 画面中心とターゲットの差分をマウス移動量に変換
|
// Mouse モード: 画面中心とターゲットの差分をマウス移動量に変換
|
||||||
void CFramework::AimMouse(const Vector2& target, const Vector2& center)
|
void CFramework::AimMouse(const Vector2& target, const Vector2& center)
|
||||||
{
|
{
|
||||||
float dx = target.x - center.x;
|
const float dx = target.x - center.x;
|
||||||
float dy = target.y - center.y;
|
const float dy = target.y - center.y;
|
||||||
|
const float dist = sqrtf(dx * dx + dy * dy);
|
||||||
|
|
||||||
float dist = sqrtf(dx * dx + dy * dy);
|
if (dist < 0.5f)
|
||||||
if (dist < 1.f) // 既に当たっている
|
{
|
||||||
|
m_aimResidualX = 0.f;
|
||||||
|
m_aimResidualY = 0.f;
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// smooth: 0=即時追従, 1=ゆっくり追従
|
const float referenceError = g.g_AimFov > 32.f ? g.g_AimFov * 0.5f : 32.f;
|
||||||
float scale = g.g_AimSens * (1.f - g.g_AimSmooth);
|
const float response = AimResponse(dist, g.g_AimSmooth, referenceError);
|
||||||
float mx = dx * scale;
|
|
||||||
float my = dy * scale;
|
|
||||||
|
|
||||||
// 1フレームの最大移動量でクランプ (なめらか + 暴走防止)
|
float sensitivity = g.g_AimSens;
|
||||||
float maxSpeed = g.g_AimMaxSpeed;
|
if (sensitivity < 0.1f) sensitivity = 0.1f;
|
||||||
float len = sqrtf(mx * mx + my * my);
|
if (sensitivity > 5.f) sensitivity = 5.f;
|
||||||
|
|
||||||
|
// Never allow the smoothing slider to turn a small error into a one-frame snap.
|
||||||
|
float gain = response * sensitivity;
|
||||||
|
if (gain > 0.85f) gain = 0.85f;
|
||||||
|
|
||||||
|
float mx = dx * gain;
|
||||||
|
float my = dy * gain;
|
||||||
|
|
||||||
|
// MaxSpeed is expressed at 60 FPS; keep the behavior stable across frame rates.
|
||||||
|
float maxSpeed = g.g_AimMaxSpeed * FrameScale();
|
||||||
|
if (maxSpeed < 1.f) maxSpeed = 1.f;
|
||||||
|
|
||||||
|
const float len = sqrtf(mx * mx + my * my);
|
||||||
if (len > maxSpeed)
|
if (len > maxSpeed)
|
||||||
{
|
{
|
||||||
mx = mx / len * maxSpeed;
|
mx = mx / len * maxSpeed;
|
||||||
my = my / len * maxSpeed;
|
my = my / len * maxSpeed;
|
||||||
}
|
}
|
||||||
|
|
||||||
// デッドゾーン (細かいジッター防止)
|
// Preserve fractional movement instead of truncating every frame to LONG.
|
||||||
if (fabsf(mx) < 0.5f && fabsf(my) < 0.5f)
|
const float moveX = mx + m_aimResidualX;
|
||||||
|
const float moveY = my + m_aimResidualY;
|
||||||
|
const LONG sendX = static_cast<LONG>(lroundf(moveX));
|
||||||
|
const LONG sendY = static_cast<LONG>(lroundf(moveY));
|
||||||
|
m_aimResidualX = moveX - static_cast<float>(sendX);
|
||||||
|
m_aimResidualY = moveY - static_cast<float>(sendY);
|
||||||
|
|
||||||
|
if (sendX == 0 && sendY == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
SendMouseMove((LONG)mx, (LONG)my);
|
SendMouseMove(sendX, sendY);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Memory モード: MovementContext._rotation (Vector2 x=yaw y=pitch) へ書く
|
// Memory モード: MovementContext._rotation (Vector2 x=yaw y=pitch) へ書く
|
||||||
|
|
@ -319,13 +401,12 @@ void CFramework::AimMemory(const Vector3& target, const Vector3& localPos)
|
||||||
yaw = ClampAngle(yaw);
|
yaw = ClampAngle(yaw);
|
||||||
pitch = ClampAngle(pitch);
|
pitch = ClampAngle(pitch);
|
||||||
|
|
||||||
// 平滑化: 現在値 → 目標値へ補間 (yaw は短い方へ回す)
|
// Distance-adaptive exponential smoothing. It is never 0 or 1, so the
|
||||||
float t = 1.f - g.g_AimSmooth;
|
// slider cannot produce either a one-frame snap or a permanently lagging aim.
|
||||||
if (t <= 0.f)
|
|
||||||
return;
|
|
||||||
|
|
||||||
float dyaw = ClampAngle(yaw - rot.x);
|
float dyaw = ClampAngle(yaw - rot.x);
|
||||||
float dpitch = ClampAngle(pitch - rot.y);
|
float dpitch = ClampAngle(pitch - rot.y);
|
||||||
|
float angleError = sqrtf(dyaw * dyaw + dpitch * dpitch);
|
||||||
|
float t = AimResponse(angleError, g.g_AimSmooth, 0.75f);
|
||||||
|
|
||||||
Vector2 newRot{
|
Vector2 newRot{
|
||||||
ClampAngle(rot.x + dyaw * t),
|
ClampAngle(rot.x + dyaw * t),
|
||||||
|
|
|
||||||
|
|
@ -92,6 +92,11 @@ private:
|
||||||
uintptr_t m_diagBestAddr = 0; // 最近一帧锁定的目标地址
|
uintptr_t m_diagBestAddr = 0; // 最近一帧锁定的目标地址
|
||||||
float m_diagBestDist = 0.f;// 最近一帧目标到屏幕中心的距离
|
float m_diagBestDist = 0.f;// 最近一帧目标到屏幕中心的距离
|
||||||
|
|
||||||
|
// 鼠标自瞄的亚像素累积,避免小误差因 LONG 截断而永远到不了目标。
|
||||||
|
uintptr_t m_aimLastTarget = 0;
|
||||||
|
float m_aimResidualX = 0.f;
|
||||||
|
float m_aimResidualY = 0.f;
|
||||||
|
|
||||||
void DrawLine(ImVec2 a, ImVec2 b, ImColor color, float width)
|
void DrawLine(ImVec2 a, ImVec2 b, ImColor color, float width)
|
||||||
{
|
{
|
||||||
ImGui::GetBackgroundDrawList()->AddLine(ImVec2((int)a.x, (int)a.y), ImVec2((int)b.x, (int)b.y), color, width);
|
ImGui::GetBackgroundDrawList()->AddLine(ImVec2((int)a.x, (int)a.y), ImVec2((int)b.x, (int)b.y), color, width);
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ void CFramework::RenderMenu()
|
||||||
ImGui::Checkbox("启用", &g.g_Aim);
|
ImGui::Checkbox("启用", &g.g_Aim);
|
||||||
ImGui::Combo("方式", &g.g_AimMethod, AimMethodList, IM_ARRAYSIZE(AimMethodList));
|
ImGui::Combo("方式", &g.g_AimMethod, AimMethodList, IM_ARRAYSIZE(AimMethodList));
|
||||||
ImGui::CustomSliderFloat("锁定范围", "##AimFov", &g.g_AimFov, 10.f, 500.f);
|
ImGui::CustomSliderFloat("锁定范围", "##AimFov", &g.g_AimFov, 10.f, 500.f);
|
||||||
ImGui::CustomSliderFloat("平滑", "##AimSmooth", &g.g_AimSmooth, 0.f, 1.f);
|
ImGui::CustomSliderFloat("平滑(0-100)", "##AimSmooth", &g.g_AimSmooth, 0.f, 100.f);
|
||||||
ImGui::CustomSliderFloat("最大距离", "##AimDist", &g.g_AimMaxDist, 50.f, 2000.f);
|
ImGui::CustomSliderFloat("最大距离", "##AimDist", &g.g_AimMaxDist, 50.f, 2000.f);
|
||||||
ImGui::Combo("瞄准部位", &g.g_AimBone, AimBoneList, IM_ARRAYSIZE(AimBoneList));
|
ImGui::Combo("瞄准部位", &g.g_AimBone, AimBoneList, IM_ARRAYSIZE(AimBoneList));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ struct Globals
|
||||||
bool g_Aim = false;
|
bool g_Aim = false;
|
||||||
int g_AimMethod = 1; // 0 = Memory(写旋转), 1 = Mouse(SendInput)
|
int g_AimMethod = 1; // 0 = Memory(写旋转), 1 = Mouse(SendInput)
|
||||||
float g_AimFov = 150.f; // FOV 半径 [px]
|
float g_AimFov = 150.f; // FOV 半径 [px]
|
||||||
float g_AimSmooth = 0.45f; // 0=瞬移 1=最慢
|
float g_AimSmooth = 45.f; // 0-100: 自适应平滑,0=快但有限幅,100=慢但不会瞬移
|
||||||
float g_AimSens = 1.0f; // Mouse 模式灵敏度倍率
|
float g_AimSens = 1.0f; // Mouse 模式灵敏度倍率
|
||||||
float g_AimMaxSpeed = 80.f; // Mouse 模式单帧最大移动 [px]
|
float g_AimMaxSpeed = 80.f; // Mouse 模式单帧最大移动 [px]
|
||||||
float g_AimMaxDist = 500.f; // 最大锁定距离 [m]
|
float g_AimMaxDist = 500.f; // 最大锁定距离 [m]
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue