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

如何在SDL2中使用b2Draw?DrawSegment方法未被调用

问题:Box2D中DebugDrawer的DrawSegment方法未被调用

我期望控制台输出hello,但重载的DrawSegment方法始终没被触发,相关代码如下:


DebugDrawer.cpp

#include "DebugDrawer.h"
#include <iostream>

DebugDrawer::DebugDrawer()
{

}

void DebugDrawer::DrawSegment(const b2Vec2 &p1, const b2Vec2 &p2, const b2Color &color)
{
    std::cout << "hello" << std::endl;
}

void DebugDrawer::DrawSolidPolygon(const b2Vec2 *vertices, int32 vertexCount, const b2Color &color) { }
void DebugDrawer::DrawPolygon(const b2Vec2 *vertices, int32 vertexCount, const b2Color &color) { }
void DebugDrawer::DrawPoint(const b2Vec2 &p, float size, const b2Color &color) { }
void DebugDrawer::DrawCircle(const b2Vec2 &center, float radius, const b2Color &color) { }
void DebugDrawer::DrawSolidCircle(const b2Vec2 &center, float radius, const b2Vec2 &axis, const b2Color &color) { }
void DebugDrawer::DrawTransform(const b2Transform &xf) { }

DebugDrawer.h

#ifndef DEBUGDRAWER_H
#define DEBUGDRAWER_H

#include "box2d/b2_draw.h"

class DebugDrawer : public b2Draw
{
public:
    DebugDrawer();

private:
    void DrawSolidPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color);
    void DrawPoint (const b2Vec2 &p, float size, const b2Color &color);
    void DrawPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color);
    void DrawCircle(const b2Vec2& center, float radius, const b2Color& color);
    void DrawSolidCircle(const b2Vec2& center, float radius, const b2Vec2& axis, const b2Color& color);
    void DrawSegment(const b2Vec2& p1, const b2Vec2& p2, const b2Color& color);
    void DrawTransform(const b2Transform& xf);
};

#endif // DEBUGDRAWER_H

创建矩形物体代码

b2PolygonShape shape;
shape.SetAsBox(50.f / WORLD_SCALE, 50.f / WORLD_SCALE);

b2BodyDef bdef;
bdef.type = b2_staticBody;

pBody = pWorld->CreateBody(&bdef);
pBody->CreateFixture(&shape, 2.f);

调试绘制设置(main.cpp中)

pDebugDrawer = new DebugDrawer();
pWorld->SetDebugDraw(pDebugDrawer);

uint32 flags = 0;
flags += b2Draw::e_shapeBit;
flags += b2Draw::e_jointBit;
flags += b2Draw::e_centerOfMassBit;
flags += b2Draw::e_aabbBit;
flags += b2Draw::e_pairBit;
pDebugDrawer->SetFlags(flags);

主循环中的调用

pWorld->Step(0.016f, 8, 3);
pWorld->DebugDraw();

完整main.cpp

#ifdef _WIN32
#include <windows.h>
extern "C" __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
extern "C" __declspec(dllexport) DWORD AmdPowerXpressRequestHighPerformance = 0x00000001;
#endif

#define SDL_MAIN_HANDLED

#include <glad/glad.h>
#include <SDL.h>
#include <box2d/box2d.h>
#include <iostream>
#include "DebugDrawer.h"

const float WORLD_SCALE = 30.f;
b2World* pWorld;
DebugDrawer* pDebugDrawer;
b2Body* pBody;

