You need to enable JavaScript to run this app. Raylib开发2D游戏:玩家碰地面无法移动的问题求助
优惠活动
大模型
产品
解决方案
定价
更多

Raylib开发2D游戏:玩家碰地面无法移动的问题求助

核心问题定位

你当前的逻辑存在两个致命设计错误,直接导致贴地时输入完全失效:

  • 执行顺序完全颠倒:碰撞检测发生在plr矩形赋值之前,相当于用上一帧的旧碰撞盒判定当前帧的位置,检测结果完全不准。
  • 碰撞回退粒度太粗:只要检测到任意碰撞(包括重力导致的y方向轻微下沉),就把整个newPos(包含左右按键带来的x方向合法位移)全部回退到oldPos。只要玩家站在地面上,重力每帧都会把y方向往下拉一点,这一帧必然触发碰撞——你按左右键产生的x位移,直接跟着y的下沉量一起被回退抹掉,自然完全动不了。
  • 存在初始化缺陷:oldPos从未被赋值,程序启动初期会存在坐标野值。
修复方案

放弃“碰撞就整体回退上一帧位置”的粗粒度逻辑,改成分轴独立处理碰撞:每帧先记录当前位置,分别计算x、y方向的位移,分别检测两个方向是否碰撞,哪个方向碰了就只回退哪个方向的位移,不影响另一个方向的合法移动。

核心修复代码片段:

// 将原重力宏改为可变变量,支持落地时临时关闭
float gravity = 3.0f;

// 主循环核心逻辑
while(!WindowShouldClose())
{
    // 1. 记录当前帧初始位置作为回退基准
    pl.oldPos = pl.newPos;

    // 2. 计算x方向的输入位移
    float moveX = 0;
    if (IsKeyDown(KEY_RIGHT)) moveX += plSpeed;
    if (IsKeyDown(KEY_LEFT)) moveX -= plSpeed;

    // 3. 计算y方向的位移(上跳输入+重力)
    if (IsKeyDown(KEY_UP)) pl.newPos.y -= plSpeed;
    pl.newPos.y += gravity;

    // 4. 提前给碰撞盒赋值当前的候选位置,避免用过期数据检测
    plr.width = 30;
    plr.height = 30;
    plr.x = pl.newPos.x;
    plr.y = pl.newPos.y;

    // 5. 单独处理y方向碰撞(地面接触)
    if (CheckCollisionRecs(plr, floor))
    {
        // 只修正y坐标:贴在地面上边缘,不产生重叠
        pl.newPos.y = floor.y - plr.height;
        plr.y = pl.newPos.y;
        gravity = 0; // 落地后关闭重力,避免每帧持续下沉触发碰撞
    }
    else
    {
        gravity = 3.0f; // 在空中恢复重力
    }

    // 6. 单独处理x方向位移碰撞
    pl.newPos.x += moveX;
    plr.x = pl.newPos.x;
    if (CheckCollisionRecs(plr, floor))
    {
        // 只回退x方向的位移,不影响y方向的贴地状态
        pl.newPos.x -= moveX;
        plr.x = pl.newPos.x;
    }

    // 原有绘制逻辑保持不变
    BeginDrawing();
    ClearBackground(RAYWHITE);
    DrawRectangleRec(floor, GREEN);
    DrawRectangleRec(plr, pl.color);
    EndDrawing();
}

这套逻辑下,玩家站在地面时,y方向的位置会被校准到刚好贴住地面,x方向的左右输入只会被单独检测是否碰到障碍物,不会被重力导致的y方向碰撞连带回退,可正常响应移动输入。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.11.04 09:36:05