Я нахожусь в процессе упаковки 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/
Итак, я думаю, что я более или менее понимаю, что здесь происходит сейчас.
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 мог бы заполнить меня … Это было бы здорово.
Других решений пока нет …