lengshizai 2024-04-22 23:05 采纳率: 31.7%
浏览 17
已结题

Yolo识别出的坐标的模拟鼠标应用问题

老板布置的工作:改写C++yolo 并随便写个FPS游戏锁头的算法
已经解决了yoloC++化。但在鼠标应用过程出了问题。
明天要开工作组会了,捉鸡,随便一个FPS全屏游戏都行,对游戏不要求 ,你玩cs1.6我都没意见
方法是不断截屏识别,获取坐标。
问题如下: 在yoloV5导出的坐标中,已换算为导出坐标(POSx,POSy)已经是对应屏幕的坐标了
灵敏度系数调整的也还可以··
但在实际调用过程中出现了鼠标跑飞问题

划重点:问题不是出在平滑度以及灵敏度上,请考虑FPS游戏视角的变化以及窗口缩放问题、
不要再照搬AI了 头秃

#include <windows.h>
#include <iostream>
#include <cmath>
#include <random>
 
// 全局变量,记录最后一次移动的坐标
int lastMovedX = 0;
int lastMovedY = 0;
 
const LPCWSTR windowClass = L"类名"; // 或者具体的类名,如L"ConsoleWindowClass"
const LPCWSTR windowTitle = L"窗口标题";
 
bool isMoving = false; // 全局标志,用于标记是否正在进行鼠标移动
 
double SmoothFunction(double t, float smoothnessFactor)
{
    return std::pow(t, 1.0f / (1.0f + smoothnessFactor));
}
 
// 更新中心视角到目标坐标
void UpdateCenterView(int targetX, int targetY, int step, float sensitivity, float smoothnessFactor)
{
    // 获取当前鼠标位置
    POINT currentMousePos;
    GetCursorPos(&currentMousePos);
 
    // 确保目标坐标在屏幕范围内
    targetX = std::clamp(targetX, 0, GetSystemMetrics(SM_CXSCREEN) - 1);
    targetY = std::clamp(targetY, 0, GetSystemMetrics(SM_CYSCREEN) - 1);
 
    // 计算目标位置与上次移动位置之间的增量
    int deltaX = targetX - lastMovedX;
    int deltaY = targetY - lastMovedY;
 
    // 当目标坐标与上一次移动位置的距离小于等于步长时,无需移动
    if (std::hypot(deltaX, deltaY) <= step)
    {
        return;
    }
 
    isMoving = true; // 设置标志,表示开始新的鼠标移动操作
 
    // 计算移动方向(以弧度表示)
    double angle = atan2(deltaY, deltaX);
 
    // 计算所需移动次数(向上取整)
    double distance = std::hypot(deltaX, deltaY);
    int numMoves = static_cast<int>(std::ceil(distance / step));
 
    for (int i = 0; i < numMoves; ++i)
    {
        double t = static_cast<double>(i) / numMoves;
        double t_smoothed = t; // 默认无平滑
 
        if (smoothnessFactor > 0.0f)
        {
            // 使用平滑曲线(如指数或余弦函数)平滑t
            t_smoothed = SmoothFunction(t, smoothnessFactor);
        }
 
        int newX = static_cast<int>(lastMovedX + step * sensitivity * cos(angle) * t_smoothed);
        int newY = static_cast<int>(lastMovedY + step * sensitivity * sin(angle) * t_smoothed);
 
        INPUT input = {};
        input.type = INPUT_MOUSE;
        input.mi.dwFlags = MOUSEEVENTF_MOVE;
        input.mi.dx = newX - currentMousePos.x;
        input.mi.dy = newY - currentMousePos.y;
        SendInput(1, &input, sizeof(INPUT));
        Sleep(3);
 
        // 检查是否有新的指令打断当前移动
        if (!isMoving)
        {
            break; // 中断当前移动操作
        }
    }
 
    lastMovedX = currentMousePos.x;
    lastMovedY = currentMousePos.y;
    isMoving = false; // 移动操作完成,重置标志
}
 
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    HWND hwnd = FindWindowW(windowClass, windowTitle);
    if (hwnd == NULL)
    {
        std::cerr << "Failed to find the game window.\n";
        return -1;
    }
 
    SetForegroundWindow(hwnd);
    Sleep(500);
 
    int step = 20;
    float sensitivity = 0.1f; // 假设默认视角灵敏度为1.0,根据实际游戏调整
    float smoothnessFactor = 0.8f; // 平滑度因子,根据需要调整
   //假定屏幕分辨率是1600*900 
    UpdateCenterView(POSx, POSy, step, sensitivity, smoothnessFactor);
    return 0;
}
 

  • 写回答

