The Game Engine  1
Game.cpp
Go to the documentation of this file.
1 #include "Game.h"
2 #include "fns.h"
3 #include <string>
4 #include <iostream>
5 #include <SDL/SDL_opengl.h>
6 #include <SDL/SDL_ttf.h>
7 #include <time.h>
8 #include "Text.h"
9 #include "Collision.h"
10 #include "Input.h"
11 #include "Color.h"
12 
13 using namespace std;
14 
15 Game* Game::m_instance = NULL;
16 
18  if(!m_instance)
19  m_instance = new Game;
20  return m_instance;
21 }
22 
24  Running(false),
25  poll(false),
26  mScreen(NULL),
27  ShowCollisions(false),
28  ShowFPS(false),
29  Paused(false),
30  Focused(true),
31  alwaysDraw(false),
32  mCamera(),
33  CurrentLevel(NULL),
34  CurrentSprite(NULL),
35  CurrentParticleSystem(NULL),
36  CurrentParticle(NULL),
37  CurrentText(NULL),
38  nextSecondTick(0),
39  nextDrawTick(0),
40  numFrames(0),
41  currentFPS(0),
42  avgFPS(0),
43  drawLoops(0),
44  Language(English),
45  mLevels(map<string, Level*>()),
46  txtFPS(NULL)
47 {
48  int screenwidth = 640;
49  int screenheight = 480;
50 
52  if (SDL_Init(SDL_INIT_VIDEO) < 0) {
53  cout<<"Couldn't initialize SDL: "<<SDL_GetError()<<endl;
54  exit (1);
55  }
56 
57  if(SDL_InitSubSystem(SDL_INIT_EVENTTHREAD)<0)
58  cout<<"Couldn't initialize SDL: "<<SDL_GetError()<<endl;
59  else
60  poll = true;
61 
62  atexit (SDL_Quit);
63  // Initialize SDL_ttf library
64  if (TTF_Init() != 0)
65  {
66  cout << "TTF_Init() Failed: " << TTF_GetError() << endl;
67  SDL_Quit();
68  exit(1);
69  }
70  atexit (TTF_Quit);
71 
72  /* Turn on double buffering with a 24bit Z buffer.
73  * You may need to change this to 16 or 32 for your system */
74  SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
75  SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
76 
78  SDL_WM_SetCaption("Ivan's Game", NULL);
79 
80  SDL_ShowCursor(0);
81 
82  resize(screenwidth, screenheight);
83 
85  srand(time(0)+SDL_GetTicks());
86 
89 
91  Input* keyboard = new Input();
92 
95  //tie each joystick to an input.
96  for(int i=0,end=Input::getNumJoysticks(); i < end; ++i )
97  {
98  Input* joy = new Input(true);
99  }
100  }
101 
103  LoadResources();
104 
105  /* Initialize FPS */
106  for (int index = 0; index < FPSRANGE; index++)
107  {
108  FPSs[index] = 0;
109  }
110 }
111 
113 {
114  foritr(i,mLevels){
115  delete i->second;
116  }
117  delete txtFPS;
118 }
119 
121 {
122  return CurrentLevel;
123 }
124 
126 {
127  return CurrentLevel->getName();
128 }
129 
130 void Game::setCurrentLevel(string name) {
131  if(!CurrentLevel||CurrentLevel->getName()!=name) {
132  Level* l = loadLevel(name);
133  if(l)
134  CurrentLevel = l;
135  }
136  else
137  cout<<"Level "<<name<<" does not exist."<<endl;
138 }
139 
140 Level* Game::loadLevel(string name) {
141  auto level = mLevels.find(name);
142  if(level != mLevels.end()){
143  LoadingLevel = level->second;
144  level->second->load();
145  LoadingLevel = NULL;
146  return level->second;
147  }
148  cout<<"Level "<<name<<" does not exist."<<endl;
149  return NULL;
150 }
151 
153 {
154  return mLevels.size();
155 }
156 
157 void Game::run()
158 {
159  Running = true;
160 
161  if(!CurrentLevel)
162  setCurrentLevel("World");
163 
164  nextGameTick = SDL_GetTicks();
165  int loops=0;
166 
168  while (Running) {
170  SDL_Event event;
171 
172  loops=0;
173 
174  while( SDL_GetTicks() > nextGameTick && loops < MAX_FRAMESKIP){
175  //here because we don't really need to care about input outside of when we're going to update... and it's fast enough
176  if(poll)
177  {
178  while(SDL_PollEvent(&event))
179  handleInput(event);
180  }
181  else
182  {
184  if (0 == SDL_WaitEvent(&event)) {
185  std::cout<<"waiting"<<std::endl;
186  }
187  handleInput(event);
188  }
189 
190  getCurrentLevel()->update();
192  loops++;
193  }
194 
195  if(Game::game()->ShowFPS){
196  if(!txtFPS)
197  txtFPS = new Text("fps", "", 24, Color::WHITE, 600, 50, Point2D());
198  txtFPS->lines[0]=ToString<Uint32>(game()->getFPS());
199  }
200 
201  //make sure the camera is where it needs to be
202  mCamera.updatePos();
203 
204  draw();
205  }
207  getCurrentLevel()->unload();
208  stopDrawTimer();
209 
210 }
211 
212 void Game::stop(){
213  Running=false;
214 }
215 
216 Font* Game::getFont( FontType t = Game::game()->Language, int s = 24){
217  pair<FontType,int> key = pair<FontType,int>(t,s);
218  map<pair<FontType, int>, Font*>::iterator it = mFonts.find(key);
219  //if the font doesn't exist
220  if (it == mFonts.end()) {
221  //create it
222  Font* f = new Font(t, s);
223  mFonts[key] = f;
224  return f;
225  } else {
226  Font* f = it->second;
227  f->count++;
228  return f;
229  }
230 }
231 
232 void Game::removeFont( FontType t = English, int s = 24){
233  pair<FontType,int> key = pair<FontType,int>(t,s);
234  map<pair<FontType, int>, Font*>::iterator it = mFonts.find(key);
235  //if the font doesn't exist
236  if (it != mFonts.end()) {
237  Font* f = it->second;
238  f->count--;
239  if(f->count==0)
240  mFonts.erase(it);
241  }
242 }
243 
244 void Game::removeFont(Font* font){
245  removeFont(font->type, font->size);
246 }
247 
248 Texture* Game::getTexture(string filename, Texture* tex){
249  auto it = mTextures.find(filename);
250  if(it != mTextures.end()){
251  Texture* val = it->second;
252  val->count++;
253  return val;
254  }
255  else{
256  if(tex){
257  glGenTextures(1, &tex->image);
258  tex->count++;
259  mTextures[filename] = tex;
260  return tex;
261  }
262  else
263  {
264  Texture* t = new Texture();
265  glGenTextures(1, &t->image);
266  t->count++;
267  mTextures[filename] = t;
268  return t;
269  }
270  }
271 }
272 
273 void Game::removeTexture(string filename){
274  auto it = mTextures.find(filename);
275  if(it != mTextures.end()){
276  Texture* val = it->second;
277  if(val->count--==1)
278  {
279  glDeleteTextures(1, &val->image);
280  delete it->second;
281  mTextures.erase(it);
282  }
283  }
284 }
285 
287  //auto it = mTextures.find(Texture,);
288 }
289 
291  mAnims.push_back(anim);
292 }
293 
295  for(int i=0, count=mAnims.size(); i < count; i++) {
296  if(mAnims[i]->Name==name) {
297  return mAnims[i];
298  }
299  }
300  //try loading if it's not there
301  try{
302  Animation* a = new Animation(name);
303  addAnimation(a);
304  return a;
305  }
306  catch(exception e){
307  cout<<"Could not load "<<name<<" because:"<<e.what()<<endl;
308  }
309  return NULL;
310 }
311 
313  foritr(ptr, mAnims) {
314  if(anim == *ptr) {
315  (*ptr)->clear();
316  mAnims.erase(ptr);
317  return;
318  }
319  }
320 }
321 
322 void Game::addActor(string name, Actor actor) {
323  mActors.insert(make_pair(name, actor));
324 }
325 
326 void Game::removeActor(string name) {
327  mActors.erase(name);
328 }
329 
331  if(l)
332  l->addObject(sp);
333  else if(CurrentLevel)
334  CurrentLevel->addObject(sp);
335  else
336  LoadingLevel->addObject(sp);
337 }
338 
340  if(l)
341  l->removeObject(sp);
342  else if(CurrentLevel)
344  else
346 }
347 
348 void Game::removeAllSprites(string name, Level* l){
349  if(l)
350  l->removeAllSprites(name);
351  else if(CurrentLevel)
353  else
355 }
356 
357 void Game::removeAllParticleSystems(string name, Level* l){
358  if(l)
359  l->removeAllParticleSystems(name);
360  else if(CurrentLevel)
362  else
364 }
365 
367  string name = l->getName();
368  auto level = mLevels.find(name);
369  if(level == mLevels.end() || mLevels.size() == 0){
370  mLevels[name] = l;
371  }
372  else {
373  cout<<"Level "<<name<<" already exists!"<<endl;
374  }
375 }
376 
377 void Game::handleInput(SDL_Event event)
378 {
379  switch (event.type) {
384  case SDL_QUIT:
385  Running = !Running;
386  break;
390  case SDL_ACTIVEEVENT:
391  switch(event.active.state)
392  {
393  case SDL_APPMOUSEFOCUS:
394  //follow mouse if on window
395  FollowMouse = event.active.gain==1;
396  break;
397 
398  case SDL_APPINPUTFOCUS:
399  if(event.active.gain==1)
400  {
401  cout<<"Appinputfocus gained"<<endl;
402  Paused = false;
403  Focused = true;
404  Uint32 delta = SDL_GetTicks() - unfocusTime;
405  nextSecondTick+=delta;
406  nextDrawTick+=delta;
407  nextGameTick+=delta;
408  }
409  else
410  {
411  cout<<"inputfocus lost"<<endl;
412  Focused = false;
413  Paused=true;
414  unfocusTime = SDL_GetTicks();
415  }
416  break;
417 
418  case SDL_APPACTIVE:
419  if(event.active.gain==1)
420  {
421  cout<<"active gained"<<endl;
422  Paused = false;
423  Focused = true;
424  Uint32 delta = SDL_GetTicks() - unfocusTime;
425  nextSecondTick+=delta;
426  nextDrawTick+=delta;
427  nextGameTick+=delta;
428  }
429  else
430  {
431  cout<<"active lost"<<endl;
432  Focused = false;
433  Paused=true;
434  unfocusTime = SDL_GetTicks();
435  }
436  break;
437  case SDL_APPINPUTFOCUS | SDL_APPACTIVE:
438  if(event.active.gain==1)
439  {
440  Paused = false;
441  Focused = true;
442  cout<<"Focus and input gained"<<endl;
443  Uint32 delta = SDL_GetTicks() - unfocusTime;
444  nextSecondTick+=delta;
445  nextDrawTick+=delta;
446  nextGameTick+=delta;
447  }
448  break;
449  default:
450  cout<<"got something unexpected:"<<(int)event.active.state<<endl;
451  break;
452  }
453  break;
454 
455  case SDL_VIDEORESIZE :
456  resize( event.resize.w, event.resize.h ) ;
457  break ;
458 
459  case SDL_USEREVENT:
460  //draw();
461  break;
462 
466  case SDL_KEYDOWN:
467  {
468  Input::updateInputs(event);
469  break;
470  }
471  case SDL_KEYUP:
472  {
473  std::cout<<"pressed:"<<event.key.keysym.sym<<std::endl;
474  switch(event.key.keysym.sym)
475  {
476  case SDLK_ESCAPE:
477  {
478  Running=!Running;
479  break;
480  }
481  case SDLK_F11:
482  {
484  break;
485  }
486  case SDLK_F10:
487  {
488  ShowFPS = !ShowFPS;
489  break;
490  }
491  case SDLK_MINUS:
492  {
493  mCamera.zoomOut(.1);
494  break;
495  }
496  case SDLK_EQUALS:
497  {
498  mCamera.zoomIn(.1);
499  break;
500  }
501  case SDLK_0:
502  {
503  mCamera.zoom(1);
504  break;
505  }
506  }
507  Input::updateInputs(event);
508  break;
509  }
510  default:
511  // fallthrough if the key wasn't escape or control
512  Input::updateInputs(event);
513  break;
514  }
515 }
516 
517 void Game::draw(){
518  if( Focused && (alwaysDraw || (SDL_GetTicks() > nextDrawTick && drawLoops < MAX_FRAMESKIP))){
519 
523  if(txtFPS && ShowFPS)
524  txtFPS->draw();
525 
526  //get our fps data
529  SDL_GL_SwapBuffers();
530  }
531 }
532 
534  if(SDL_InitSubSystem(SDL_INIT_TIMER)<0)
535  cout<<"Couldn't initialize SDL: "<<SDL_GetError()<<endl;
536  timer = SDL_AddTimer(drawInterval, pushUserEvent, NULL);
537  if (!timer) {
538  std::cout << "Timer creation failed" << std::endl;
539  exit(3);
540  }
541 }
542 
544 {
545  SDL_RemoveTimer(timer);
546  SDL_QuitSubSystem(SDL_INIT_TIMER);
547 }
548 
549 void Game::resize(int w = 640, int h = 480){
550  mScreen = SDL_SetVideoMode(w, h, 32, SDL_OPENGL | SDL_RESIZABLE);
551  if (!mScreen) {
552  cout<<"Couldn't set video mode: "<<SDL_GetError()<<endl;
553  exit (2);
554  }
555 
556  // Set the OpenGL state after creating the context with SDL_SetVideoMode
557  glClearColor (0.0, 0.0, 0.0, 0.0);
558 
559  // Need this to display a texture
560  glEnable( GL_TEXTURE_2D );
561 
562  glViewport( 0, 0, w, h );
563 
564  glMatrixMode( GL_PROJECTION );
565  glLoadIdentity();
566 
567  glOrtho( 0, w, h, 0, -1, 1 );
568 
569  glMatrixMode( GL_MODELVIEW );
570  glEnable(GL_BLEND);
571  glDepthFunc(GL_LEQUAL);
572  glLoadIdentity();
573 }
574 
575 Uint32 Game::pushUserEvent(Uint32 interval, void* data)
576 {
577  SDL_Event event;
578  SDL_UserEvent uevent = {
579  SDL_USEREVENT, /* type */
580  0, /* code */
581  0, /* data1 */
582  0 }; /* data2 */
583  event.user = uevent;
584 
585  SDL_PushEvent(&event);
586 
587  return interval;
588 }
589 
591  Uint32 startclock = SDL_GetTicks();
592 
593  numFrames++;
594 
595  if (startclock > nextSecondTick)
596  {
597  nextSecondTick = startclock + 1000;
598 
600  numFrames = 0;
601 
602  if (currentFPS < FPSRANGE-1)
603  currentFPS++;
604  else
605  currentFPS = 0;
606 
607  Uint32 frameTotal = 0;
608  for (int index = 0; index < FPSRANGE; index++)
609  {
610  frameTotal += FPSs[index];
611  }
612 
613  avgFPS = frameTotal / FPSRANGE;
614  }
615 }