1 /++ 2 The module describing the unit of the object - Instance. 3 4 An instance is an object in a scene with behavior only for itself with the 5 interaction of other instances, through collisions, any internal events. 6 Each instance has properties of execution conditions, rendering conditions, 7 rendering properties, conditions for the execution of some events. All of these 8 properties describe an instance, however, more behavior can be achieved using 9 inheritance (see `tida.localevent`). Instance functions are not inherited. but 10 they are directly written and marked with attributes that give execution 11 conditions (under what conditions it is necessary to execute, as if it is a 12 transfer of control between scenes, rendering of a frame, processing user input). 13 14 Also, an instance has a hard mask, where, when it touches another mask, 15 a collision event can be generated and such instances can handle this event, 16 if, of course, the corresponding functions have been marked with attributes. 17 18 --- 19 class MyObject : Instance 20 { 21 this() { ... } 22 23 @Init 24 void onInitFunction() 25 { 26 firstProperty = 0.0f; 27 position = vecf(32f, 11.5f); 28 ... 29 } 30 31 @Collision("OtherInstanceName") 32 void onCollsion(Instance other) 33 { 34 other.posiiton -= vecf(1, 0); 35 } 36 } 37 --- 38 39 Macros: 40 LREF = <a href="#$1">$1</a> 41 HREF = <a href="$1">$2</a> 42 43 Authors: $(HREF https://github.com/TodNaz,TodNaz) 44 Copyright: Copyright (c) 2020 - 2021, TodNaz. 45 License: $(HREF https://github.com/TodNaz/Tida/blob/master/LICENSE,MIT) 46 +/ 47 module tida.instance; 48 49 /++ 50 Checks if an object is an instance. 51 +/ 52 template isInstance(T) 53 { 54 enum isInstance = is(T : Instance); 55 } 56 57 /++ 58 Instance object. Can be created for a render unit as well as for legacy 59 with a programmable model. 60 +/ 61 class Instance 62 { 63 import tida.vector; 64 import tida.sprite; 65 import tida.shape; 66 import tida.component; 67 68 protected: 69 /++ 70 Instance sprite. Will be output at the position of the instance. 71 +/ 72 Sprite sprite; 73 74 /++ 75 Components of an instance, complementing its functionality. 76 +/ 77 Component[] components; 78 79 /// only for call. 80 bool _destroy = false; 81 82 public: 83 /++ 84 The name of the instance, by which you can later identify 85 the collided or other events. 86 +/ 87 string name; 88 89 /++ 90 Instance tags. By this parameter, it is possible to distribute an instance 91 about groups, for example, instances that should not let the player in upon 92 collision will be marked with the "solid" tag, but not necessarily only 93 non-living creatures should be used, and others who should not squeeze 94 through are marked with such a tag. 95 (This is an example, there is no such implementation in the framework). 96 +/ 97 string[] tags; 98 99 /++ 100 The position of the instance. Serves for collision, rendering, and 101 other instance services. 102 +/ 103 Vector!float position; 104 105 /++ 106 An auxiliary variable that remembers the position in the previous 107 pass of the game loop. 108 +/ 109 Vector!float previous; 110 111 /++ 112 Collision mask. A mask is a kind of geometric shape (or several shapes) 113 that sets the collision boundary between other instances. 114 +/ 115 Shape!float mask; 116 117 /++ 118 A property that determines whether an instance can collide with 119 other instances. 120 +/ 121 bool solid = false; 122 123 /++ 124 Instance identifier (often means storage location in an instances array). 125 +/ 126 size_t id; 127 128 /++ 129 The identifier for the instance in the stream. Shows which thread the 130 instance is running on (changing the property does not affect thread selection). 131 +/ 132 size_t threadid; 133 134 /++ 135 A property indicating whether to handle all events for such an instance. 136 If false, no event will be processed for this instance, however, 137 it will exist. It is necessary if you do not need to delete the instance, 138 but you also do not need to process its events. 139 +/ 140 bool active = true; 141 142 /++ 143 A property that indicates whether to render the instance and perform 144 rendering functions. 145 +/ 146 bool visible = true; 147 148 /++ 149 A property that indicates whether it is only necessary to draw the object 150 without handling other events in it. 151 +/ 152 bool onlyDraw = false; 153 154 /++ 155 A property that indicates whether to transition to a new scene when 156 transferring control to another scene. 157 +/ 158 bool persistent = false; 159 160 /++ 161 The identifier of the layer in which the instance is placed. 162 The render queue is affected, the larger the number, the later the 163 instance will be rendered. 164 +/ 165 int depth = 0; 166 167 @safe: 168 this() 169 { 170 sprite = new Sprite(); 171 172 name = typeid(this).stringof; 173 } 174 175 /++ 176 Removes an instance. However, not immediately, this will only happen on 177 the next iteration of the game loop for thread safety. 178 +/ 179 final void destroy() 180 { 181 _destroy = true; 182 } 183 184 /++ 185 A method for adding an instance to an instance to expand functionality. 186 187 Params: 188 component = Component object. 189 +/ 190 void add(T)(T component) 191 { 192 import tida.scenemanager; 193 static assert(isComponent!T, T.stringof ~ " is not a component!"); 194 195 components ~= component; 196 if (component.name == "") 197 component.name = T.stringof; 198 199 sceneManager.componentExplore!T(this, component); 200 } 201 202 /++ 203 A method for adding an instance to an instance to expand functionality. 204 205 Params: 206 T = Component type. 207 +/ 208 void add(T)() 209 { 210 add(new T()); 211 } 212 213 /++ 214 A function that returns a component based on its class. 215 216 Params: 217 T = Component type. 218 +/ 219 T cmp(T)() 220 { 221 static assert(isComponent!T, T.stringof ~ " is not a component!"); 222 223 foreach (e; components) 224 { 225 if ((cast(T) e) !is null) 226 { 227 return cast(T) e; 228 } 229 } 230 231 return null; 232 } 233 234 /++ 235 Finds a component by its name. 236 237 Params: 238 name = Component name. 239 +/ 240 Component cmp(string name) 241 { 242 foreach (e; components) 243 { 244 if (e.name == name) 245 return e; 246 } 247 248 return null; 249 } 250 251 /++ 252 Detaches a component from an instance by finding it by class. 253 254 Params: 255 T = Component type. 256 +/ 257 void dissconnect(T)() 258 { 259 import std.algorithm : remove; 260 import tida.scenemanager; 261 static assert(isComponent!T, "`" ~ T.stringof ~ "` is not a component!"); 262 263 Component cmp; 264 265 foreach (i; 0 .. components.length) 266 { 267 if ((cast(T) components[i]) !is null) 268 { 269 cmp = components[i]; 270 271 foreach(fun; sceneManager.leaveComponents[cmp]) fun(); 272 273 components = components.remove(i); 274 break; 275 } 276 } 277 } 278 279 /++ 280 Detaches a component from an instance by finding it by name. 281 282 Params: 283 T = Component type. 284 +/ 285 void dissconnect(string name) 286 { 287 import std.algorithm : remove; 288 import tida.scenemanager; 289 290 foreach (i; 0 .. components.length) 291 { 292 if (components[i].name == name) 293 { 294 foreach(fun; sceneManager.leaveComponents[components[i]]) fun(); 295 296 components = components.remove(i); 297 break; 298 } 299 } 300 } 301 302 /++ 303 Detaches absolutely all components in this instance. 304 +/ 305 void dissconnectAll() @trusted 306 { 307 import tida.scenemanager; 308 import std.algorithm : remove; 309 310 foreach (i; 0 .. components.length) 311 { 312 if (sceneManager !is null) 313 { 314 foreach(fun; sceneManager.leaveComponents[components[i]]) fun(); 315 } 316 317 components = components.remove(i); 318 } 319 } 320 321 package(tida): 322 Sprite spriteDraw() 323 { 324 return sprite; 325 } 326 327 bool isDestroy() 328 { 329 return _destroy; 330 } 331 332 Component[] getComponents() 333 { 334 return components; 335 } 336 }