1 /** 2 * Defines the DGame class, the base class for all game logic. 3 */ 4 module dash.core.dgame; 5 import dash; 6 import core.memory; 7 8 /** 9 * The states the game can be in. 10 */ 11 enum EngineState 12 { 13 /// The main game state. 14 Run, 15 /// In edit mode 16 Editor, 17 /// Refresh changed assets, but don't reset state. 18 Refresh, 19 /// Reload all assets at the beginning of the next cycle. 20 Reset, 21 /// Quit the game and the end of this cycle. 22 Quit 23 } 24 25 /** 26 * Contains flags for all things that could be disabled. 27 */ 28 struct GameStateFlags 29 { 30 bool updateScene; 31 bool updateUI; 32 bool updateTasks; 33 bool autoRefresh; 34 //bool updatePhysics; 35 36 /** 37 * Set each member to false. 38 */ 39 void pauseAll() 40 { 41 foreach( member; __traits(allMembers, GameStateFlags) ) 42 static if( __traits(compiles, __traits(getMember, GameStateFlags, member) = false) ) 43 __traits(getMember, GameStateFlags, member) = false; 44 } 45 46 /** 47 * Set each member to true. 48 */ 49 void resumeAll() 50 { 51 foreach( member; __traits(allMembers, GameStateFlags) ) 52 static if( __traits(compiles, __traits(getMember, GameStateFlags, member) = true) ) 53 __traits(getMember, GameStateFlags, member) = true; 54 } 55 } 56 57 /** 58 * The main game loop manager. Meant to be overridden. 59 */ 60 class DGame 61 { 62 public: 63 /// The instance to be running from 64 static DGame instance; 65 66 /// The editor controller, resolved by reflection.d 67 Editor editor; 68 69 /// Current state of the game 70 EngineState currentState; 71 72 /// The current update settings 73 GameStateFlags* stateFlags; 74 75 /// The currently active scene 76 Scene activeScene; 77 78 /** 79 * Overrideable. Returns the name of the window. 80 */ 81 @property string title() 82 { 83 return "Dash"; 84 } 85 86 /** 87 * Main Game loop. 88 */ 89 final void run() 90 { 91 start(); 92 93 GC.collect(); 94 95 // Loop until there is a quit message from the window or the user. 96 while( currentState != EngineState.Quit ) 97 { 98 if( currentState == EngineState.Reset ) 99 { 100 stop(); 101 start(); 102 GC.collect(); 103 } 104 else if( currentState == EngineState.Refresh ) 105 { 106 refresh(); 107 } 108 109 ////////////////////////////////////////////////////////////////////////// 110 // Update 111 ////////////////////////////////////////////////////////////////////////// 112 113 // Platform specific program stuff 114 Graphics.messageLoop(); 115 116 // Update time 117 Time.update(); 118 119 // Update input 120 Input.update(); 121 122 // Update webcore 123 if ( stateFlags.updateUI ) 124 { 125 UserInterface.updateAwesomium(); 126 } 127 128 // Update physics 129 //if( stateFlags.updatePhysics ) 130 // PhysicsController.stepPhysics( Time.deltaTime ); 131 132 if ( stateFlags.updateTasks ) 133 { 134 executeTasks(); 135 } 136 137 if ( stateFlags.updateScene ) 138 { 139 activeScene.update(); 140 } 141 142 // Do the updating of the child class. 143 onUpdate(); 144 145 // Update the editor. 146 //if( currentState == EngineState.Editor ) 147 editor.update(); 148 149 ////////////////////////////////////////////////////////////////////////// 150 // Draw 151 ////////////////////////////////////////////////////////////////////////// 152 153 activeScene.draw(); 154 155 // Draw in child class 156 onDraw(); 157 158 // End drawing 159 Graphics.endDraw(); 160 161 //break; 162 } 163 164 stop(); 165 } 166 167 protected: 168 /** 169 * To be overridden, logic for when the game is being initalized. 170 */ 171 void onInitialize() { } 172 /** 173 * To be overridden, called once per frame during the update cycle. 174 */ 175 void onUpdate() { } 176 /** 177 * To be overridden, called once per frame during the draw cycle. 178 */ 179 void onDraw() { } 180 /** 181 * To be overridden, called when the came is closing. 182 */ 183 void onShutdown() { } 184 /** 185 * To be overridden, called when refreshing content. 186 */ 187 void onRefresh() { } 188 /** 189 * To be overridden, called when resetting and the state must be saved. 190 */ 191 void onSaveState() { } 192 193 private: 194 /** 195 * Function called to initialize controllers. 196 */ 197 final void start() 198 { 199 currentState = EngineState.Run; 200 201 stateFlags = new GameStateFlags; 202 stateFlags.resumeAll(); 203 204 // This is so that the bench marks will log properly, 205 // and config options will be update upon second call. 206 DashLogger.setDefaults(); 207 208 bench!( { Config.initialize(); } )( "Config init" ); 209 bench!( { DashLogger.initialize(); } )( "Logger init" ); 210 bench!( { Input.initialize(); } )( "Input init" ); 211 bench!( { Graphics.initialize(); } )( "Graphics init" ); 212 bench!( { Assets.initialize(); } )( "Assets init" ); 213 bench!( { Audio.initialize(); } )( "Audio init" ); 214 bench!( { Prefabs.initialize(); } )( "Prefabs init" ); 215 bench!( { UserInterface.initializeAwesomium(); } )( "UI init" ); 216 bench!( { editor.initialize( this ); } )( "Editor init" ); 217 bench!( { DGame.instance.onInitialize(); } )( "Game init" ); 218 219 debug scheduleIntervaledTask( 1.seconds, { if( stateFlags.autoRefresh ) currentState = EngineState.Refresh; return false; } ); 220 } 221 222 /** 223 * Function called to shutdown controllers. 224 */ 225 final void stop() 226 { 227 onShutdown(); 228 editor.shutdown(); 229 resetTasks(); 230 UserInterface.shutdownAwesomium(); 231 Assets.shutdown(); 232 Graphics.shutdown(); 233 Audio.shutdown(); 234 } 235 236 /** 237 * Reloads content and yaml. 238 */ 239 final void refresh() 240 { 241 // Refresh 242 Config.refresh(); 243 Assets.refresh(); 244 Graphics.refresh(); 245 Prefabs.refresh(); 246 activeScene.refresh(); 247 // Need to refresh key events. 248 //Input.initialize(); 249 250 // Restart 251 currentState = EngineState.Run; 252 253 // Refresh game. 254 onRefresh(); 255 } 256 257 /** 258 * Called when engine is resetting. 259 */ 260 final void saveState() 261 { 262 onSaveState(); 263 } 264 }