You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++ SFML实现玩家恒定速度平滑直线移动至鼠标右键点击点

问题背景

开发俯视角游戏,需要实现类《英雄联盟》的右键点击移动逻辑:角色以恒定速度沿直线平滑移动到点击位置。原有实现存在路径锯齿、单轴先到达终点无法同步、角色在目标点抖动的问题。
复现场景:角色坐标(500,500),点击坐标(760,124)时,X轴距离差260、Y轴距离差376,原有逻辑下X轴先抵达目标,Y轴单独移动导致路径呈折线。
原有代码逻辑缺陷:X、Y轴独立以固定步长位移,未按两轴距离比例分配移动步长,且无到达判定逻辑。

实现原理

要实现恒定速度直线移动,核心是基于方向向量归一化拆分轴移动量:

  • 右键点击时仅记录一次目标点坐标,避免每帧读取鼠标位置导致角色跟随鼠标移动
  • 每帧计算角色当前位置到目标点的X/Y轴差值、两点直线总距离
  • 当总距离小于停止阈值(规避浮点计算误差)时,判定到达目标,直接将角色对齐到目标点并停止移动,解决抖动问题
  • 总距离大于阈值时,将X/Y轴差值除以总距离得到归一化方向向量,再乘以固定移动速度,得到当前帧X/Y轴的实际移动量。该方式能保证两轴移动量的比例和距离差比例完全一致,角色全程沿直线移动,两轴同步到达终点,且合速度始终等于设定的固定移动速度。
代码修改

头文件调整(Player.h)

在私有成员变量区补充停止阈值变量即可,其余原有逻辑保持不变:

#include "Libs.cpp"
class player
{
public:
    player();
    virtual ~player();
    void update(RenderWindow* Twin);
    void render(RenderTarget* target);

private:
    void initBody();
    void initVarribles();
    
    Texture playerT;
    Sprite playerS;

    bool allowMove;
    int movedTimes;
    float mX;
    float mY;
    bool tempB;
    float movementSpeed;
    float stopThreshold; // 新增:到达目标的判定阈值,避免浮点误差抖动
};

逻辑实现调整(Player.cpp)

引入cmath头文件支持平方根计算,替换原有独立判断X/Y轴移动的逻辑:

#include <cmath> // 新增,用于距离计算

void player::initVarribles()
{
    movementSpeed = 2.0f;
    tempB = false;
    allowMove = false;
    movedTimes = 0;
    mX = 0.0f;
    mY = 0.0f;
    stopThreshold = 1.5f; // 阈值设为1~2像素即可,可根据手感调整
}

void player::update(RenderWindow* Twin)
{
    if (Mouse::isButtonPressed(Mouse::Right))
    {
        allowMove = true;
        tempB = false;
    }
    
    // 仅在刚触发右键点击时记录一次目标点
    if (tempB == false)
    {
        mX = Mouse::getPosition(*Twin).x;
        mY = Mouse::getPosition(*Twin).y;
        tempB = true;
    }

    if (allowMove == true)
    {   
        Vector2f currentPos = playerS.getPosition();
        float dx = mX - currentPos.x;
        float dy = mY - currentPos.y;
        float totalDistance = sqrt(dx*dx + dy*dy);

        // 到达目标点判定
        if (totalDistance < stopThreshold)
        {
            allowMove = false;
            playerS.setPosition(mX, mY); // 对齐坐标消除位置误差
            return;
        }

        // 按比例拆分速度到两个轴,保证直线移动
        float frameMoveX = (dx / totalDistance) * movementSpeed;
        float frameMoveY = (dy / totalDistance) * movementSpeed;
        playerS.move(frameMoveX, frameMoveY);
    }
}
效果验证

针对给出的复现参数计算:

  • 初始位置(500,500),目标点(760,124),dx=260,dy=-376
  • 总直线距离约为457.12像素
  • 每帧X轴移动量约1.14像素,Y轴移动量约-1.65像素,比例与两轴距离差完全一致
  • 两轴会同步抵达目标点,移动路径为严格直线,无锯齿、无过冲抖动

可选优化:如果需要适配不同帧率保持移动速度恒定,可以在计算移动量时乘以帧间隔deltaTime,将movementSpeed单位改为像素/秒即可。

内容的提问来源于stack exchange,提问作者Jakebix

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 13:18:22