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

使用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;
}

重点修改说明:

  1. 每帧更新移动:把小球的速度和位置更新移到主循环的通用逻辑里,只要小球激活,每帧都会动,这样就能持续平滑移动了。
  2. 速度平滑过渡:用Vector2Lerp做线性插值,让当前速度逐渐接近目标速度,smoothFactor可以自己调,0.1的话加速比较平缓,数值越大加速越快。
  3. 移除重复更新:删掉了鼠标松开时重复更新位置的代码,现在统一在每帧逻辑里处理,避免瞬间跳步。
  4. 蓄力预览:按住鼠标时绘制一条红线,从球到鼠标位置,方便你直观看到蓄力的方向和力度。
  5. 边界反弹:加了可选的碰撞处理,小球碰到屏幕边缘会反弹,不会直接飞出去,体验更好。
  6. 资源收尾:加上了纹理释放和窗口关闭的代码,更规范。

这样改完之后,你拖动鼠标松开,小球就会平滑地加速向相反方向移动啦!

备注:内容来源于stack exchange,提问作者Midnight Demise

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.23 07:04:31