1 #include "engine.h"
2 #include "random.h"
3 #include "gameEntity.h"
4 #include "Updatable.h"
5 #include "collisionable.h"
6
7 #ifdef DEBUG
8 #include <typeinfo>
9 int DEBUG_PobjCount;
10 PObject* DEBUG_PobjListStart;
11 #endif
12
13 #ifdef WIN32
14 #include <windows.h>
15
16 namespace
17 {
18 HINSTANCE exchndl = nullptr;
19 }
20 #endif
21
22 Engine* engine;
23
Engine()24 Engine::Engine()
25 {
26 engine = this;
27
28 #ifdef WIN32
29 // Setup crash reporter (Dr. MinGW) if available.
30 exchndl = LoadLibrary(TEXT("exchndl.dll"));
31
32 if (exchndl)
33 {
34 auto pfnExcHndlInit = GetProcAddress(exchndl, "ExcHndlInit");
35
36 if (pfnExcHndlInit)
37 {
38 pfnExcHndlInit();
39 LOG(INFO) << "Crash Reporter ON";
40 }
41 else
42 {
43 LOG(WARNING) << "Failed to initialize Crash Reporter";
44 FreeLibrary(exchndl);
45 exchndl = nullptr;
46 }
47 }
48 #endif // WIN32
49
50 initRandom();
51 windowManager = nullptr;
52 CollisionManager::initialize();
53 InputHandler::initialize();
54 gameSpeed = 1.0;
55 running = true;
56 elapsedTime = 0.0;
57 soundManager = new SoundManager();
58 }
~Engine()59 Engine::~Engine()
60 {
61 if (windowManager)
62 windowManager->close();
63 delete soundManager;
64 soundManager = nullptr;
65
66 #ifdef WIN32
67 if (exchndl)
68 {
69 FreeLibrary(exchndl);
70 exchndl = nullptr;
71 }
72 #endif // WIN32
73 }
74
registerObject(string name,P<PObject> obj)75 void Engine::registerObject(string name, P<PObject> obj)
76 {
77 objectMap[name] = obj;
78 }
79
getObject(string name)80 P<PObject> Engine::getObject(string name)
81 {
82 if (!objectMap[name])
83 return NULL;
84 return objectMap[name];
85 }
86
runMainLoop()87 void Engine::runMainLoop()
88 {
89 windowManager = dynamic_cast<WindowManager*>(*getObject("windowManager"));
90 if (!windowManager)
91 {
92 sf::Clock frameTimeClock;
93 while(running)
94 {
95 float delta = frameTimeClock.getElapsedTime().asSeconds();
96 frameTimeClock.restart();
97 if (delta > 0.5f)
98 delta = 0.5f;
99 if (delta < 0.001f)
100 delta = 0.001f;
101 delta *= gameSpeed;
102
103 entityList.update();
104 foreach(Updatable, u, updatableList)
105 u->update(delta);
106 elapsedTime += delta;
107 CollisionManager::handleCollisions(delta);
108 ScriptObject::clearDestroyedObjects();
109 soundManager->updateTick();
110
111 sf::sleep(sf::seconds(1.f/60.f - delta));
112 //if (elapsedTime > 2.0)
113 // break;
114 }
115 }else{
116 sf::Clock frameTimeClock;
117 #ifdef DEBUG
118 sf::Clock debugOutputClock;
119 #endif
120 while(running && windowManager->window.isOpen())
121 {
122 InputHandler::preEventsUpdate();
123 // Handle events
124 sf::Event event;
125 while (windowManager->window.pollEvent(event))
126 {
127 handleEvent(event);
128 }
129 InputHandler::postEventsUpdate();
130
131 #ifdef DEBUG
132 if (sf::Keyboard::isKeyPressed(sf::Keyboard::Escape) && windowManager->hasFocus())
133 running = false;
134
135 if (debugOutputClock.getElapsedTime().asSeconds() > 1.0)
136 {
137 printf("Object count: %4d %4zd %4zd\n", DEBUG_PobjCount, updatableList.size(), entityList.size());
138 debugOutputClock.restart();
139 }
140 #endif
141
142 float delta = frameTimeClock.restart().asSeconds();
143 if (delta > 0.5f)
144 delta = 0.5f;
145 if (delta < 0.001f)
146 delta = 0.001f;
147 delta *= gameSpeed;
148 #ifdef DEBUG
149 if (sf::Keyboard::isKeyPressed(sf::Keyboard::Tab))
150 delta /= 5.f;
151 if (sf::Keyboard::isKeyPressed(sf::Keyboard::Tilde))
152 delta *= 5.f;
153 #endif
154 EngineTiming engine_timing;
155
156 sf::Clock engine_timing_clock;
157 entityList.update();
158 foreach(Updatable, u, updatableList)
159 u->update(delta);
160 elapsedTime += delta;
161 engine_timing.update = engine_timing_clock.restart().asSeconds();
162 CollisionManager::handleCollisions(delta);
163 engine_timing.collision = engine_timing_clock.restart().asSeconds();
164 ScriptObject::clearDestroyedObjects();
165 soundManager->updateTick();
166
167 // Clear the window
168 windowManager->render();
169 engine_timing.render = engine_timing_clock.restart().asSeconds();
170 engine_timing.server_update = 0.0f;
171 if (game_server)
172 engine_timing.server_update = game_server->getUpdateTime();
173
174 last_engine_timing = engine_timing;
175 }
176 soundManager->stopMusic();
177 }
178 }
179
handleEvent(sf::Event & event)180 void Engine::handleEvent(sf::Event& event)
181 {
182 // Window closed: exit
183 if (event.type == sf::Event::Closed)
184 running = false;
185 if (event.type == sf::Event::GainedFocus)
186 windowManager->windowHasFocus = true;
187 if (event.type == sf::Event::LostFocus)
188 windowManager->windowHasFocus = false;
189 #ifdef DEBUG
190 if ((event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::L))
191 {
192 int n = 0;
193 printf("------------------------\n");
194 std::unordered_map<string,int> totals;
195 for(PObject* obj = DEBUG_PobjListStart; obj; obj = obj->DEBUG_PobjListNext)
196 {
197 printf("%c%4d: %4d: %s\n", obj->isDestroyed() ? '>' : ' ', n++, obj->getRefCount(), typeid(*obj).name());
198 if (!obj->isDestroyed())
199 {
200 totals[typeid(*obj).name()]=totals[typeid(*obj).name()]+1;
201 }
202 }
203 printf("--non-destroyed totals--\n");
204 int grand_total=0;
205 for (auto entry : totals)
206 {
207 printf("%4d %s\n", entry.second, entry.first.c_str());
208 grand_total+=entry.second;
209 }
210 printf("%4d %s\n",grand_total,"All PObjects");
211 printf("------------------------\n");
212 }
213 #endif
214 InputHandler::handleEvent(event);
215 if (event.type == sf::Event::Resized)
216 windowManager->setupView();
217 #ifdef __ANDROID__
218 //Focus lost and focus gained events are used when the application window is created and destroyed.
219 if (event.type == sf::Event::LostFocus)
220 running = false;
221
222 //The MouseEntered and MouseLeft events are received when the activity needs to pause or resume.
223 if (event.type == sf::Event::MouseLeft)
224 {
225 //Pause is when a small popup is on top of the window. So keep running.
226 while(windowManager->window.isOpen() && windowManager->window.waitEvent(event))
227 {
228 if (event.type != sf::Event::MouseLeft)
229 handleEvent(event);
230 if (event.type == sf::Event::MouseEntered)
231 break;
232 }
233 }
234 #endif//__ANDROID__
235 }
236
setGameSpeed(float speed)237 void Engine::setGameSpeed(float speed)
238 {
239 gameSpeed = speed;
240 }
241
getGameSpeed()242 float Engine::getGameSpeed()
243 {
244 return gameSpeed;
245 }
246
getElapsedTime()247 float Engine::getElapsedTime()
248 {
249 return elapsedTime;
250 }
251
getEngineTiming()252 Engine::EngineTiming Engine::getEngineTiming()
253 {
254 return last_engine_timing;
255 }
256
shutdown()257 void Engine::shutdown()
258 {
259 running = false;
260 }
261