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

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

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

#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;
}

请修改我的代码 要求任意一个全屏FPS游戏,能交任务就行
效率方法无所谓。C++

  • 写回答

6条回答 默认 最新

  • 专家-赤兔[在线] 全栈领域优质创作者 2024-04-22 23:02
    关注

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

    根据你的描述,看起来你在尝试实现一个简单的自动瞄准系统,但是遇到了鼠标移动不准确的问题。这可能是由于鼠标移动的频率过高或者移动量过大导致的。为了改进这个问题,我们可以优化鼠标移动的算法,使其更加平滑,并且增加一些逻辑来处理可能的游戏窗口大小变化。

    以下是修改后的代码,主要改动包括:

    1. 添加了一个全局变量prevUpdateTime来跟踪上一次更新时间。
    2. 修改了UpdateCenterView函数,使其只在指定的时间间隔内执行一次移动操作。
    3. 添加了一个CalculateTargetMove函数来计算每次移动的具体距离和角度,以便更精确地控制鼠标移动。
    #include <windows.h>
    #include <iostream>
    #include <cmath>
    #include <chrono>
    #include <thread>
    #include <random>
    
    // 全局变量
    int lastMovedX = 0;
    int lastMovedY = 0;
    int prevUpdateTime = 0;
    float timeInterval = 0.01f; // 时间间隔,可以根据实际情况调整
    
    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 CalculateTargetMove(int startX, int startY, int endX, int endY, double& distance, double& angle)
    {
        distance = std::sqrt(std::pow(endX - startX, 2) + std::pow(endY - startY, 2));
        angle = atan2(endY - startY, endX - startX);
    }
    
    // 更新中心视角到目标坐标
    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);
    
        // 如果目标坐标与当前位置相同,则不进行移动
        if (targetX == currentMousePos.x && targetY == currentMousePos.y)
        {
            return;
        }
    
        // 计算鼠标移动的间隔时间
        auto currentTime = std::chrono::high_resolution_clock::now();
        auto elapsedTime = currentTime - prevUpdateTime;
        float timeElapsedSeconds = static_cast<float>(elapsedTime.count()) * 1e-6f;
    
        // 只有在达到预定间隔时间后才移动鼠标
        if (timeElapsedSeconds >= timeInterval)
        {
            prevUpdateTime = currentTime;
    
            double distance;
            double angle;
            CalculateTargetMove(lastMovedX, lastMovedY, targetX, targetY, distance, angle);
    
            // 当目标位置与上一次移动位置的距离小于等于步长时,无需移动
            if (distance <= step)
            {
                return;
            }
    
            isMoving = true; // 设置标志,表示开始新的鼠标移动操作
    
            // 计算移动方向(以弧度表示)
            double t = 1.0f; // 初始化为最大值,确保至少移动一次
    
            if (distance > step)
            {
                // 计算所需移动次数(向上取整)
                int numMoves = static_cast<int>(std::ceil(distance / step));
    
                // 分配移动次数
                t = static_cast<double>(numMoves - 1) / numMoves;
            }
    
            double 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 = newX;
            lastMovedY = newY;
        }
    }
    
    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 
        while (true)
        {
            UpdateCenterView(POSx, POSy, step, sensitivity, smoothnessFactor);
            Sleep(1); // 这里只是为了简化示例,实际运行时可以去掉或替换为合适的循环条件
        }
    
        return 0;
    }
    

    这个版本的代码应该会使鼠标移动更加平滑,同时也能适应游戏窗口大小的变化。请将你的YOLO输出的坐标值POSxPOSy传递给UpdateCenterView函数。如果你的游戏窗口大小发生变化,可能需要重新调整timeIntervalsensitivity参数以获得最佳效果。

    评论 编辑记录

报告相同问题?

问题事件

  • 已结题 (查看结题原因) 4月22日
  • 创建了问题 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