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

Raylib C++平台游戏碰撞问题:仅地面顶部碰撞生效

Raylib C++平台游戏碰撞检测问题修复

问题根源

你的代码存在几个核心问题导致碰撞仅在玩家站在地面顶部生效:

  • 玩家碰撞矩形计算存在笔误:GetRectangle()中的y - h / x是错误逻辑,会导致碰撞区域偏移
  • 碰撞响应逻辑过于粗暴,仅处理了玩家站在地面顶部的场景,未考虑其他方向的碰撞
  • 移动与重力未结合deltaTime,帧率变化会导致游戏速度不稳定

修复后的完整代码

#include "raylib.h"
#include <stdio.h>
#include <math.h>

struct square
{
    float x, y;
    float w, h;
    float gravity;
    float velocity;
    float speed;

    // 修复矩形计算:以玩家中心为原点生成正确的碰撞矩形
    Rectangle GetRectangle() {
        return Rectangle{ x - w / 2, y - h / 2, w, h };
    }

    void drawsquare() {
        DrawRectangleRec(GetRectangle(), RED);
    }
};

struct obby
{
    float x, y;
    float w, h;

    Rectangle GetRectangle() {
        return Rectangle{ x, y, w, h };
    }

    void drawobby() {
        DrawRectangleRec(GetRectangle(), BROWN);
    }
};

int currentLevel = 1;

int main(void) 
{
    InitWindow(1100, 700, "Basic Platformer");
    SetWindowState(FLAG_VSYNC_HINT);
    SetTargetFPS(60);

    square player;
    player.x = 100;
    player.y = 400;
    player.w = 80;
    player.h = 80;
    player.gravity = 0.0f;
    player.velocity = 300.0f; // 调整为适配deltaTime的数值
    player.speed = 200.0f;

    obby floor1;
    floor1.x = 50;
    floor1.y = 575;
    floor1.w = 160;
    floor1.h = 30;

    while (!WindowShouldClose()) 
    {
        float deltaTime = GetFrameTime();

        // 重力更新(结合deltaTime保证帧率无关)
        player.gravity += player.velocity * deltaTime;
        player.y += player.gravity * deltaTime;

        // 水平移动(分离A/D按键判断,避免互锁)
        if (IsKeyDown(KEY_A)) {
            player.x -= player.speed * deltaTime;
        }
        if (IsKeyDown(KEY_D)) {
            player.x += player.speed * deltaTime;
            currentLevel = 2;
        }

        // 跳跃触发
        if (IsKeyPressed(KEY_W)) {
            player.gravity = -250.0f;
        }

        // 碰撞检测与多方向响应
        Rectangle playerRec = player.GetRectangle();
        Rectangle floorRec = floor1.GetRectangle();

        if (CheckCollisionRecs(playerRec, floorRec)) {
            // 计算四个方向的碰撞重叠量
            float overlapTop = floorRec.y - (playerRec.y + playerRec.height);
            float overlapBottom = (floorRec.y + floorRec.height) - playerRec.y;
            float overlapLeft = floorRec.x - (playerRec.x + playerRec.width);
            float overlapRight = (floorRec.x + floorRec.width) - playerRec.x;

            // 找到最小重叠的方向,确定碰撞面
            float minOverlap = fminf(fminf(fabsf(overlapTop), fabsf(overlapBottom)), 
                                    fminf(fabsf(overlapLeft), fabsf(overlapRight)));

            if (minOverlap == fabsf(overlapTop)) {
                // 玩家从上方碰撞地面(站在地面)
                player.y = floorRec.y - playerRec.height;
                player.gravity = 0.0f;
            }
            else if (minOverlap == fabsf(overlapBottom)) {
                // 玩家从下方碰撞地面(比如跳穿场景)
                player.y = floorRec.y + floorRec.height;
                player.gravity = 0.0f;
            }
            else if (minOverlap == fabsf(overlapLeft)) {
                // 玩家从左侧碰撞地面
                player.x = floorRec.x - playerRec.width;
            }
            else if (minOverlap == fabsf(overlapRight)) {
                // 玩家从右侧碰撞地面
                player.x = floorRec.x + floorRec.width;
            }
        }

        BeginDrawing();
        ClearBackground(GRAY);

        // 关卡渲染(保留你的预留逻辑)
        if (currentLevel == 1) {
            floor1.drawobby();
        }

        player.drawsquare();
        EndDrawing();
    }

    CloseWindow();
    return 0;
}

关键修复说明

  • 修正碰撞矩形计算:将y - h / x改为y - h / 2,确保玩家碰撞区域以自身中心为原点正确生成,这是碰撞检测异常的核心原因
  • 帧率无关运动:所有移动、重力计算都乘以deltaTime,保证游戏在不同帧率下运行速度一致
  • 多方向碰撞响应:通过计算四个方向的碰撞重叠量,精准判断碰撞面,支持顶部、底部、左侧、右侧的碰撞处理
  • 优化碰撞位置修正:根据实际重叠量调整玩家位置,避免粗暴赋值导致的穿模或位置异常

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 10:26:02