핚국산업기술대학교 제 14 강 GUI (III) 이대현교수
학습안내 학습목표 CEGUI 라이브러리를이용하여, 게임메뉴 UI 를구현해본다. 학습내용 CEGUI 레이아웃의로딩및렌더링. OIS 와 CEGUI 의연결. CEGUI 위젯과이벤트의연동.
UI 구현 : 하드코딩방식 C++ 코드를이용하여, 코드내에서직접위젯들을생성및설정 CEGUI::PushButton* resumebutton = (CEGUI::PushButton*)CEGUI::WindowManager::getSingleton().createWindow("TaharezLook/ Button", Resume"); meditorguisheet->addchildwindow(resumebutton); resumebutton->setposition(cegui::uvector2(cegui::udim(0.35f,0),cegui::udim(0.45f,0))); resumebutton->setsize(cegui::uvector2(cegui::udim(0.3f, 0), CEGUI::UDim(0.1f, 0))); resumebutton->settext("resume");
UI 구현 :.layout 파일의이용 레이아웃에디터를이용하여구성설정 코드내에서.layout 파일을로딩하면서, 화면구성 loadwindowlayout("lecturetitle.layout");
마우스및키입력과 CEGUI 의연동 CEGUI 는자체적으로키및마우스입력을받아들이는로직을갖고있지않음. 외부입력을 CEGUI 측으로전달 (Injection) 해주는연결부를따로구현해야함. injectmousemove, injectmousewheelchange injectmousebuttonup, injectmousebuttondown injectkeyup, injectkeydown injectchar OIS Layer CEGUI Layer
위젯과이벤트의연결 PushButton::EventClicked bool TitleState::startGame(const CEGUI::EventArgs &evt)... 이벤트처리루틴...
실습 TitleUI 게임타이틀 UI 의구현
CEGUI Library Download 강의홈페이지에서 Visual Studio version 에맞는라이브러리를다운로드및압축해제. CEGUI_HOME 환경변수설정.
CEGUI 설정 : include 디렉토리설정
CEGUI 설정 : CEGUI 라이브러리설정
CEGUI 설정 : DLL 준비 CEGUI 의 DLL 파일들을실행폴더에담아야함 CEGUIBase_d.dll CEGUIExpatParser_d.dll CEGUIFalagardWRBase_d.dll CEGUIOgreRenderer_d.dll CEGUITinyXMLParser_d.dll Release mode 의경우는 _d 를뺀 DLL 복사필요
TitleState.cpp bool TitleState::startGame(const CEGUI::EventArgs &evt) mgamestart = true; 실습 return true; void TitleState::enter(void) mcontinue = true; mgamestart = false; mtitlelayout = ceguiwindowmanager->loadwindowlayout("lecturetitle.layout"); ceguisystem->setguisheet(mtitlelayout); ceguiwindowmanager->getwindow("startgamebutton")->subscribeevent( CEGUI::PushButton::EventClicked, CEGUI::Event::Subscriber(&TitleState::startGame, this)); void TitleState::exit(void) ceguisystem->setguisheet(null); ceguiwindowmanager->getwindow("startgamebutton")->removeevent(cegui::pushbutton::eventclicked); ceguiwindowmanager->destroywindow(mtitlelayout); bool TitleState::frameEnded(GameManager* game, const FrameEvent& evt) if (mgamestart) game->changestate(playstate::getinstance()); return mcontinue;
GameManager.cpp (1) 실습 void GameManager::init(void)... 중략... mceguirenderer = &CEGUI::OgreRenderer::bootstrapSystem(); ceguischememanager->create("lectureskin.scheme"); unsigned int w, h, d; int left, top; mwindow->getmetrics(w, h, d, left, top); const OIS::MouseState &ms = mmouse->getmousestate(); ms.width = w; ms.height = h;
GameManager.cpp (2) CEGUI::MouseButton GameManager::convertButton(OIS::MouseButtonID buttonid) switch (buttonid) case OIS::MB_Left: return CEGUI::LeftButton; case OIS::MB_Right: return CEGUI::RightButton; case OIS::MB_Middle: return CEGUI::MiddleButton; default: return CEGUI::LeftButton; bool GameManager::mouseMoved(const OIS::MouseEvent &e) CEGUI::Point mousepos = CEGUI::MouseCursor::getSingleton().getPosition(); mousepos.d_x = e.state.x.abs; mousepos.d_y = e.state.y.abs; CEGUI::MouseCursor::getSingleton().setPosition(mousePos); ceguisystem->injectmousemove(e.state.x.rel, e.state.y.rel); ceguisystem->injectmousewheelchange(e.state.z.rel); return states.back()->mousemoved(this, e); bool GameManager::mousePressed(const OIS::MouseEvent &e, OIS::MouseButtonID id ) ceguisystem->injectmousebuttondown(convertbutton(id)); return states.back()->mousepressed(this, e, id); bool GameManager::mouseReleased(const OIS::MouseEvent &e, OIS::MouseButtonID id ) ceguisystem->injectmousebuttonup(convertbutton(id)); return states.back()->mousereleased(this, e, id); 실습
GameManager.cpp (3) 실습 bool GameManager::keyPressed(const OIS::KeyEvent &e) ceguisystem->injectkeydown(e.key); ceguisystem->injectchar(e.text); return states.back()->keypressed(this, e); bool GameManager::keyReleased(const OIS::KeyEvent &e) ceguisystem->injectkeyup(e.key); return states.back()->keyreleased(this, e);
실행화면 : Title UI ( 화면크기를 1024x768 로설정필요 )
CEGUI 라이브러리초기화 mceguirenderer = &CEGUI::OgreRenderer::bootstrapSystem(); ceguischememanager->create("lectureskin.scheme"); #define ceguiwindowmanager (CEGUI::WindowManager::getSingletonPtr()) #define ceguisystem (CEGUI::System::getSingletonPtr()) #define ceguischememanager (CEGUI::SchemeManager::getSingletonPtr()) GameManager.h unsigned int w, h, d; int left, top; mwindow->getmetrics(w, h, d, left, top); const OIS::MouseState &ms = mmouse->getmousestate(); ms.width = w; ms.height = h;
OIS 마우스클릭을 CEGUI 의연결 CEGUI::MouseButton GameManager::convertButton(OIS::MouseButtonID buttonid) switch (buttonid) case OIS::MB_Left: return CEGUI::LeftButton; case OIS::MB_Right: return CEGUI::RightButton; case OIS::MB_Middle: return CEGUI::MiddleButton; default: return CEGUI::LeftButton; bool GameManager::mousePressed(const OIS::MouseEvent &e, OIS::MouseButtonID id ) ceguisystem->injectmousebuttondown(convertbutton(id)); return states.back()->mousepressed(this, e, id); bool GameManager::mouseReleased(const OIS::MouseEvent &e, OIS::MouseButtonID id ) ceguisystem->injectmousebuttonup(convertbutton(id)); return states.back()->mousereleased(this, e, id);
OIS 의마우스움직임을 CEGUI 의연결 bool GameManager::mouseMoved(const OIS::MouseEvent &e) CEGUI::Point mousepos = CEGUI::MouseCursor::getSingleton().getPosition(); mousepos.d_x = e.state.x.abs; mousepos.d_y = e.state.y.abs; CEGUI::MouseCursor::getSingleton().setPosition(mousePos); ceguisystem->injectmousemove(e.state.x.rel, e.state.y.rel); ceguisystem->injectmousewheelchange(e.state.z.rel); return states.back()->mousemoved(this, e);
Key 입력을 CEGUI 와연결 bool GameManager::keyPressed(const OIS::KeyEvent &e) ceguisystem->injectkeydown(e.key); ceguisystem->injectchar(e.text); return states.back()->keypressed(this, e); bool GameManager::keyReleased(const OIS::KeyEvent &e) ceguisystem->injectkeyup(e.key); return states.back()->keyreleased(this, e);
CEGUI 레이아웃로딩및버튼클릭이벤트연결 void TitleState::enter(void) mcontinue = true; mgamestart = false; mtitlelayout = ceguiwindowmanager->loadwindowlayout("lecturetitle.layout"); ceguisystem->setguisheet(mtitlelayout); ceguiwindowmanager->getwindow("startgamebutton")->subscribeevent( CEGUI::PushButton::EventClicked, CEGUI::Event::Subscriber(&TitleState::startGame, this)); void TitleState::exit(void) ceguisystem->setguisheet(null); ceguiwindowmanager->getwindow("startgamebutton")->removeevent(cegui::pushbutton::eventclicked); ceguiwindowmanager->destroywindow(mtitlelayout);
입력과게임로직의분리처리 bool TitleState::startGame(const CEGUI::EventArgs &evt) mgamestart = true; return true; bool TitleState::frameEnded(GameManager* game, const FrameEvent& evt) if (mgamestart) game->changestate(playstate::getinstance()); return mcontinue; bool TitleState::keyPressed(GameManager* game, const OIS::KeyEvent &e) switch(e.key) case OIS::KC_SPACE: mgamestart = true; break; case OIS::KC_ESCAPE: mcontinue = false; break; return true;
초간단실습과제 현재프로그램은종료버튼에대핚처리를하고있지않음. 종료버튼에이벤트를추가하여, 종료버튼을눌렀을경우, 게임이종료되게하시오.
실습 CharacterSelectUI 캐릭터선택 UI 구현
PlayState.cpp 실습 void PlayState::_createCharacterSelectUI(void) mback = false; mcharacterselectlayout = ceguiwindowmanager->loadwindowlayout("characterselect.layout"); ceguisystem->setguisheet(mcharacterselectlayout); ceguiwindowmanager->getwindow("professoricon")->subscribeevent( CEGUI::Window::EventMouseEnters, CEGUI::Event::Subscriber(&PlayState::professorSelected, this)); ceguiwindowmanager->getwindow("ninjaicon")->subscribeevent( CEGUI::Window::EventMouseEnters, CEGUI::Event::Subscriber(&PlayState::ninjaSelected, this)); ceguiwindowmanager->getwindow("backbutton")->subscribeevent( CEGUI::PushButton::EventClicked, CEGUI::Event::Subscriber(&PlayState::backButtonClicked, this)); void PlayState::_destroyCharacterSelectUI(void) ceguisystem->setguisheet(null); ceguiwindowmanager->getwindow("professoricon")->removeevent(cegui::window::eventmouseenters); ceguiwindowmanager->getwindow("ninjaicon")->removeevent(cegui::window::eventmouseenters); ceguiwindowmanager->getwindow("backbutton")->removeevent(cegui::pushbutton::eventclicked); ceguiwindowmanager->destroywindow(mcharacterselectlayout);
실행화면
마우스가위젯위에왔을때의이벤트처리 실습 ceguiwindowmanager->getwindow("professoricon")->subscribeevent( CEGUI::Window::EventMouseEnters, CEGUI::Event::Subscriber(&PlayState::professorSelected, this)); ceguiwindowmanager->getwindow("ninjaicon")->subscribeevent( CEGUI::Window::EventMouseEnters, CEGUI::Event::Subscriber(&PlayState::ninjaSelected, this));
캐릭터교체 mcharacteryaw->attachobject(mprofessorentity); mcharacteryaw->attachobject(mninjaentity); bool PlayState::professorSelected(const CEGUI::EventArgs &evt) mcharacterentity = mprofessorentity; mprofessorentity->setvisible(true); mninjaentity->setvisible(false); manimationstate = mprofessoranimationstate; mcharacteryaw->setorientation(ogre::quaternion::identity); return true; bool PlayState::ninjaSelected(const CEGUI::EventArgs &evt) mcharacterentity = mninjaentity; mprofessorentity->setvisible(false); mninjaentity->setvisible(true); manimationstate = mninjaanimationstate; mcharacteryaw->setorientation(ogre::quaternion(degree(180), Ogre::Vector3::UNIT_Y)); return true;
정리 CEGUI 의구현방식 하드코딩레이아웃파일로딩 입력시스템 ( 키및마우스입력 ) 과 CEGUI 의연결 입력시스템으로부터넘어온값을 CEGUI 로전달 (Inject) 해야함. 위젯이벤트의처리 위젯별로해당되는이벤트에대한함수를만들고, 이를연결시켜야 (Subscribe) 함.