1 /** 2 * This module defines the Scene class, TODO 3 * 4 */ 5 module dash.core.scene; 6 import dash.core, dash.components, dash.graphics, dash.utility; 7 8 import std.path; 9 10 enum SceneName = "[scene]"; 11 12 /** 13 * The Scene contains a list of all objects that should be drawn at a given time. 14 */ 15 final class Scene 16 { 17 private: 18 GameObject _root; 19 20 package: 21 GameObject[uint] objectById; 22 uint[string] idByName; 23 24 public: 25 /// The camera to render with. 26 Camera camera; 27 Listener listener; 28 UserInterface ui; 29 30 /// The root object of the scene. 31 mixin( Getter!_root ); 32 33 this() 34 { 35 _root = new GameObject; 36 _root.name = SceneName; 37 _root.scene = this; 38 } 39 40 /** 41 * Load all objects inside the specified folder in FilePath.Objects. 42 * 43 * Params: 44 * objectPath = The folder location inside of /Objects to look for objects in. 45 */ 46 final void loadObjects( string objectPath = "" ) 47 { 48 foreach( file; buildNormalizedPath( Resources.Objects, objectPath ).scanDirectory() ) 49 { 50 // Create the objects 51 foreach( desc; file.deserializeMultiFile!( GameObject.Description )() ) 52 { 53 auto newObj = GameObject.create( desc ); 54 _root.addChild( newObj ); 55 objectsByResource[ file ] ~= GameObjectResource( file, newObj ); 56 } 57 } 58 } 59 60 /** 61 * Remove all objects from the collection. 62 */ 63 final void clear() 64 { 65 _root.shutdown(); 66 destroy( _root ); 67 _root = new GameObject; 68 69 if( ui ) 70 { 71 ui.shutdown(); 72 destroy( ui ); 73 // TODO: Can be built automatically by config 74 ui = null; 75 } 76 } 77 78 /** 79 * Updates all objects in the scene. 80 */ 81 final void update() 82 { 83 if( ui ) 84 ui.update(); 85 _root.update(); 86 } 87 88 /** 89 * Draws all objects in the scene. 90 */ 91 final void draw() 92 { 93 _root.draw(); 94 } 95 96 /** 97 * Refreshes all objects in the scene that need refreshing. 98 */ 99 final void refresh() 100 { 101 // Iterate over each file, and it's objects 102 foreach_reverse( file; objectsByResource.keys ) 103 { 104 auto objReses = objectsByResource[ file ]; 105 106 if( file.exists() ) 107 { 108 if( file.needsRefresh() ) 109 { 110 auto descs = deserializeMultiFile!( GameObject.Description )( file ); 111 assert( descs.length == objReses.length, "Adding or removing objects from a file is currently unsupported." ); 112 113 foreach( i, objRes; objReses ) 114 { 115 objRes.object.refresh( descs[ i ] ); 116 } 117 } 118 } 119 else 120 { 121 foreach( objRes; objReses ) 122 { 123 objRes.object.shutdown(); 124 removeChild( objRes.object ); 125 } 126 127 objectsByResource.remove( file ); 128 } 129 } 130 } 131 132 /** 133 * Gets the object in the scene with the given name. 134 * 135 * Params: 136 * name = The name of the object to look for. 137 * 138 * Returns: The object with the given name. 139 */ 140 final GameObject opIndex( string name ) 141 { 142 if( auto id = name in idByName ) 143 return this[ *id ]; 144 else 145 return null; 146 } 147 148 /** 149 * Gets the object in the scene with the given id. 150 * 151 * Params: 152 * index = The id of the object to look for. 153 * 154 * Returns: The object with the given id. 155 */ 156 final GameObject opIndex( uint index ) 157 { 158 if( auto obj = index in objectById ) 159 return *obj; 160 else 161 return null; 162 } 163 164 /** 165 * Adds object to the children, adds it to the scene graph. 166 * 167 * Params: 168 * newChild = The object to add. 169 */ 170 final void addChild( GameObject newChild ) 171 { 172 _root.addChild( newChild ); 173 } 174 175 /** 176 * Removes the given object as a child from this scene. 177 * 178 * Params: 179 * oldChild = The object to remove. 180 */ 181 final void removeChild( GameObject oldChild ) 182 { 183 _root.removeChild( oldChild ); 184 } 185 186 /** 187 * Gets all objects in the scene. 188 * 189 * Returns: All objects belonging to this scene. 190 */ 191 final @property GameObject[] objects() 192 { 193 return objectById.values; 194 } 195 }