Epic Online Services サンプルの AuthAndFriends のコードリーディング ③
今回からイベントループに入っていきますが、SDL2 を使った GUI プログラミングに不慣れなので少しずつ見ていきます。
イベントループ部分
int main(int Argc, char* Args[]) { // 略 //Main loop flag bool bQuit = false; //Event handler SDL_Event Event; //Enable text input SDL_StartTextInput(); //While application is running while (!bQuit) { //Handle events on queue while (SDL_PollEvent(&Event) != 0) { bQuit = ProcessSDLEvents(&Event); } Main->Tick(); //Update screen SDL_GL_SwapWindow(Main->GetWindow()); } //Disable text input SDL_StopTextInput();
上記は main
のイベントループ部分のみ抜粋したものです。
ProcessSDLEvents
メソッドがイベントハンドルをしているようです。
ProcessSDLEvents
bool ProcessSDLEvents(SDL_Event *Event) { FUIEvent InputEvent = FInput::ProcessSDLEvent(*Event); if (InputEvent.GetType() != EUIEventType::None) { FGame::Get().GetMenu()->OnUIEvent(InputEvent); } else { switch (Event->type) { case SDL_QUIT: { return true; } case SDL_WINDOWEVENT: { ProcessWindowEvent(&Event->window); break; } default: break; } } return false; }
FInput::ProcessSDLEvent
ここでは、 SDL_Event
を FUIEvent
に変換しています。詳細は省略しますが、 FUIEvent
は以下の種類があり、 SDL_Event
の特定の操作イベントが割り当てられます。
enum class EUIEventType : unsigned char { None, MousePressed, MouseReleased, MouseWheelScrolled, KeyPressed, KeyReleased, TextInput, CopyText, SelectAll, PasteText, FullscreenToggle, SearchText, FocusGained, FocusLost, FriendInviteSent, InviteToSession, Last = FriendInviteSent };
else 部分
else 部分は QUIT か Window 操作時に関するものです。 QUIT の場合は true
が返却され、イベントループを抜けるようになっています。
InputEvent が None 以外のとき
FGame::Get().GetMenu()->OnUIEvent(InputEvent)
が呼び出されています。
前回見たとおりで FGame
は多くのゲームの要素を管理しており、 GetMenu
では FMenu
のインスタンスを取得します。
FMenu::OnUIEvent
実際には親クラスである FBaseMenu::OnUIEvent
が呼び出されます。
void FBaseMenu::OnUIEvent(const FUIEvent& Event) { #ifdef EOS_DEMO_SDL // FullScreenToggle に関するコードがあるが省略 else #endif if (Event.GetType() == EUIEventType::MousePressed) { for (DialogPtr NextDialog : Dialogs) { if (NextDialog->CheckCollision(Event.GetVector())) { NextDialog->OnUIEvent(Event); } else { NextDialog->SetFocused(false); } } } else { for (DialogPtr NextDialog : Dialogs) { NextDialog->OnUIEvent(Event); } } if (AuthDialogs) AuthDialogs->OnUIEvent(Event); }
Dialogs 配列の内部
FBaseMenu
の内部では以下が Dialogs
配列に追加されています。
- ConsoleDialog
- FriendsDialog
- ExitDialog (非表示)
- PopupDialog (非表示)
また FMenu
の内部では以下が追加されています。
- CustomInvitesDialog
CheckCollision
NextDialog->CheckCollision
は Dialog::CheckCollision
に実装されており、Dialog
内部の Widgets
(UI 要素) の座標とマウスポイントの座標がオーバーラップしているかどうかを判定しています。
AuthDialogs
AuthDialogs
は Dialogs
配列に入っていないことからも、少し特別な扱いになっています。
void FBaseMenu::CreateAuthDialogs() { AuthDialogs = std::make_shared<FAuthDialogs>( FriendsDialog, L"Friends", BoldSmallFont->GetFont(), SmallFont->GetFont(), TinyFont->GetFont()); AuthDialogs->Create(); }
AuthDialogs
は生成時に FriendsDialog
も受け取るようになっています。
void FBaseMenu::Create() { BackgroundImage->Create(); TitleLabel->Create(); TitleLabel->SetFont(BoldLargeFont->GetFont()); FPSLabel->Create(); FPSLabel->SetFont(SmallFont->GetFont()); CreateConsoleDialog(); CreateAuthDialogs(); CreateExitDialog(); CreatePopupDialog(); }
void FMenu::Create() { CreateFriendsDialog(); // creates console dialog, which is needed for creating custom invites dialog FBaseMenu::Create(); CreateCustomInvitesDialog(); }
上記のように、FriendsDialog
だけは FMenu
で生成され、その後 FBaseMenu
で AuthDialog
を含む他の Dialog
が生成されています。
まとめ
今日はイベントループに入り、イベントをまず受け取っている FMenu
の構成要素を眺めました。
次は FMenu
の構成要素がどのように UI にセットされているかなど見てみたいと思います。