将C++对象方法作为SDL_EventFilter传递

q1qsirdb  于 11个月前  发布在  其他
关注(0)|答案(2)|浏览(88)

我正在尝试使用SDL 2在C++中创建一个游戏,当然我想检查窗口大小调整事件.

bool Game::SetupSDL()
{
    if (SDL_Init(SDL_INIT_VIDEO) < 0)
    {
        std::cout << "SDL initialization failed: " << SDL_GetError() << std::endl;
        return false;
    }

    window = SDL_CreateWindow(
        "SDL",
        SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
        640, 480,
        SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE);

    if (window == NULL)
    {
        std::cout << "SDL window creation failed: " << SDL_GetError() << std::endl;
        return false;
    }

    if (TTF_Init() < 0)
    {
        return false;
    }

    renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);

    SDL_AddEventWatch(OnResize, window);

    return true;
}

字符串
OnResize是这样初始化的:

int Game::OnResize(void *data, SDL_Event *event)
{
    if (event->type == SDL_WINDOWEVENT && event->window.event == SDL_WINDOWEVENT_RESIZED)
    {
        SetScale();
        states[state]->OnResize(*this);
    }
    return 0;
}


然而,当我尝试编译它时,我得到以下结果:

error: cannot convert 'Game::OnResize' from type 'int (Game::)(void*, SDL_Event*)' to type 'SDL_EventFilter {aka int (*)(void*, SDL_Event*)}'
  SDL_AddEventWatch(this->OnResize, window);


所以看起来我把一个示例方法作为一个SDL_FilterEvent来传递是很复杂的.

dauxcl2d

dauxcl2d1#

问题:

为了向SDL_AddEventWatch注册事件回调,
你需要以SDL_EventFilter类型的函数的形式提供一个回调:

int (*SDL_EventFilter)(void *userdata, SDL_Event *event);

字符串
这应该是一个自由函数,或者是一个类的静态方法。它不能是一个非静态方法,因为这样的方法需要一个Game示例(this指针)才能被调用。

解决方案:

为了使用非静态方法作为回调,可以使用userdata参数作为上下文。
注册事件处理程序时,将this(即Game*)作为userdata与静态方法一起传递:

static int Game::OnResizeEventCallback(void *userdata, SDL_Event *event);  // see implementation below

// ...

//---------------------------------------vvvvv-
SDL_AddEventWatch(OnResizeEventCallback, this);


然后,当你得到回调函数时,将userdata转换回Game*,并调用非静态方法:

static int Game::OnResizeEventCallback(void *userdata, SDL_Event *event)
{
    // Retrieve your instance:
    Game* pThis = reinterpret_cast<Game*>(userdata);
    // Call your non-static method with it:
    pThis->OnResize(event);
}

nhhxz33t

nhhxz33t2#

你会得到这个错误,因为语言不知道如何访问类的正确示例来调用方法。
您可以将Game::OnResize替换为Game类外部的自由浮动函数,该函数可以访问指向您的游戏示例的指针,并随沿着SDL事件数据转发,也可以在Game类中使用静态方法。
如果你想把它全部保存在你的类中(就像我倾向于做的那样),你可以用一个静态方法来替换Game::OnResize,这个静态方法可以访问你的游戏的指针,然后创建一个新的非静态方法来实际处理事件。然后静态方法可以把事件转发给非静态方法。
就像这样:

// =========================================================================
// game.h
// =========================================================================

class Game
{
    public:
    
        // public stuff...
        
    private:
    
        // private stuff...
        
        // replace OnResize with this:
        static int OnSDLEvent(void *data, SDL_Event *event);
        
        // new function:
        int HandleSDLEvent(void *data, SDL_Event *event);
};

// =========================================================================
// game.cpp
// =========================================================================

// somewhere at the top...
Game *g_Game{}; // global pointer to the game, only in this file

Game::Game()
{
    // let's make g_Game point to our actual game instance
    // in your game's constructor.

    // or it could be in Game::SetupSDL() or wherever...
    // it just needs to happen before adding your event watch.

    // this is so the static method has an instance to work with.
    g_Game = this;
}

// here's the static method that gets called by SDL
int Game::OnSDLEvent(void *data, SDL_Event *event)
{
    // just pass along the event data.
    return g_Game->HandleSDLEvent(data, event);
}

// and here's where you actually handle the event!
int Game::HandleSDLEvent(void *data, SDL_Event *event)
{
    if (event->type == SDL_WINDOWEVENT && event->window.event == SDL_WINDOWEVENT_RESIZED)
    {
        SetScale();
        states[state]->OnResize(*this);
    }
    return 0;
}

// finally, feed SDL with our static method we created
bool Game::SetupSDL()
{
    // setup code here...

    // now we pass in our static method
    SDL_AddEventWatch(OnSDLEvent, window);

    // etc.
}

字符串

相关问题