Presentation is loading. Please wait.

Presentation is loading. Please wait.

Game Programming 04 The Game Loop and Real-time Simulation 2010 년 2 학기 디지털콘텐츠전공.

Similar presentations


Presentation on theme: "Game Programming 04 The Game Loop and Real-time Simulation 2010 년 2 학기 디지털콘텐츠전공."— Presentation transcript:

1 Game Programming 04 The Game Loop and Real-time Simulation 2010 년 2 학기 디지털콘텐츠전공

2 Time in Game Games: –Real-time, dynamic, interactive computer simulation –Time plays an important role! –Different types of time in a game Real time Game time local timeline of an animation

3 Rendering Loop Real-time 3D Graphics is different from OS’s GUI –Redraw in Windows PC/Mac OS: Mostly static Small portion of the screen is changing Rectangle invalidation –Redraw in a Game: Entire contents of the screen is changing Like a movie with a series of still images in rapid succession Succession requires a LOOP – the rendering loop

4 Rendering Loop Typical structure for a rendering loop: while(!quit) { // Update camera transform based on // user input, or predefined scenario updateCamera(); // Update positions, orientations and // other visual states of the elements updateSceneElements(); // Render a still frame into the “back buffer” renderScene(); // Swap the back buffer with the front buffer swapBuffers(); } while(!quit) { // Update camera transform based on // user input, or predefined scenario updateCamera(); // Update positions, orientations and // other visual states of the elements updateSceneElements(); // Render a still frame into the “back buffer” renderScene(); // Swap the back buffer with the front buffer swapBuffers(); }

5 Game Loop Game consists of many subsystems: –Device I/O –Rendering –Animation –Collision detection and resolution –Rigid body dynamic simulation (optional) –Multiplayer networking –Audio Need to be update periodically – Game Loop –Update rates can be different Rendering/animation: 30~60 Hz Dynamic simulation: 120 Hz AI: 2 Hz (twice per second)

6 Game Loop – A Simple Example Pong (Atari arcade game) –A Legendary Game: http://www.pong- story.com/arcade.htmhttp://www.pong- story.com/arcade.htm –Simple but exciting! http://www.youtube.com/watch?v=LPkUvfL8T1I

7 Pong Game Loop void main()// pong { initGame(); while(true)// Game Loop { readInterfaceDevices(); if(quitButtonPressed()) break; movePaddles(); moveBall(); collideAndBounceBall(); if(ballImpactedSide(LEFT_PLAYER) { incrementScore(RIGHT_PLAYER); resetBall(); } if(ballImpactedSide(RIGHT_PLAYER) { incrementScore(LEFT_PLAYER); resetBall(); } renderPlayfield(); } void main()// pong { initGame(); while(true)// Game Loop { readInterfaceDevices(); if(quitButtonPressed()) break; movePaddles(); moveBall(); collideAndBounceBall(); if(ballImpactedSide(LEFT_PLAYER) { incrementScore(RIGHT_PLAYER); resetBall(); } if(ballImpactedSide(RIGHT_PLAYER) { incrementScore(LEFT_PLAYER); resetBall(); } renderPlayfield(); }

8 Game loop architectural styles 1.Windows Message Pumps 2.Callback-Driven Frameworks 3.Even-based Updating

9 Windows Message Pumps Message Pump: –A routine for handling windows messages Games in a Windows OS must obey windows’ rule Many messages from the OS cannot be ignored // Message Pump – Typical Windows Routine while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } // Message Pump – Typical Windows Routine while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); }

10 Windows Message Pumps Message Pump for a game: –Modify the windows message pump with the game loop // Message Pump for a game while (true) { // Service all pending windows messages while (PeekMessage(&msg, NULL, 0, 0)>0) { TranslateMessage(&msg); DispatchMessage(&msg); } // If no more windows messages, // run one iteration of the game loop RunOneIterationOfGameLoop(); } // Message Pump for a game while (true) { // Service all pending windows messages while (PeekMessage(&msg, NULL, 0, 0)>0) { TranslateMessage(&msg); DispatchMessage(&msg); } // If no more windows messages, // run one iteration of the game loop RunOneIterationOfGameLoop(); }

11 Call-back Driven Framework Framework: –A partially-constructed application Encapsulating knowledge of how to use the low-level libraries Providing functions for the game flow But functions are mostly empty –Need to be completed by a programmer Fill-in the missing details Overide call-back functions

12 Call-back Driven Framework Example from Ogre3D’s game loop while (true) { for (each frameListener) { frameListener.frameStarted(); } renderCurrentScene(); for (each frameListener) { frameListener.frameEnded(); } while (true) { for (each frameListener) { frameListener.frameStarted(); } renderCurrentScene(); for (each frameListener) { frameListener.frameEnded(); }

13 Call-back Driven Framework Using Ogre’s FrameListener Class GameFrameListener : public Ogre::FrameListener { public: virtual void frameStarted(const FrameEvent &event) { // Do things happening before rendering pollJoypad(event); updatePlayerControls(events); updateDynamicSimulation(events); resolveCollisions(events); updateCamera(events); // etc. } virtual void frameEnded(const FrameEvent &event) { // Do things after rendering drawHud(events); } Class GameFrameListener : public Ogre::FrameListener { public: virtual void frameStarted(const FrameEvent &event) { // Do things happening before rendering pollJoypad(event); updatePlayerControls(events); updateDynamicSimulation(events); resolveCollisions(events); updateCamera(events); // etc. } virtual void frameEnded(const FrameEvent &event) { // Do things after rendering drawHud(events); }

14 Event-Driven Updating Event: –Any interesting change in the state of the game –Examples: The player pressing a keyboard The explosion going off An enemy character spotting the player

15 Event-Driven Updating Event System –Similar to windows GUI –A subsystem of a game engine Register events of interests Respond to the events when they occur –Periodic services can be implemented by an event Example: Posting a event for every 1/30 sec. Using the event que for posting a event for the future

16 MEASURING AND DEALING WITH TIME

17 Timelines Real Time –Actual time measured directly via the CPU clock Game Time –Times measured or used in the game –Does not need to be coincide with the real time Slow/fast motion in the game Temporarily pausing the game When debugging, slow-down helps to figure out.

18 Timelines Local and Global timelines –Each animation clip or audio clip may have a different timeline Origin (t=0) defined to the start of the clip Easy to speed up/down when playback Easy to play backward Playing a clip Speed up Play backward

19 Frame Rate and Time Deltas Frame Rate: f –How rapidly the sequence of still images changes –Hertz (Hz) : number of cycles for second –Frames per Second (FPS) : Used in games and film. Same with Hz 30/60 in North America or Japan (NTSC) 50 in Europe (PAL) –Can be varying time to time! Time Delta: Δt –The amount of time between frames: Also known as Frame time, delta time Inverse of the frame rate: 1/f 30 FPS = 1/30 sec = 33.3 ms

20 From Frame Rate to Speed Speed: v –Meters per second (or pixels per second) Make a spaceship move: –Change in position: Δx = v Δt –With a current position x 1, at next frame: x 2 = x 1 + v Δt –Since the movement depends on Δt, how to determine it?

21 Old-days CPU-dependent Games CPU-Dependent: –Do not use any Δt ! –Instead, specify the speed by the meters per frame –With a good PC, will runs fast –With a bad PC, will runs slow –Provide a “Turbo” button to speed up in old-days

22 Updating based on Elapsed Time –To be CPU-independent: Measuring Δt Read CPU time twice: Once at the beginning and once at the end of the frame Most game do this! –Is it accurate? We are measuring the past Δt as an upcomming Δt “Past performance is not a guarantee of future results” Sudden drop in the frame rate: Frame-rate spike

23 Using a Running Average Averaging the frame-time over a few frames –Reduce the influence of a sudden change in frame rate –Can adapt smoothly with a varying framerate

24 Governing the Frame Rate Frame Rate Governing: –Guarantee every frame’s duration to be 33.3 ms or 16.6 ms –Sleep if ends earlier otherwise “takes our lumps”

25 Measuring Real Time Querying system time: –The number of seconds since midnight, Jan 1, 1970 –Not enough resolution High-Resolution Timer: –Count the number of CPU cycles since the last power on/reset –For example: 3GHz processor increments 3 billion times per second Resolution: 1/3 billion = 3.33 x 10 -10 second =0.333 ns Stored with 64 bit integer: 195 years of duration to record time(); QueryPerformanceCounter();// read the counter (64bit integer) QueryPerformanceFrequency(); // cycles per second QueryPerformanceCounter();// read the counter (64bit integer) QueryPerformanceFrequency(); // cycles per second

26 Time to Back to OGRE3D

27 Basic of OGRE Scene Manager: –Managing everything appearing in the scene –Cameras, Objects, Planes, billboards, lights...and so on 3 kinds of Scene Managers –Octree(8 진 트리 ) Scene Manager 기본 장면 관리자 대부분의 장면에 사용 가능 –BSP(Binary Surface Partition) Scene Manager 건물 내부와 같이 벽과 복도 등으로 구성된 장면에 최적화된 성능. –Terrain Scene Manager 정적 지형을 가지는 비교적 소규모의 장면에 적합 고해상도의 지형에 적합 mSceneMgr = mRoot->createSceneManager(Ogre::ST_GENERIC);

28 Basic of OGRE Entity: –Objects to be rendered on the scene –3D meshes: Character, robot, fish, terrain and so on. –Cameras, lights, billboards are not entities. 3D Mesh

29 Basic of OGRE Scene Node: –Representing translation, rotation and scale (transformation) –Not an actual object –An(or multiple) entity can be attached to. Node Entity1 Entity2

30 Scene Manager, node and entity root Node1 Node2 Entity1 Entity2 Entity3 Node3 Entity4 Entity5 Node4 Entity6

31 Hierarchical Modeling A hierarchical model is created by nesting the descriptions of subparts into one another to form a tree organization

32 Revisiting the code void TutorialApplication::createScene(void) { // create your scene here :) Ogre::Entity* ogreHead = mSceneMgr->createEntity("Head", "ogrehead.mesh"); Ogre::SceneNode* headNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(); headNode->attachObject(ogreHead); // Set ambient light mSceneMgr->setAmbientLight(Ogre::ColourValue(0.5, 0.5, 0.5)); // Create a light Ogre::Light* l = mSceneMgr->createLight("MainLight"); l->setPosition(20,80,50); } void TutorialApplication::createScene(void) { // create your scene here :) Ogre::Entity* ogreHead = mSceneMgr->createEntity("Head", "ogrehead.mesh"); Ogre::SceneNode* headNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(); headNode->attachObject(ogreHead); // Set ambient light mSceneMgr->setAmbientLight(Ogre::ColourValue(0.5, 0.5, 0.5)); // Create a light Ogre::Light* l = mSceneMgr->createLight("MainLight"); l->setPosition(20,80,50); }

33 Adding One More Node void TutorialApplication::createScene(void) { // create your scene here :) Ogre::Entity* ogreHead = mSceneMgr->createEntity("Head", "ogrehead.mesh"); Ogre::SceneNode* headNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(); headNode->attachObject(ogreHead); Ogre::Entity* ogreHead2 = mSceneMgr->createEntity( "Head2", "ogrehead.mesh" ); Ogre::SceneNode* headNode2 = mSceneMgr->getRootSceneNode()->createChildSceneNode ( "HeadNode2", Ogre::Vector3( 100, 0, 0 ) ); headNode2->attachObject( ogreHead2 ); // Set ambient light mSceneMgr->setAmbientLight(Ogre::ColourValue(0.5, 0.5, 0.5)); // Create a light Ogre::Light* l = mSceneMgr->createLight("MainLight"); l->setPosition(20,80,50); } void TutorialApplication::createScene(void) { // create your scene here :) Ogre::Entity* ogreHead = mSceneMgr->createEntity("Head", "ogrehead.mesh"); Ogre::SceneNode* headNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(); headNode->attachObject(ogreHead); Ogre::Entity* ogreHead2 = mSceneMgr->createEntity( "Head2", "ogrehead.mesh" ); Ogre::SceneNode* headNode2 = mSceneMgr->getRootSceneNode()->createChildSceneNode ( "HeadNode2", Ogre::Vector3( 100, 0, 0 ) ); headNode2->attachObject( ogreHead2 ); // Set ambient light mSceneMgr->setAmbientLight(Ogre::ColourValue(0.5, 0.5, 0.5)); // Create a light Ogre::Light* l = mSceneMgr->createLight("MainLight"); l->setPosition(20,80,50); }

34 Node Transformation Translate: –SceneNode::translate ( Ogre::Vector3(..) ); Rotate: –SceneNode::yaw(Degree(..)); –SceneNode::pitch ( ); –SceneNode::roll ( ); Scale –SceneNode::scale ( x, y, z );

35 Cool ninja without hassle Replace the CreateScene function with the one in our homepage!

36 정리 OGRE 3D 의 rendering process: – 시스템 초기화 Root 개체 생성 Configuration 설정 Render Window 생성 Resource 위치 설정 Frame Listener 생성 – 씬 생성 Scene Manager 생성 Camera 및 viewport 생성 Light 생성 Entity 생성 Scene node 생성 – 렌더링

37 Frame Listener 한 장면이 화면에 렌더링되기 직전 / 직후에 해야 할 일을 정의하고 있는 객체 추가 작업을 위해서는 frame listener 를 추가 생성 하고, 이를 root 에 등록시켜 사용 여러 개의 frame listener 가 존재할 수 있다.

38 Frame Listener 의 맴버함수 frameStarted Called just before a frame is rendered. frameRenderingQueued Called after all render targets have had their r endering commands issued, but before the render windows have been asked to flip th eir buffers over frameEnded Called just after a frame has been rendered. virtual bool frameStarted(const FrameEvent& evt); virtual bool frameRenderingQueued(const FrameEvent& evt); virtual bool frameEnded(const FrameEvent& evt) virtual bool frameStarted(const FrameEvent& evt); virtual bool frameRenderingQueued(const FrameEvent& evt); virtual bool frameEnded(const FrameEvent& evt) FrameEvent structure: Real timeSinceLastEvent, Real timeSinceLastFrame 값을 기억하는 구조체

39 Frame Listener 의 호출 Root 객체의 rendering loop 내에서 호출 bool Root::renderOneFrame(void) { if(!_fireFrameStarted()) return false; if (!_updateAllRenderTargets()) return false; return _fireFrameEnded(); } bool Root::renderOneFrame(void) { if(!_fireFrameStarted()) return false; if (!_updateAllRenderTargets()) return false; return _fireFrameEnded(); }

40 Ogre Engine 의 Rendering Loop Root::startRendering() 함수에서 이뤄짐 Redering Loop 실행 – 매 프레임 마다 renderOneFrame 실행 : Loop 의 중단 –FrameStarted, frameRenderingQueued, FrameEnded 에서 하나라도 false 를 return 할 경우 1. Frame Listener 들의 FrameStarted() 함수 호출 3. Frame Listener 들의 FrameEnded() 함수 호출 Frame Listener 들의 frameRenderingQueued() 함수 호출 2. 한 프레임 렌더링

41 Input Handling Types of input handling –Unbuffered Input Testing states of Mouse/Keyboard every frame Do action if necessary –Buffered Input Event(message)-driven Event is queued into a buffer Call message pump routines per frame

42 Ninja 움직이기 Add two functions in Application class: class OgreApp : public BaseApplication { public: BasicTutorial4(void); virtual ~BasicTutorial4(void); protected: virtual void createScene(void); virtual bool frameRenderingQueued(const Ogre::FrameEvent& evt); private: bool processUnbufferedInput(const Ogre::FrameEvent& evt); } class OgreApp : public BaseApplication { public: BasicTutorial4(void); virtual ~BasicTutorial4(void); protected: virtual void createScene(void); virtual bool frameRenderingQueued(const Ogre::FrameEvent& evt); private: bool processUnbufferedInput(const Ogre::FrameEvent& evt); }

43 Ninja 움직이기 Add two functions in Application class: class OgreApp : public BaseApplication { public: BasicTutorial4(void); virtual ~BasicTutorial4(void); protected: virtual void createScene(void); virtual bool frameRenderingQueued(const Ogre::FrameEvent& evt); private: bool processUnbufferedInput(const Ogre::FrameEvent& evt); } class OgreApp : public BaseApplication { public: BasicTutorial4(void); virtual ~BasicTutorial4(void); protected: virtual void createScene(void); virtual bool frameRenderingQueued(const Ogre::FrameEvent& evt); private: bool processUnbufferedInput(const Ogre::FrameEvent& evt); }

44 CreateScene 수정 Ninja 를 포함하고 light 를 세팅 mSceneMgr->setAmbientLight(Ogre::ColourValue(0.25, 0.25, 0.25)); Ogre::Entity* ninjaEntity = mSceneMgr->createEntity("Ninja", "ninja.mesh"); Ogre::SceneNode *node = mSceneMgr->getRootSceneNode() ->createChildSceneNode("NinjaNode"); node->attachObject(ninjaEntity); Ogre::Light* pointLight = mSceneMgr->createLight("pointLight"); pointLight->setType(Ogre::Light::LT_POINT); pointLight->setPosition(Ogre::Vector3(250, 150, 250)); pointLight->setDiffuseColour(Ogre::ColourValue::White); pointLight->setSpecularColour(Ogre::ColourValue::White); mSceneMgr->setAmbientLight(Ogre::ColourValue(0.25, 0.25, 0.25)); Ogre::Entity* ninjaEntity = mSceneMgr->createEntity("Ninja", "ninja.mesh"); Ogre::SceneNode *node = mSceneMgr->getRootSceneNode() ->createChildSceneNode("NinjaNode"); node->attachObject(ninjaEntity); Ogre::Light* pointLight = mSceneMgr->createLight("pointLight"); pointLight->setType(Ogre::Light::LT_POINT); pointLight->setPosition(Ogre::Vector3(250, 150, 250)); pointLight->setDiffuseColour(Ogre::ColourValue::White); pointLight->setSpecularColour(Ogre::ColourValue::White);

45 Frame Listner 수정 frameRenderingQueued 함수 override bool OgreApp::frameRenderingQueued(const Ogre::FrameEvent& evt) { bool ret = BaseApplication::frameRenderingQueued(evt); if(!processUnbufferedInput(evt)) return false; return ret; } bool OgreApp::frameRenderingQueued(const Ogre::FrameEvent& evt) { bool ret = BaseApplication::frameRenderingQueued(evt); if(!processUnbufferedInput(evt)) return false; return ret; }

46 Processing Input bool OgreApp::processUnbufferedInput(const Ogre::FrameEvent& evt) { static bool mMouseDown = false; // If a mouse button is depressed static Ogre::Real mToggle = 0.0; // The time left until next toggle static Ogre::Real mRotate = 0.13; // The rotate constant static Ogre::Real mMove = 250; // The movement constant bool OgreApp::processUnbufferedInput(const Ogre::FrameEvent& evt) { static bool mMouseDown = false; // If a mouse button is depressed static Ogre::Real mToggle = 0.0; // The time left until next toggle static Ogre::Real mRotate = 0.13; // The rotate constant static Ogre::Real mMove = 250; // The movement constant

47 Processing Input UnbufferedInput 구현 –Mouse 와 keyboard 의 현재 상태를 얻어옴 (BaseApplication::frameRenderingQueued 에서 수행 ) 다음과 같이 사용할 준비를 한다. bool OgreApp::processUnbufferedInput(const Ogre::FrameEvent& evt) { static bool mMouseDown = false; // If a mouse button is depressed static Ogre::Real mToggle = 0.0; // The time left until next toggle static Ogre::Real mRotate = 0.13; // The rotate constant static Ogre::Real mMove = 250; // The movement constant bool OgreApp::processUnbufferedInput(const Ogre::FrameEvent& evt) { static bool mMouseDown = false; // If a mouse button is depressed static Ogre::Real mToggle = 0.0; // The time left until next toggle static Ogre::Real mRotate = 0.13; // The rotate constant static Ogre::Real mMove = 250; // The movement constant mMouse->capture(); mKeyboard->capture(); mMouse->capture(); mKeyboard->capture();

48 Toggle 기능 구현 현재 mouse 와 마지막 mouse 상태의 비교를 통 해 구현 bool currMouse = mMouse->getMouseState().buttonDown(OIS::MB_Left); if (currMouse && ! mMouseDown) { Ogre::Light* light = mSceneMgr->getLight("pointLight"); light->setVisible(! light->isVisible()); } mMouseDown = currMouse; bool currMouse = mMouse->getMouseState().buttonDown(OIS::MB_Left); if (currMouse && ! mMouseDown) { Ogre::Light* light = mSceneMgr->getLight("pointLight"); light->setVisible(! light->isVisible()); } mMouseDown = currMouse;

49 Delayed Toggle 구현 눌린 시간을 기억하여 어느 일정시간이상 눌렸으 면 실행 mToggle -= evt.timeSinceLastFrame; if ((mToggle isKeyDown(OIS::KC_1)) { mToggle = 0.5; Ogre::Light* light = mSceneMgr->getLight("pointLight"); light->setVisible(! light->isVisible()); } mToggle -= evt.timeSinceLastFrame; if ((mToggle isKeyDown(OIS::KC_1)) { mToggle = 0.5; Ogre::Light* light = mSceneMgr->getLight("pointLight"); light->setVisible(! light->isVisible()); }

50 Keyboard 입력 구현 키보드의 상태를 찾아내어 구현 Ogre::Vector3 transVector = Ogre::Vector3::ZERO; if (mKeyboard->isKeyDown(OIS::KC_I)) // Forward transVector.z -= mMove; if (mKeyboard->isKeyDown(OIS::KC_K)) // Backward transVector.z += mMove; if (mKeyboard->isKeyDown(OIS::KC_U)) // Up transVector.y += mMove; if (mKeyboard->isKeyDown(OIS::KC_O)) // Down transVector.y -= mMove; mSceneMgr->getSceneNode("NinjaNode") ->translate(transVector * evt.timeSinceLastFrame, Ogre::Node::TS_LOCAL); Ogre::Vector3 transVector = Ogre::Vector3::ZERO; if (mKeyboard->isKeyDown(OIS::KC_I)) // Forward transVector.z -= mMove; if (mKeyboard->isKeyDown(OIS::KC_K)) // Backward transVector.z += mMove; if (mKeyboard->isKeyDown(OIS::KC_U)) // Up transVector.y += mMove; if (mKeyboard->isKeyDown(OIS::KC_O)) // Down transVector.y -= mMove; mSceneMgr->getSceneNode("NinjaNode") ->translate(transVector * evt.timeSinceLastFrame, Ogre::Node::TS_LOCAL);

51 Rotate 구현 SHIFT 키와 조합하여 구현 if (mKeyboard->isKeyDown(OIS::KC_J)) // Left - yaw or strafe { if(mKeyboard->isKeyDown( OIS::KC_LSHIFT )) { // Yaw left mSceneMgr->getSceneNode("NinjaNode")->yaw(Ogre::Degree(mRotate * 5)); } else { transVector.x -= mMove; // Strafe left } if (mKeyboard->isKeyDown(OIS::KC_L)) // Right - yaw or strafe { if(mKeyboard->isKeyDown( OIS::KC_LSHIFT )) { // Yaw right mSceneMgr->getSceneNode("NinjaNode")->yaw(Ogre::Degree(-mRotate * 5)); } else { transVector.x += mMove; // Strafe right } if (mKeyboard->isKeyDown(OIS::KC_J)) // Left - yaw or strafe { if(mKeyboard->isKeyDown( OIS::KC_LSHIFT )) { // Yaw left mSceneMgr->getSceneNode("NinjaNode")->yaw(Ogre::Degree(mRotate * 5)); } else { transVector.x -= mMove; // Strafe left } if (mKeyboard->isKeyDown(OIS::KC_L)) // Right - yaw or strafe { if(mKeyboard->isKeyDown( OIS::KC_LSHIFT )) { // Yaw right mSceneMgr->getSceneNode("NinjaNode")->yaw(Ogre::Degree(-mRotate * 5)); } else { transVector.x += mMove; // Strafe right }


Download ppt "Game Programming 04 The Game Loop and Real-time Simulation 2010 년 2 학기 디지털콘텐츠전공."

Similar presentations


Ads by Google