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
相关产品推荐
相关产品推荐