int main()
{
    // Initialize the SDL2 library
    if (SDL_Init(SDL_INIT_VIDEO) != 0)
    {
        SDL_Log("Failed to initialize the SDL2 library: %s", SDL_GetError());
        return 1;
    }

    // Create a SDL window
    const int WIN_WIDTH = 500;
    const int WIN_HEIGHT = 500;
    SDL_Window* window = SDL_CreateWindow(
        "Empty Window",
        SDL_WINDOWPOS_CENTERED,
        SDL_WINDOWPOS_CENTERED,
        WIN_WIDTH, WIN_HEIGHT,
        SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL);

    // Create a SDL renderer
    SDL_Renderer* renderer = SDL_CreateRenderer(
        window, -1, SDL_RENDERER_ACCELERATED);
    if (!renderer)
    {
        SDL_Log("Failed to create a SDL renderer %s", SDL_GetError());
        return 1;
    }

    SDL_GLContext context = SDL_GL_CreateContext(window);

    // Initialize the GLAD library
    if (!gladLoadGL())
    {
        SDL_Log("Failed to initialize the GLAD library");
        return 1;
    }

    glViewport(0, 0, WIN_WIDTH, WIN_HEIGHT);
    glClearColor(0.1f, 0.1f, 0.1f, 1.0f);

    b2Vec2 gravity(0.f, 9.8f);
    pWorld = new b2World(gravity);

    pDebugDrawer = new DebugDrawer();
    pWorld->SetDebugDraw(pDebugDrawer);

    uint32 flags = 0;
    flags += b2Draw::e_shapeBit;
    flags += b2Draw::e_jointBit;
    flags += b2Draw::e_centerOfMassBit;
    flags += b2Draw::e_aabbBit;
    flags += b2Draw::e_pairBit;
    pDebugDrawer->SetFlags(flags);

    b2PolygonShape shape;
    shape.SetAsBox(50.f / WORLD_SCALE, 50.f / WORLD_SCALE);

    b2BodyDef bdef;
    bdef.type = b2_staticBody;

    pBody = pWorld->CreateBody(&bdef);
    pBody->CreateFixture(&shape, 2.f);

    SDL_Event event;
    bool running = true;
    SDL_PollEvent(&event);

    while (running)
    {
        switch (event.type)
        {
        case SDL_QUIT:
            running = false;
            break;
        case SDL_KEYDOWN:
            switch (event.key.keysym.sym)
            {
            case SDLK_ESCAPE:
                running = false;
                break;
            }
            break;
        }

        glClear(GL_COLOR_BUFFER_BIT);

        pWorld->Step(0.016f, 8, 3);
        pWorld->DebugDraw();

        SDL_GL_SwapWindow(window);
        SDL_PollEvent(&event);
    }

    delete pWorld;
    delete pDebugDrawer;

    SDL_GL_DeleteContext(context);
    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);
    SDL_Quit();
    return 0;
}

解决方案

1. 修正方法的访问权限

b2Draw基类中的所有绘制方法都是public虚函数,但你在子类中把DrawSegment等方法设为了private。基类调用这些方法时无法访问子类的私有实现,实际执行的是基类的空方法,而非你写的输出逻辑。

修改DebugDrawer.h,将所有重载方法改为public,并加上override关键字确保重载正确:

class DebugDrawer : public b2Draw
{
public:
    DebugDrawer();

    void DrawSolidPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color) override;
    void DrawPoint (const b2Vec2 &p, float size, const b2Color &color) override;
    void DrawPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color) override;
    void DrawCircle(const b2Vec2& center, float radius, const b2Color& color) override;
    void DrawSolidCircle(const b2Vec2& center, float radius, const b2Vec2& axis, const b2Color& color) override;
    void DrawSegment(const b2Vec2& p1, const b2Vec2& p2, const b2Color& color) override;
    void DrawTransform(const b2Transform& xf) override;
};

2. 触发DrawSegment的场景说明

DrawSegment不会在绘制普通静态多边形时被调用,它的触发场景包括:

  • 启用e_jointBit时,绘制关节的连接线
  • 启用e_pairBit时,绘制碰撞对的重叠部分
  • 手动在其他绘制方法中调用DrawSegment

如果需要测试DrawSegment,可以添加两个物体并创建关节,或者在DrawPolygon中遍历多边形顶点调用DrawSegment绘制边。

3. 验证物体是否在视口内

虽然你的静态物体默认在原点,但可以确认世界坐标转屏幕坐标的逻辑是否正确,确保物体处于视口范围内,否则调试绘制可能不会触发。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 10:54:14