Событийный SDL2

Я нахожусь в процессе упаковки SDL в объекты C ++. По сути, я просто устал видеть SDL_ в моем коде. Я хотел бы по крайней мере пространства имен … SDL :: Window. Я сделал это, все идет более или менее хорошо.

Проблема возникает с событиями. Я бы хотел, чтобы это было обусловлено событиями (обратными вызовами), а не опрашиванием очереди событий. (подпрограммы распространения, которые вы должны написать, чтобы SDL_Event соответствовал абстракции, которую я разработал, являются болезненными).

Взять, к примеру, класс Window. Его конструктор вызывает

SDL_AddEventWatch(window_events, this);

где window_events является статическим членом класса Window. Он ловит что-нибудь типа SDL_WINDOWEVENT.

int Window::window_events(void* data, SDL::Events::Event* ev)
{
if (ev->type == SDL::Events::Window::Any)
{
auto win = static_cast<Window *>(data);
if (ev->window.windowID == SDL_GetWindowID(win->mWindow))
{
std::vector<event_callback> callbacks = win->mWindowCallbacks;
for (const auto cbk : callbacks)
{
cbk(*ev);
}
}
}
return 0;
}

Мой класс Window также содержит методы hook и unhook. Каждый принимает std :: function. Это то, что mWindowCallbacks представляет собой коллекцию. Любая внешняя процедура, заинтересованная в событии, получает копию, переданную ему.

//...
using event_callback = std::function<void(SDL::Events::Event)>;
//...

template<typename T> bool
find_func(const T & object,
const std::vector<T> & list,
int * location=nullptr)
{
int offset = 0;

for (auto single : list)
{
if (single.target<T>() ==
object.target<T>())
{
if (location != nullptr) *location = offset;
return true;
}
offset++;
}
return false;
}

void
Window::hook(event_callback cbk)
{
if (!find_func(cbk, mWindowCallbacks))
{
mWindowCallbacks.push_back(cbk);
}
}

void
Window::unhook(event_callback cbk)
{
int offset = 0;
if (find_func(cbk, mWindowCallbacks, &offset))
{
mWindowCallbacks.erase(mWindowCallbacks.begin() + offset);
}
}

Использование:

///...
void cbk_close(SDL::Events::Event e)
{
if (e.window.event == SDL::Events::Window::Close)
{
window.close();
quit = true;
}
}
///...
std::function<void(SDL::Events::Event)> handler = cbk_close;
SDL::Window window;
window.hook(handler);

Близко:

void Window::close()
{
SDL_DelEventWatch(window_events, this);
SDL_DestroyWindow(mWindow);
mWindowCallbacks.clear();
}

Мне это не кажется ужасным дизайном.
Когда вы нажимаете close в окне, вызывается cbk_close, он вызывает close, устанавливает флаг выхода … Затем он возвращается к циклу window_events. Как и ожидалось … Однако эта функция, похоже, не возвращает управление программе.

Это то, что мне нужно помочь. Я не очень понимаю, почему. Я думаю, что это угон основного потока, так как программа выйдет, как только закроется эта функция, если у вас есть одно окно, или … сбой, если у вас есть два.

Я на правильном пути с этим? Я застрял на этой неделе. Это действительно довольно бесит. Для всех, кто хочет поиграть с этим; вот git репо для полного кода.
Windows, решение Visual Studio 2015 / VC.
https://bitbucket.org/andywm/sdl_oowrapper/

1

Решение

Итак, я думаю, что я более или менее понимаю, что здесь происходит сейчас.

SDL_AddEventWatch(void (*)(void *, SDL_Event*), void *)

Если вы используете C ++, вы должны установить соглашение о вызовах.

SDLCALL

В моем случае;

int SDLCALL
Window::window_events(void* data, SDL::Events::Event* ev)

Это, кажется, мешает системе событий sdl захватывать основной поток.

Что касается его сбоя с несколькими окнами … Хорошо, если я уберу эту строку

SDL_DelEventWatch(window_events, this);

это не терпит крах … Не совсем уверен, почему, но если я выясню это, я исправлю свой ответ — и если кто-то с более опытным с SDL мог бы заполнить меня … Это было бы здорово.

0

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]