23条回答 默认 最新

  • 专家-赤兔[在线] 全栈领域优质创作者 2024-04-22 23:05
    关注
    获得0.45元问题酬金

    引自免费微信小程序:皆我百晓生

    针对您所描述的问题,即在将YOLO识别出的坐标应用于FPS游戏鼠标控制时出现鼠标跑飞现象,且排除了平滑度和灵敏度问题后,推测可能与游戏视角变化、窗口缩放等因素有关。针对这些问题,您可以尝试以下改进措施:

    1. 处理窗口缩放与坐标映射: 如果游戏窗口进行了缩放,识别出的坐标可能与实际游戏内坐标存在比例关系的差异。您可以获取游戏窗口的实际大小和屏幕分辨率,计算缩放比例,然后对YOLO输出的坐标进行相应调整。以下是相关代码示例:

      RECT windowRect;
      GetWindowRect(hwnd, &windowRect); // 获取游戏窗口的屏幕坐标范围
      int windowWidth = windowRect.right - windowRect.left;
      int windowHeight = windowRect.bottom - windowRect.top;
      
      int screenWidth = GetSystemMetrics(SM_CXSCREEN);
      int screenHeight = GetSystemMetrics(SM_CYSCREEN);
      
      float windowScaleX = static_cast<float>(windowWidth) / screenWidth;
      float windowScaleY = static_cast<float>(windowHeight) / screenHeight;
      
      int scaledPOSx = static_cast<int>(POSx * windowScaleX);
      int scaledPOSy = static_cast<int>(POSy * windowScaleY);
      
      UpdateCenterView(scaledPOSx, scaledPOSy, step, sensitivity, smoothnessFactor);
      
    2. 考虑游戏视角动态变化: 部分FPS游戏的视角可能会随角色移动、跳跃等动作而动态变化。在这种情况下,单纯依赖YOLO识别出的目标坐标可能导致鼠标移动不准确。为适应这种变化,可以尝试引入游戏内视角方向信息作为辅助输入,结合YOLO坐标进行修正。具体实现方式取决于游戏API提供的视角数据接口,这里仅提供一种思路:

      • 获取当前游戏视角方向(如俯仰角、偏航角),通过游戏API或内存读取等方式。
      • 根据视角方向对YOLO坐标进行适当偏移或旋转修正,确保鼠标移动与游戏内视角保持一致。
    3. 处理鼠标捕捉与焦点问题: 确保鼠标焦点始终位于游戏窗口内,避免鼠标跑出游戏窗口导致控制失效。可以考虑使用SetCapture()函数将鼠标捕获到游戏窗口,并在程序退出时释放鼠标捕获。示例如下:

      SetCapture(hwnd);
      // ...
      ReleaseCapture();
      
    4. 优化鼠标移动逻辑: 目前的鼠标移动逻辑是基于固定步长和角度计算增量。为了应对游戏视角快速变化的情况,可以尝试采用更灵活的移动策略,如根据视角变化速度动态调整步长和移动频率。此外,确保鼠标移动与游戏帧率同步,可以减少因帧率波动导致的定位偏差。

    综上所述,您可以通过处理窗口缩放、考虑游戏视角动态变化、处理鼠标捕捉与焦点问题以及优化鼠标移动逻辑等方面对现有代码进行改进,以解决鼠标跑飞问题。由于具体实现细节可能依赖于游戏类型和API接口,以上建议仅供参考,您需要根据实际情况进行调整和适配。

    评论 编辑记录

报告相同问题?

问题事件

  • 系统已结题 4月30日
  • 创建了问题 4月22日

悬赏问题

  • ¥15 软件工程用例图的建立(相关搜索:软件工程用例图|画图)
  • ¥15 如何在arcgis中导出拓扑关系表
  • ¥15 处理数据集文本挖掘代码
  • ¥15 matlab2017
  • ¥15 在vxWorks下TCP/IP编程,总是connect()报错,连接服务器失败: errno = 0x41
  • ¥15 AnolisOs7.9如何安装 Qt_5.14.2的运行库
  • ¥20 求:怎么实现qt与pcie通信
  • ¥50 前后端数据顺序不一致问题,如何解决?(相关搜索:数据结构)
  • ¥15 基于蒙特卡罗法的中介效应点估计代码
  • ¥15 罗技G293和UE5.3