使用Raylib实现小球速度向量平滑过渡动画的问题求助
使用Raylib实现小球速度向量平滑过渡动画的问题求助
嘿,我看了你的代码,终于找到问题所在啦!现在小球要么瞬间跳一下就不动,要么一下子冲出去,主要是这几个原因:
- 移动逻辑只执行一次:你把小球的位置更新代码全放在了
IsMouseButtonReleased的分支里,只有松开鼠标的那一帧会动一下,之后的帧里完全没再更新位置,自然没法持续平滑移动。 - 重复更新位置:在鼠标松开的那一帧,你先算了一次
movementThisFrame加到位置上,紧接着又在if(ball.active)里再把speed加了一次,这会导致那一帧直接跳两倍距离,特别突兀。 - 速度瞬间拉满:你直接把拖动产生的向量赋值给
ball.speed,如果拖动距离大,速度会瞬间变得超大,小球一下就冲没影了,完全没有平滑的加速过程。
咱们来改改代码,实现你想要的平滑拉弓效果:
首先,给小球结构体加个targetSpeed变量,用来存我们最终要达到的目标速度,这样就能让当前速度慢慢过渡过去:
typedef struct Ball { Vector2 position; Vector2 speed; Vector2 targetSpeed; // 新增:用来做平滑过渡的目标速度 float radius; bool active; } Ball;
然后调整主循环的逻辑,把小球的移动更新放到每帧都执行的地方,再用线性插值实现速度的平滑过渡,还要加上蓄力预览线让操作更直观:
#include "raylib.h" typedef struct Ball { Vector2 position; Vector2 speed; Vector2 targetSpeed; float radius; bool active; } Ball; int main(void) { const int width = 1080; const int height = 720; static Ball ball = {0}; Vector2 pos1; Vector2 pos2; Vector2 posChange; float smoothFactor = 0.1f; // 平滑系数,越小加速越慢,可自己调 SetTargetFPS(60); InitWindow(width, height, "Midny is sad frfr"); Texture2D background = LoadTexture("green_checker.png"); // 初始化小球参数 ball.position = (Vector2){(float)width/4, height-80}; ball.speed = (Vector2){0, 0}; ball.targetSpeed = (Vector2){0, 0}; ball.radius = 8; ball.active = false; while (!WindowShouldClose()) { // 输入处理 if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) { pos1 = GetMousePosition(); // 按住鼠标时重置小球状态,方便重新蓄力 ball.active = false; ball.speed = (Vector2){0, 0}; ball.targetSpeed = (Vector2){0, 0}; } if (IsMouseButtonDown(MOUSE_BUTTON_LEFT)) { pos2 = GetMousePosition(); posChange = Vector2Subtract(pos2, pos1); } if (IsMouseButtonReleased(MOUSE_BUTTON_LEFT)) { // 设置目标速度,乘以0.2是调整力度,防止速度太大 Vector2 DirectionVelocityVector = Vector2Negate(posChange); ball.targetSpeed = Vector2Scale(DirectionVelocityVector, 0.2f); ball.active = true; } // 小球移动逻辑:每帧都执行! if (ball.active) { // 用线性插值让当前速度慢慢趋近目标速度,实现平滑加速 ball.speed = Vector2Lerp(ball.speed, ball.targetSpeed, smoothFactor); // 计算每帧移动量,乘以GetFrameTime保证不同帧率下移动速度一致 Vector2 movementThisFrame = Vector2Scale(ball.speed, GetFrameTime() * 100); ball.position = Vector2Add(ball.position, movementThisFrame); // 可选:边界反弹,防止小球飞出屏幕 if (ball.position.x - ball.radius < 0 || ball.position.x + ball.radius > width) { ball.speed.x *= -1; ball.targetSpeed.x *= -1; } if (ball.position.y - ball.radius < 0 || ball.position.y + ball.radius > height) { ball.speed.y *= -1; ball.targetSpeed.y *= -1; } } // 绘制部分 BeginDrawing(); ClearBackground(RAYWHITE); DrawTexture(background, 0, 0, WHITE); // 按住鼠标时绘制蓄力线,直观看到方向和力度 if (IsMouseButtonDown(MOUSE_BUTTON_LEFT)) { DrawLineV(ball.position, pos2, RED); } DrawCircleV(ball.position, ball.radius, WHITE); EndDrawing(); } // 别忘了释放资源! UnloadTexture(background); CloseWindow(); return 0; }
重点修改说明:
- 每帧更新移动:把小球的速度和位置更新移到主循环的通用逻辑里,只要小球激活,每帧都会动,这样就能持续平滑移动了。
- 速度平滑过渡:用
Vector2Lerp做线性插值,让当前速度逐渐接近目标速度,smoothFactor可以自己调,0.1的话加速比较平缓,数值越大加速越快。 - 移除重复更新:删掉了鼠标松开时重复更新位置的代码,现在统一在每帧逻辑里处理,避免瞬间跳步。
- 蓄力预览:按住鼠标时绘制一条红线,从球到鼠标位置,方便你直观看到蓄力的方向和力度。
- 边界反弹:加了可选的碰撞处理,小球碰到屏幕边缘会反弹,不会直接飞出去,体验更好。
- 资源收尾:加上了纹理释放和窗口关闭的代码,更规范。
这样改完之后,你拖动鼠标松开,小球就会平滑地加速向相反方向移动啦!
备注:内容来源于stack exchange,提问作者Midnight Demise
相关产品推荐
相关产品推荐

