1 module demos.space_invaders;
2 
3 import app;
4 
5 import bindbc.sdl;
6 
7 import bubel.ecs.attributes;
8 import bubel.ecs.core;
9 import bubel.ecs.entity;
10 import bubel.ecs.manager;
11 import bubel.ecs.std;
12 
13 import cimgui.cimgui;
14 
15 import ecs_utils.gfx.texture;
16 import ecs_utils.math.vector;
17 import ecs_utils.utils;
18 
19 import game_core.basic;
20 import game_core.rendering;
21 import game_core.collision;
22 
23 import gui.attributes;
24 
25 private enum float px = 1.0/512.0;
26 
27 
28 extern(C):
29 
30 /*#######################################################################################################################
31 ------------------------------------------------ Types ------------------------------------------------------------------
32 #######################################################################################################################*/
33 
34 struct SpaceInvaders
35 {
36     __gshared const (char)* tips = "Use \"WASD\" keys to move and \"Space\" for shooting.
37 On start there is not to much to do. But you can spawn thousands of entities. You can even change guild for enemies to make them kilking themselves.
38 You can add any component to any entity which sometimes can give fun results. This demo wasn't created with such  combination in mind, but that is something which comes naturally with ECS.";
39 
40     EntityTemplate* enemy_tmpl;
41     EntityTemplate* ship_tmpl;
42     EntityTemplate* laser_tmpl;
43     EntityTemplate*[5] bullet_tmpl;
44     Texture texture;
45 
46     ShootGrid* shoot_grid;
47 
48     bool move_system = true;
49     bool draw_system = true;
50     
51     const vec2 map_size = vec2(400,300);
52     const float cell_size = 60;
53 
54     EntityID player_ship;
55 
56     ~this() @nogc nothrow
57     {
58         // if(shoot_grid)Mallocator.dispose(shoot_grid);
59         if(enemy_tmpl)gEntityManager.freeTemplate(enemy_tmpl);
60         if(ship_tmpl)gEntityManager.freeTemplate(ship_tmpl);
61         if(laser_tmpl)gEntityManager.freeTemplate(laser_tmpl);
62         foreach (EntityTemplate* tmpl; bullet_tmpl)
63         {
64             if(tmpl)gEntityManager.freeTemplate(tmpl);
65         }
66         texture.destroy();
67     }
68 }
69 
70 struct SceneGrid
71 {
72     struct Element
73     {
74         EntityID entity;
75         int guild;
76         vec2 min;
77         vec2 max;
78     }
79 
80     struct Cell
81     {
82         Element[20] elements;
83     }
84 
85     void create()
86     {
87         cells_count.x = cast(int)((space_invaders.map_size.x - 0.01f) / space_invaders.cell_size) + 1;
88         cells_count.y = cast(int)((space_invaders.map_size.y - 0.01f) / space_invaders.cell_size) + 1;
89         cells = Mallocator.makeArray!Cell(cells_count.x * cells_count.y);
90     }
91 
92     void destroy()
93     {
94         if(cells)
95         {
96             Mallocator.dispose(cells);
97             cells = null;
98         }
99     }
100 
101     ivec2 cells_count;
102     Cell[] cells;
103 }
104 
105 enum Direction : byte 
106 {
107     up,
108     down,
109     left,
110     right
111 }
112 
113 /*#######################################################################################################################
114 ------------------------------------------------ Components ------------------------------------------------------------------
115 #######################################################################################################################*/
116 
117 /*struct CLocation
118 {
119     mixin ECS.Component;
120 
121     alias value this;
122 
123     vec2 value = vec2(0);
124 }
125 
126 struct CScale
127 {
128     mixin ECS.Component;
129 
130     ///use component as it value
131     alias value this;
132 
133     vec2 value = vec2(16,16);
134 }
135 
136 struct CDepth
137 {
138     mixin ECS.Component;
139 
140     alias depth this;
141 
142     short depth;
143 }
144 
145 struct CRotation
146 {
147     mixin ECS.Component;
148 
149     ///use component as it value
150     alias value this;
151 
152     float value = 0;
153 }
154 
155 struct CTexture
156 {
157     mixin ECS.Component;
158 
159     //Texture tex;
160     uint id;
161     vec4 coords = vec4(0,0,0,1);
162 }*/
163 
164 // struct CVelocity
165 // {
166 //     mixin ECS.Component;
167 
168 //     alias value this;
169 
170 //     vec2 value = vec2(0,0);
171 // }
172 
173 struct CEnemy
174 {
175     mixin ECS.Component;    
176 }
177 
178 struct CShip
179 {
180     mixin ECS.Component;
181 }
182 
183 struct CAutoShoot
184 {
185     mixin ECS.Component;
186 }
187 
188 struct CGuild
189 {
190     mixin ECS.Component;
191 
192     byte guild;
193 }
194 
195 struct CBullet
196 {
197     mixin ECS.Component;
198 
199     int damage = 1;
200 }
201 
202 struct CWeapon
203 {
204     mixin ECS.Component;
205 
206     static struct Level
207     {
208         float reload_time;
209         float dispersion;
210         int damage;
211     }
212 
213     __gshared Level[12] levels = [Level(4000,0),Level(4000,0.1),
214     Level(500,0),Level(350,0),Level(250,0.02),Level(175,0.03),Level(110,0.04),
215     Level(80,0.05),Level(50,0.08),Level(20,0.1),Level(10,0.12),Level(2,0.14)];
216 
217     enum Type : ubyte
218     {
219         laser,
220         enemy_laser,
221         blaster,
222         canon,
223         plasma
224     }
225 
226     float shoot_time = 0;
227     @GUIRange(0, 4) Type type;
228     @GUIRange(0, 11) ubyte level = 1;
229 }
230 
231 struct CWeaponLocation
232 {
233     mixin ECS.Component;
234 
235     vec2 rel_pos = vec2(0,0);
236 }
237 
238 struct CShootDirection
239 {
240     mixin ECS.Component;
241     
242     @GUIRange(0, 3) Direction direction;
243 }
244 
245 struct CSideMove
246 {
247     mixin ECS.Component;
248 
249     byte group = -1;
250 }
251 
252 struct CTargetParent
253 {
254     mixin ECS.Component;
255 
256     EntityID parent;
257     vec2 rel_pos = vec2(0,0);
258 }
259 
260 
261 struct CHitPoints
262 {
263     mixin ECS.Component;
264 
265     alias value this;
266 
267     int value = 3;
268 }
269 
270 struct CMaxHitPoints
271 {
272     mixin ECS.Component;
273 
274     alias value this;
275 
276     int value = 3;
277 }
278 
279 struct CHitMark
280 {
281     mixin ECS.Component;
282 
283     alias value this;
284 
285     ubyte value = 0;
286 }
287 
288 struct CUpgrade
289 {
290     mixin ECS.Component;
291 
292     alias value this;
293 
294     enum Upgrade : ubyte
295     {
296         hit_points,
297         regeneration,
298         laser
299     }
300 
301     Upgrade value;
302 }
303 
304 struct CAnimation
305 {
306     mixin ECS.Component;
307     
308     vec4[] frames;
309     @GUIRangeF(0, float.max)float time = 0;
310     @GUIRangeF(0, float.max)float speed = 1;
311 }
312 
313 struct CAnimationLooped
314 {
315     mixin ECS.Component;
316 }
317 
318 
319 
320 struct CParticle
321 {
322     mixin ECS.Component;
323 
324     float life = 0;
325 }
326 
327 struct CTarget 
328 {
329     mixin ECS.Component;
330 
331     EntityID target;
332 }
333 
334 struct CTargetPlayerShip
335 {
336     mixin ECS.Component;
337 }
338 
339 struct CChildren
340 {
341     mixin ECS.Component;
342 
343     EntityID[] childern;
344 }
345 
346 struct CBoss
347 {
348     mixin ECS.Component;
349 }
350 
351 struct CParts
352 {
353     mixin ECS.Component;
354 
355     @GUIDisabled ubyte count;
356 }
357 
358 struct CInit
359 {
360     mixin ECS.Component;
361 
362     enum Type
363     {
364         space_ship,
365         tower,
366         boss
367     }
368 
369     @GUIRange(0, 2)Type type;
370 }
371 
372 struct CParticleEmitter
373 {
374     mixin ECS.Component;
375 
376     vec2 range = vec2(0,0);
377     vec2 time_range = vec2(500,1000);
378     ///It can be array of tempaltes or (like in this demo) simply index of template;
379     //uint tmpl_id;
380     //EntityTemplate* tmpl;
381 }
382 
383 ///Due to perfarmance reason emitter time and attributes are divided into seprate components.
384 ///Beyon that both components are considerd to be used together.
385 struct CParticleEmitterTime
386 {
387     mixin ECS.Component;
388 
389     float time = 0;
390 }
391 
392 ///You can create separate component for every kind of spawned entities but it's not practial due to archetype fragmentation.
393 ///Second approach can be commented code. It's gives good flexibility inchoosing entity, but it limits to one entity.
394 ///Instead of entity it can be array of templates which is good solution, but if possibilities is known at time of game development it
395 ///can be simply index/enum for type of spawn. Bad thing about this solution is problem witch merging multiple spawning types during
396 ///gameplay, i.e. giving buff which cast firebols upon death.
397 struct CSpawnUponDeath
398 {
399     mixin ECS.Component;
400 
401     enum Type
402     {
403         flashes_emitter,
404     }
405 
406     //EntityID parent;
407     //EntityTemplate* tmpl;
408     @GUIRange(0,0) Type type;
409 }
410 
411 ///This component can be replaced by "CSpawnUponDeath" but I want to gives possibility to add this component to every entity
412 ///during gameplay. End application works exacly the same way for every demo so I can't use different way as adding component.
413 struct CShootWaveUponDeath
414 {
415     mixin ECS.Component;
416 
417     @GUIRange(0, 4) CWeapon.Type bullet_type;
418 }
419 
420 /*#######################################################################################################################
421 ------------------------------------------------ Events ------------------------------------------------------------------
422 #######################################################################################################################*/
423 
424 struct EChangeDirection
425 {
426     mixin ECS.Event;
427 
428     this(Direction direction)
429     {
430         this.direction = direction;
431     }
432 
433     Direction direction;
434 }
435 
436 struct EUpgrade
437 {
438     mixin ECS.Event;
439 }
440 
441 struct EDeath
442 {
443     mixin ECS.Event;
444 }
445 
446 struct EDamage
447 {
448     mixin ECS.Event;
449 
450     this(uint damage)
451     {
452         this.damage = damage;
453     }
454 
455     uint damage = 0;
456 }
457 
458 struct EBulletHit
459 {
460     mixin ECS.Event;
461 
462     this(EntityID id, uint damage)
463     {
464         this.id = id;
465         this.damage = damage;
466     }
467 
468     EntityID id;
469     uint damage;
470 }
471 
472 struct EDestroyedChild
473 {
474     mixin ECS.Event;
475 
476     this(EntityID id)
477     {
478         this.id = id;
479     }
480 
481     EntityID id;
482 }
483 
484 /*#######################################################################################################################
485 ------------------------------------------------ Systems ------------------------------------------------------------------
486 #######################################################################################################################*/
487 
488 struct ParentOwnerSystem
489 {
490     mixin ECS.System;
491 
492     struct EntitiesData
493     {
494         CChildren[] children;
495     }
496 
497     void onRemoveEntity(EntitiesData data)
498     {
499         //currently EntitiesData always has only one element
500         foreach(child; data.children[0].childern)
501         {
502             gEntityManager.removeEntity(child);
503         }
504         if(data.children[0].childern.length)Mallocator.dispose(data.children[0].childern);
505     }
506 }
507 
508 struct ShipWeaponSystem
509 {
510     mixin ECS.System;
511 
512     struct EntitiesData
513     {
514         int length;
515         Entity[] entity;
516         CInit[] init;
517         //CShip[] ship;
518         CChildren[] children;
519     }
520 
521     struct Ship
522     {
523         EntityTemplate* laser1_tmpl;
524         EntityTemplate* laser2_tmpl;
525         EntityTemplate* main_weapon_tmpl;
526 
527         void add(Entity* entity)
528         {
529             CChildren* children = entity.getComponent!CChildren;
530             if(children is null || children.childern.length != 0)return;
531             EntityID[3] weapons;
532             laser1_tmpl.getComponent!CTargetParent().parent = entity.id;
533             laser2_tmpl.getComponent!CTargetParent().parent = entity.id;
534             main_weapon_tmpl.getComponent!CTargetParent().parent = entity.id;
535             weapons[0] = gEntityManager.addEntity(laser1_tmpl).id;
536             weapons[1] = gEntityManager.addEntity(laser2_tmpl).id;
537             weapons[2] = gEntityManager.addEntity(main_weapon_tmpl).id;
538             children.childern = Mallocator.makeArray(weapons);
539         }
540 
541         void create()
542         {
543             laser1_tmpl = gEntityManager.allocateTemplate([becsID!CWeapon, becsID!CLocation, becsID!CShootDirection, becsID!CTargetParent, becsID!CGuild, becsID!CVelocity].staticArray);
544             main_weapon_tmpl = gEntityManager.allocateTemplate([becsID!CLocation, becsID!CShootDirection, becsID!CTargetParent, becsID!CGuild, becsID!CVelocity].staticArray);
545             *laser1_tmpl.getComponent!CWeapon = CWeapon(0,CWeapon.Type.laser,3);
546             laser1_tmpl.getComponent!CTargetParent().rel_pos = vec2(10,13);
547             main_weapon_tmpl.getComponent!CTargetParent().rel_pos = vec2(0,4);
548             laser2_tmpl = gEntityManager.allocateTemplate(laser1_tmpl);
549             laser2_tmpl.getComponent!CTargetParent().rel_pos = vec2(-10,13);
550         }
551 
552         ~this()
553         {
554             gEntityManager.freeTemplate(laser1_tmpl);
555             gEntityManager.freeTemplate(laser2_tmpl);
556             gEntityManager.freeTemplate(main_weapon_tmpl);
557         }
558     }
559 
560     struct Tower
561     {
562         EntityTemplate* weapon_tmpl;
563         EntityTemplate* top_tmpl;
564 
565         void add(Entity* entity)
566         {
567             CChildren* children = entity.getComponent!CChildren;
568             if(children is null || children.childern.length != 0)return;
569             CDepth* depth = entity.getComponent!CDepth;
570             EntityID[2] weapons;
571             weapon_tmpl.getComponent!CTargetParent().parent = entity.id;
572             if(depth)weapon_tmpl.getComponent!CDepth().value = cast(short)(depth.value - 1);
573             else weapon_tmpl.getComponent!CDepth().value = -1;
574             top_tmpl.getComponent!CTargetParent().parent = entity.id;
575             if(depth)top_tmpl.getComponent!CDepth().value = cast(short)(depth.value - 2);
576             else top_tmpl.getComponent!CDepth().value = -2;
577 
578             weapons[0] = gEntityManager.addEntity(weapon_tmpl).id;
579             weapons[1] = gEntityManager.addEntity(top_tmpl).id;
580             children.childern = Mallocator.makeArray(weapons);
581         }
582 
583         void create()
584         {
585             weapon_tmpl = gEntityManager.allocateTemplate(
586                 [becsID!CWeapon, becsID!CLocation, becsID!CShootDirection,
587                 becsID!CTargetParent, becsID!CGuild, becsID!CVelocity,
588                 becsID!CAutoShoot, becsID!CTarget, becsID!CTargetPlayerShip,
589                 becsID!CRotation, becsID!CScale, becsID!CTexCoords,
590                 becsID!CDepth, becsID!CWeaponLocation].staticArray);
591             *weapon_tmpl.getComponent!CWeapon = CWeapon(0,CWeapon.Type.laser,3);
592             weapon_tmpl.getComponent!CTargetParent().rel_pos = vec2(0,0);
593             weapon_tmpl.getComponent!CGuild().guild = 1;
594             weapon_tmpl.getComponent!CScale().value = vec2(4,16);
595             //weapon_tmpl.getComponent!CWeapon().level = 1;
596             *weapon_tmpl.getComponent!CWeapon() = CWeapon(0,CWeapon.Type.canon,1);
597             weapon_tmpl.getComponent!CDepth().value = -1;
598             weapon_tmpl.getComponent!CTexCoords().value = vec4(136,96,4,16)*px;
599             weapon_tmpl.getComponent!CWeaponLocation().rel_pos = vec2(0,12);
600 
601             top_tmpl = gEntityManager.allocateTemplate(
602                 [becsID!CLocation, becsID!CTargetParent, becsID!CScale, 
603                 becsID!CTexCoords, becsID!CDepth].staticArray);
604             top_tmpl.getComponent!CTargetParent().rel_pos = vec2(0,1);
605             top_tmpl.getComponent!CScale().value = vec2(10,11);
606             top_tmpl.getComponent!CDepth().value = -2;
607             top_tmpl.getComponent!CTexCoords().value = vec4(112,96,10,11)*px;
608             
609         }
610 
611         ~this()
612         {
613             gEntityManager.freeTemplate(weapon_tmpl);
614             gEntityManager.freeTemplate(top_tmpl);
615         }
616     }
617 
618     struct Boss
619     {
620         EntityTemplate* tower1_tmpl;
621         EntityTemplate* tower2_tmpl;
622         EntityTemplate* tower3_tmpl;
623         EntityTemplate* tower4_tmpl;
624 
625         void add(Entity* entity)
626         {
627             CChildren* children = entity.getComponent!CChildren;
628             if(children is null || children.childern.length != 0)return;
629             CParts* parts = entity.getComponent!CParts;
630             if(parts)parts.count = 4;
631             EntityID[4] towers;
632             tower1_tmpl.getComponent!CTargetParent().parent = entity.id;
633             tower2_tmpl.getComponent!CTargetParent().parent = entity.id;
634             tower3_tmpl.getComponent!CTargetParent().parent = entity.id;
635             tower4_tmpl.getComponent!CTargetParent().parent = entity.id;
636             towers[0] = gEntityManager.addEntity(tower1_tmpl).id;
637             towers[1] = gEntityManager.addEntity(tower2_tmpl).id;
638             towers[2] = gEntityManager.addEntity(tower3_tmpl).id;
639             towers[3] = gEntityManager.addEntity(tower4_tmpl).id;
640             children.childern = Mallocator.makeArray(towers);
641         }
642 
643         void create()
644         {
645             tower1_tmpl = gEntityManager.allocateTemplate(
646                 [becsID!CColor, becsID!CHitMark, becsID!CHitPoints, becsID!CLocation, 
647                 becsID!CTexCoords, becsID!CScale, becsID!CEnemy, 
648                 becsID!CShootGrid, becsID!CGuild, becsID!CInit,
649                 becsID!CChildren, becsID!CDepth, becsID!CTargetParent,
650                 becsID!CSpawnUponDeath, becsID!CShootWaveUponDeath, becsID!CShootGridMask].staticArray
651             );
652 
653             tower1_tmpl.getComponent!CTexCoords().value = vec4(96*px,96*px,16*px,16*px);
654             tower1_tmpl.getComponent!CLocation().value = vec2(64,space_invaders.map_size.y - 16);
655             tower1_tmpl.getComponent!CGuild().guild = 1;
656             tower1_tmpl.getComponent!CInit().type = CInit.Type.tower;  
657             tower1_tmpl.getComponent!CHitPoints().value = 10;
658             tower1_tmpl.getComponent!CDepth().value = -2;
659             tower1_tmpl.getComponent!CShootWaveUponDeath().bullet_type = CWeapon.Type.canon;
660             tower1_tmpl.getComponent!CTargetParent().rel_pos = vec2(-33,2);
661 
662             tower2_tmpl = gEntityManager.allocateTemplate(tower1_tmpl);
663             tower2_tmpl.getComponent!CTargetParent().rel_pos = vec2(33,2);
664 
665             tower3_tmpl = gEntityManager.allocateTemplate(tower1_tmpl);
666             tower3_tmpl.getComponent!CDepth().value = 0;
667             tower3_tmpl.getComponent!CTargetParent().rel_pos = vec2(-40,-15);
668 
669             tower4_tmpl = gEntityManager.allocateTemplate(tower1_tmpl);
670             tower4_tmpl.getComponent!CDepth().value = 0;
671             tower4_tmpl.getComponent!CTargetParent().rel_pos = vec2(40,-15);
672         }
673 
674         ~this()
675         {
676             gEntityManager.freeTemplate(tower1_tmpl);
677             gEntityManager.freeTemplate(tower2_tmpl);
678             gEntityManager.freeTemplate(tower3_tmpl);
679             gEntityManager.freeTemplate(tower4_tmpl);
680         }
681     }
682 
683     Ship ship;
684     Tower tower;
685     Boss boss;
686 
687     void onCreate()
688     {
689         ship.create();
690         tower.create();
691         boss.create();
692     }
693 
694     void onDestroy()
695     {
696         __xdtor();
697     }
698 
699     void onAddEntity(EntitiesData data)
700     {
701         foreach(i; 0..data.length)
702         {
703             final switch(data.init[i].type)
704             {
705                 case CInit.Type.space_ship:ship.add(&data.entity[i]);break;
706                 case CInit.Type.tower:tower.add(&data.entity[i]);break;
707                 case CInit.Type.boss:boss.add(&data.entity[i]);break;
708             }
709         }
710     }
711 }
712 
713 struct MoveToParentTargetSystem
714 {
715     mixin ECS.System!32;
716 
717     struct EntitiesData
718     {
719         int length;
720         CLocation[] location;
721         @optional CVelocity[] velocity;
722         @readonly CTargetParent[] target;
723     }
724 
725     void onUpdate(EntitiesData data)
726     {
727         if(data.velocity)
728         {
729             foreach(i;0..data.length)
730             {
731                 Entity* target = gEntityManager.getEntity(data.target[i].parent);
732                 if(target)
733                 {
734                     CLocation* target_loc = target.getComponent!CLocation;
735                     if(target_loc != null)
736                     {
737                         data.location[i] = *target_loc + data.target[i].rel_pos;
738                     }
739                     CVelocity* target_vel = target.getComponent!CVelocity;
740                     if(target_vel != null)
741                     {
742                         data.velocity[i] = *target_vel;
743                     }
744                 }
745             }
746         }
747         else
748         foreach(i;0..data.length)
749         {
750             Entity* target = gEntityManager.getEntity(data.target[i].parent);
751             if(target)
752             {
753                 CLocation* target_loc = target.getComponent!CLocation;
754                 if(target_loc != null)
755                 {
756                     data.location[i] = *target_loc + data.target[i].rel_pos;
757                 }
758             }
759         }
760     }
761 }
762 /*
763 struct DrawSystem
764 {
765     mixin ECS.System!32;
766 
767     struct EntitiesData
768     {
769         uint length;
770         //uint thread_id;
771         uint job_id;
772         @readonly CTexCoords[] textures;
773         @readonly CLocation[] locations;
774         @readonly CScale[] scale;
775         @readonly @optional CRotation[] rotation;
776         @readonly @optional CDepth[] depth;
777         @readonly @optional CHitMark[] hit_mark;
778     }
779 
780     void onUpdate(EntitiesData data)
781     {
782         if(launcher.renderer.prepared_items >= launcher.renderer.MaxObjects)return;//simple leave loop if max visible objects count was reached
783         import ecs_utils.gfx.renderer;
784         Renderer.DrawData draw_data;
785         draw_data.color = 0x80808080;
786         draw_data.thread_id = data.job_id;
787         draw_data.texture = space_invaders.texture;
788         //uint color_mask = 0xFCFCFCFC;
789         uint const_map = 0x80A08080;//0x80808080;
790         if(!data.depth)
791         {
792             if(data.hit_mark)
793             {
794                 foreach(i; 0..data.length)
795                 {
796                     draw_data.color = 0x80808080 + 0x01010101 * data.hit_mark[i];
797                     draw_data.depth = cast(short)(data.locations[i].y);
798                     draw_data.coords = data.textures[i].value;
799                     draw_data.size = data.scale[i];
800                     draw_data.position = data.locations[i];
801                     launcher.renderer.draw(draw_data);
802                     //launcher.renderer.draw(space_invaders.texture, data.locations[i].value, data.scale[i], data.textures[i].coords, depth, color|const_map, 0, 0, 0, data.job_id);
803                 }
804             }
805             else if(data.rotation)
806             {
807                 foreach(i; 0..data.length)
808                 {
809                     draw_data.depth = cast(short)(data.locations[i].y);
810                     draw_data.angle = data.rotation[i];
811                     draw_data.coords = data.textures[i].value;
812                     draw_data.size = data.scale[i];
813                     draw_data.position = data.locations[i];
814                     launcher.renderer.draw(draw_data);
815                     //launcher.renderer.draw(space_invaders.texture, data.locations[i].value, data.scale[i], data.textures[i].coords, depth, 0x80808080|const_map, data.rotation[i], 0, 0, data.job_id);
816                 }
817             }
818             else
819             {
820                 foreach(i; 0..data.length)
821                 {
822                     draw_data.depth = cast(short)(data.locations[i].y);
823                     draw_data.coords = data.textures[i].value;
824                     draw_data.size = data.scale[i];
825                     draw_data.position = data.locations[i];
826                     launcher.renderer.draw(draw_data);
827                     //launcher.renderer.draw(space_invaders.texture, data.locations[i].value, data.scale[i], data.textures[i].coords, depth, 0x80808080|const_map, 0, 0, 0, data.job_id);
828                 }
829             }
830         }
831         else
832         {
833             if(data.hit_mark)
834             {
835                 if(data.rotation)
836                 {
837                     foreach(i; 0..data.length)
838                     {
839                         draw_data.color = 0x80808080 + 0x01010101 * data.hit_mark[i];
840                         draw_data.angle = data.rotation[i];
841                         draw_data.depth = cast(short)(data.depth[i] * 8 + data.locations[i].y);
842                         draw_data.coords = data.textures[i].value;
843                         draw_data.size = data.scale[i];
844                         draw_data.position = data.locations[i];
845                         launcher.renderer.draw(draw_data);
846                         //launcher.renderer.draw(space_invaders.texture, data.locations[i].value, data.scale[i], data.textures[i].coords, depth, color|const_map, data.rotation[i], 0, 0, data.job_id);
847                     }
848                 }
849                 else
850                 {
851                     foreach(i; 0..data.length)
852                     {
853                         draw_data.color = 0x80808080 + 0x01010101 * data.hit_mark[i];
854                         draw_data.depth = cast(short)(data.depth[i] * 8 + data.locations[i].y);
855                         draw_data.coords = data.textures[i].value;
856                         draw_data.size = data.scale[i];
857                         draw_data.position = data.locations[i];
858                         launcher.renderer.draw(draw_data);
859                         //launcher.renderer.draw(space_invaders.texture, data.locations[i].value, data.scale[i], data.textures[i].coords, depth, color|const_map, 0, 0, 0, data.job_id);
860                     }
861                 }
862             }
863             else if(data.rotation)
864             {
865                 foreach(i; 0..data.length)
866                 {
867                     draw_data.angle = data.rotation[i];
868                     draw_data.depth = cast(short)(data.depth[i] * 8 + data.locations[i].y);
869                     draw_data.coords = data.textures[i].value;
870                     draw_data.size = data.scale[i];
871                     draw_data.position = data.locations[i];
872                     launcher.renderer.draw(draw_data);
873                     //launcher.renderer.draw(space_invaders.texture, data.locations[i].value, data.scale[i], data.textures[i].coords, depth, 0x80808080|const_map, data.rotation[i], 0, 0, data.job_id);
874                 }
875             }
876             else
877             {
878                 foreach(i; 0..data.length)
879                 {
880                     draw_data.depth = cast(short)(data.depth[i] * 8 + data.locations[i].y);
881                     draw_data.coords = data.textures[i].value;
882                     draw_data.size = data.scale[i];
883                     draw_data.position = data.locations[i];
884                     launcher.renderer.draw(draw_data);
885                     //launcher.renderer.draw(space_invaders.texture, data.locations[i].value, data.scale[i], data.textures[i].coords, depth, 0x80808080|const_map, 0, 0, 0, data.job_id);
886                 }
887             }
888         }
889         //if(data.thread_id == 0)launcher.renderer.pushData();
890     }
891 }*/
892 
893 struct CollisionSystem
894 {
895     mixin ECS.System;
896 
897     struct EntitiesData
898     {
899 
900     }
901 
902     void onUpdate(EntitiesData data)
903     {
904 
905     }
906 }
907 
908 struct ShootingSystem
909 {
910     mixin ECS.System!32;
911 
912     bool shoot = false;
913 
914     __gshared vec4[] fire_frames = [vec4(96,64,8,16)*px,vec4(104,64,8,16)*px,vec4(112,64,8,16)*px,vec4(120,64,8,16)*px,vec4(128,64,8,16)*px,
915     vec4(136,64,8,16)*px,vec4(144,64,8,16)*px,vec4(152,64,8,16)*px,vec4(160,64,8,16)*px];
916 
917     // __gshared vec4[] fire_frames = [vec4(0,160,8,16)*px,vec4(16,160,16,16)*px,vec4(32,160,16,16)*px,vec4(48,160,16,16)*px,vec4(64,160,16,16)*px,
918     // vec4(80,160,16,16)*px,vec4(96,160,16,16)*px,vec4(112,160,16,16)*px];
919 
920     struct EntitiesData
921     {
922         ///variable named "length" contain entites count
923         uint length;
924         CWeapon[] laser;
925         @readonly CLocation[] location;
926         @readonly CGuild[] guild;
927 
928         @optional @readonly CShootDirection[] shoot_direction;
929         @optional @readonly CWeaponLocation[] weapon_location;
930         @optional @readonly CAutoShoot[] auto_shoot;
931         @optional @readonly CVelocity[] velocity;
932         @optional @readonly CRotation[] rotation;
933     }
934 
935     EntityTemplate* fire_tmpl;
936 
937     ///Called inside "registerSystem" function
938     void onCreate()
939     {
940         fire_tmpl = gEntityManager.allocateTemplate(
941             [becsID!CLocation, becsID!CTexCoords, becsID!CScale, 
942             becsID!CAnimation, becsID!CParticle, becsID!CRotation, 
943             becsID!CVelocity, becsID!CDamping].staticArray
944             );
945 
946         fire_tmpl.getComponent!CTexCoords().value = vec4(96,64,8,16)*px;
947         fire_tmpl.getComponent!CScale().value = vec2(8,16);
948         fire_tmpl.getComponent!(CParticle).life = 300;
949         *fire_tmpl.getComponent!(CAnimation) = CAnimation(fire_frames, 0, 3);
950     }
951 
952     void onDestroy()
953     {
954         gEntityManager.freeTemplate(fire_tmpl);
955     }
956 
957     bool onBegin()
958     {
959         if(launcher.getKeyState(SDL_SCANCODE_SPACE))
960         {
961             shoot = true;
962         }
963         else shoot = false;
964         return true;
965     }
966 
967     void onUpdate(EntitiesData data)
968     {
969         //conditional branch for whole entities block
970         if(shoot || data.auto_shoot)
971         {
972             foreach(i;0..data.length)
973             {
974                 CWeapon* laser = &data.laser[i];
975                 laser.shoot_time += launcher.deltaTime;
976                 while(laser.shoot_time > CWeapon.levels[laser.level - 1].reload_time)
977                 {
978                     CVelocity laser_velocity;
979                     CGuild laser_guild;
980                     CLocation laser_location;
981                     CVelocity fire_velocity;
982                     CLocation fire_location;
983                     CRotation fire_rotation;
984 
985                     laser.shoot_time -= CWeapon.levels[laser.level - 1].reload_time;
986                     laser_location.value = data.location[i];
987 
988                     laser_velocity.value = vec2((randomf()*2-1) * CWeapon.levels[laser.level - 1].dispersion,0.5);//data.shoot_direction[i].direction == Direction.up ? 1.0 : -1.0);
989                     if(data.shoot_direction && data.shoot_direction[i].direction == Direction.down)laser_velocity.y = -0.5;
990 
991                     laser_guild.guild = data.guild[i].guild;
992 
993                     if(laser.level < 3)laser_velocity.value = laser_velocity.value * 0.4f; 
994                     
995                     if(data.velocity)
996                     {
997                         fire_velocity.value = data.velocity[i];
998                         //laser_velocity.value += data.velocity[i] * 0.5;
999                     }
1000                     else fire_velocity.value = vec2(0,0);
1001 
1002                     fire_location.value = data.location[i];
1003                     if(data.shoot_direction && data.shoot_direction[i].direction == Direction.down)
1004                     {
1005                         fire_rotation.value = PI;
1006                         //fire_location.value.y -= 16;
1007                     }
1008                     else 
1009                     {
1010                         fire_rotation.value = 0;
1011                         //fire_location.value.y += 24;
1012                     }
1013 
1014                     if(data.rotation)
1015                     {
1016                         float sinn = sinf(data.rotation[i]);
1017                         float coss = cosf(data.rotation[i]);
1018                         float x = laser_velocity.y*sinn + laser_velocity.x*coss;
1019                         float y = laser_velocity.y*coss + laser_velocity.x*sinn;
1020                         laser_velocity.value = vec2(x,y);
1021                         fire_rotation.value = data.rotation[i];
1022                         if(data.weapon_location)
1023                         {
1024                             vec2 rel_pos = vec2(data.weapon_location[i].rel_pos.y*sinn+data.weapon_location[i].rel_pos.x*coss, data.weapon_location[i].rel_pos.y*coss+data.weapon_location[i].rel_pos.x*sinn);
1025                             laser_location.value += rel_pos;
1026                             fire_location.value += rel_pos;
1027                         }
1028                     }
1029                     else if(data.weapon_location)
1030                     {
1031                         laser_location.value += data.weapon_location[i].rel_pos;
1032                         fire_location.value += data.weapon_location[i].rel_pos;
1033                     }
1034 
1035                     gEntityManager.addEntity(space_invaders.bullet_tmpl[data.laser[i].type],[laser_velocity.ref_, laser_guild.ref_, laser_location.ref_].staticArray);
1036                     gEntityManager.addEntity(fire_tmpl,[fire_location.ref_, fire_rotation.ref_, fire_velocity.ref_].staticArray);
1037                 }
1038             }
1039         }
1040         else
1041         {
1042             foreach(i;0..data.length)
1043             {
1044                 CWeapon* laser = &data.laser[i];
1045                 laser.shoot_time += launcher.delta_time;
1046                 if(laser.shoot_time > CWeapon.levels[laser.level - 1].reload_time)laser.shoot_time = CWeapon.levels[laser.level - 1].reload_time;
1047             }
1048         }
1049         
1050     }
1051 }
1052 
1053 struct BulletsCollisionSystem
1054 {
1055     mixin ECS.System!32;
1056 
1057     mixin ECS.ReadOnlyDependencies!(ShootGridDependency);
1058 
1059     struct EntitiesData
1060     {
1061         ///variable named "length" contain entites count
1062         uint length;
1063         const (Entity)[] entity;
1064         @readonly CLocation[] location;
1065         @readonly CBullet[] bullet;
1066         @readonly CGuild[] guild;
1067     }
1068 
1069     void onUpdate(EntitiesData data)
1070     {
1071         EntityID id;
1072         foreach(i; 0..data.length)
1073         {
1074             if(space_invaders.shoot_grid.test(id, data.location[i], cast(ubyte)(~(1 << data.guild[i].guild))))
1075             {
1076                 gEntityManager.sendEvent(id, EBulletHit(data.entity[i].id,data.bullet[i].damage));
1077                 //gEntityManager.removeEntity(data.entity[i].id);
1078             }
1079         }
1080     }
1081 }
1082 
1083 struct CollisionMaskSystem
1084 {
1085     mixin ECS.System;
1086 
1087     mixin ECS.ReadOnlyDependencies!(ShootGridDependency);
1088 
1089     struct EntitiesData
1090     {
1091         ///variable named "length" contain entites count
1092         uint length;
1093         CShootGridMask[] mask;
1094         @readonly CGuild[] guild;
1095     }
1096 
1097     void onAddEntity(EntitiesData data)
1098     {
1099         foreach(i;0..data.length)
1100         {
1101             data.mask[i] = cast(ubyte)(1 << data.guild[i].guild);
1102         }
1103     }
1104 }
1105 
1106 struct ParticleEmittingSystem
1107 {
1108     mixin ECS.System!32;
1109 
1110     struct EntitiesData
1111     {
1112         uint length;
1113         //uint thread_id;
1114         CParticleEmitterTime[] emit_time;
1115         @readonly CLocation[] location;
1116         @readonly CParticleEmitter[] emitter;
1117 
1118         @optional @readonly CVelocity[] velocity;
1119         @optional @readonly CDepth[] depth;
1120     }
1121     
1122     __gshared vec4[] flashes = [vec4(224,0,16,16)*px,vec4(240,0,16,16)*px,vec4(256,0,16,16)*px,vec4(272,0,16,16)*px,vec4(288,0,16,16)*px,
1123     vec4(304,0,16,16)*px,vec4(320,0,16,16)*px];
1124 
1125     EntityTemplate*[1] templates;
1126 
1127     void onCreate()
1128     {
1129         templates[0] = gEntityManager.allocateTemplate(
1130             [becsID!CLocation, becsID!CTexCoords, becsID!CScale, 
1131             becsID!CAnimation, becsID!CParticle, becsID!CRotation, 
1132             becsID!CVelocity, becsID!CDamping, becsID!CDepth].staticArray);
1133         *templates[0].getComponent!CAnimation() = CAnimation(flashes,0,2);
1134         *templates[0].getComponent!CParticle() = CParticle(350);
1135         //*templates[0].getComponent!CDepth() = CDepth(-3);
1136     }
1137 
1138     void onDestroy()
1139     {
1140         foreach(tmpl; templates)
1141         {
1142             gEntityManager.freeTemplate(tmpl);
1143         }
1144     }
1145 
1146     void onUpdate(EntitiesData data)
1147     {
1148         foreach(i;0..data.length)
1149         {
1150             data.emit_time[i].time -= launcher.delta_time;
1151             while(data.emit_time[i].time < 0)
1152             {
1153                 CVelocity velocity;
1154                 CDepth depth;
1155 
1156                 CParticleEmitter* emitter = &data.emitter[i];
1157                 data.emit_time[i].time += emitter.time_range.x + randomf() * emitter.time_range.y;
1158 
1159                 if(data.velocity)
1160                 {
1161                     velocity.value = data.velocity[i];
1162                 }
1163 
1164                 if(data.depth)
1165                 {
1166                     depth.value = data.depth[i];
1167                 }
1168 
1169                 gEntityManager.addEntity(templates[0],[data.location[i].ref_,velocity.ref_,depth.ref_].staticArray);
1170             }
1171         }
1172     }
1173 }
1174 
1175 struct UpgradeCollisionSystem
1176 {
1177     mixin ECS.System!32;
1178 
1179     mixin ECS.ReadOnlyDependencies!(ShootGridDependency);
1180 
1181     struct EntitiesData
1182     {
1183         ///variable named "length" contain entites count
1184         uint length;
1185         const (Entity)[] entity;
1186         @readonly CLocation[] location;
1187         @readonly CUpgrade[] upgrade;
1188     }
1189 
1190     void onUpdate(EntitiesData data)
1191     {
1192         EntityID id;
1193         foreach(i; 0..data.length)
1194         {
1195             if(space_invaders.shoot_grid.test(id, data.location[i], cast(ubyte)(0xFF)))
1196             {
1197                 Entity* entity = gEntityManager.getEntity(id);
1198                 if(entity && entity.hasComponent(becsID!CShip))
1199                 {
1200                     gEntityManager.sendEvent(id, EUpgrade());
1201                     gEntityManager.removeEntity(data.entity[i].id);
1202                 }
1203             }
1204         }
1205     }
1206 }
1207 
1208 struct UpgradeSystem
1209 {
1210     mixin ECS.System;
1211 
1212     struct EntitiesData
1213     {
1214         const (Entity)[] entity;
1215         //@readonly CShip[] ship;
1216     }
1217 
1218     void handleEvent(Entity* entity, EUpgrade event)
1219     {
1220         CWeapon* laser = entity.getComponent!CWeapon;
1221         if(laser)
1222         {
1223             if(laser.level < CWeapon.levels.length)laser.level++;
1224         }
1225         CShip* ship = entity.getComponent!CShip;
1226         if(ship)
1227         {
1228             CChildren* children = entity.getComponent!CChildren;
1229             if(children)
1230             {
1231                 foreach(child;children.childern)
1232                 {
1233                     gEntityManager.sendEvent(child,EUpgrade());
1234                 }
1235             }
1236         }
1237     }
1238 }
1239 
1240 struct ChangeDirectionSystem
1241 {
1242     mixin ECS.System!32;
1243 
1244     Direction[8] groups_directions;
1245     bool has_changes;
1246 
1247     struct EntitiesData
1248     {
1249         uint length;
1250         const (Entity)[] entities;
1251         const (CLocation)[] locations;
1252         CVelocity[] velocity;
1253 
1254         const(CSideMove)[] side_move;
1255         @optional const(CScale)[] scale;
1256     }
1257 
1258     void onCreate()
1259     {
1260         foreach(ref direction; groups_directions)
1261         {
1262             direction = cast(Direction)-1;
1263         }
1264     }
1265 
1266     void onEnd()
1267     {
1268         if(has_changes)
1269         {
1270             foreach(ref direction; groups_directions)
1271             {
1272                 direction = cast(Direction)-1;
1273             }
1274         }
1275         has_changes = false;
1276         foreach(ref direction; groups_directions)
1277         {
1278             if(direction != cast(Direction)-1)
1279             {
1280                 has_changes = true;
1281             }
1282         }
1283     }
1284 
1285     void onUpdate(EntitiesData data)
1286     {
1287         //if(!data.side_move)return;
1288         if(has_changes)
1289         foreach(i;0..data.length)
1290         {
1291             byte group = data.side_move[i].group;
1292             if(group == -1)
1293             {
1294                 if(data.locations[i].x < 0)
1295                 {
1296                     if(data.velocity[i].x < 0)data.velocity[i].x = -data.velocity[i].x;
1297                 }
1298                 else if(data.locations[i].x > space_invaders.map_size.x)
1299                 {
1300                     if(data.velocity[i].x > 0)data.velocity[i].x = -data.velocity[i].x;
1301                 }
1302             }
1303             else
1304             {
1305                 Direction direction = groups_directions[group];
1306                 if(direction != cast(Direction)-1)
1307                 {
1308                     CVelocity* velocity = &data.velocity[i];
1309                     final switch(direction)
1310                     {
1311                         case Direction.up:
1312                             if(velocity.value.y > 0)velocity.value.y = -velocity.value.y;
1313                             break;
1314                         case Direction.down:
1315                             if(velocity.value.y < 0)velocity.value.y = -velocity.value.y;
1316                             break;
1317                         case Direction.left:
1318                             if(velocity.value.x > 0)velocity.value.x = -velocity.value.x;
1319                             break;
1320                         case Direction.right:
1321                             if(velocity.value.x < 0)velocity.value.x = -velocity.value.x;
1322                             break;
1323                     }
1324                 }
1325             }
1326         }
1327         else if(data.scale)
1328         {
1329             foreach(i;0..data.length)
1330             {
1331                 if(data.locations[i].x - data.scale[i].x * 0.5 < 0)
1332                 {
1333                     if(data.side_move[i].group == -1)
1334                     {
1335                         if(data.velocity[i].x < 0)data.velocity[i].x = -data.velocity[i].x;
1336                     }
1337                     else
1338                     {
1339                         groups_directions[data.side_move[i].group] = Direction.right;
1340                     }
1341                 }
1342                 else if(data.locations[i].x + data.scale[i].x * 0.5 > space_invaders.map_size.x)
1343                 {
1344                     if(data.side_move[i].group == -1)
1345                     {
1346                         if(data.velocity[i].x > 0)data.velocity[i].x = -data.velocity[i].x;
1347                     }
1348                     else
1349                     {
1350                         groups_directions[data.side_move[i].group] = Direction.left;
1351                     }
1352                 }
1353             }
1354         }
1355         else
1356         {
1357             foreach(i;0..data.length)
1358             {
1359                 if(data.locations[i].x < 0)
1360                 {
1361                     if(data.side_move[i].group == -1)
1362                     {
1363                         if(data.velocity[i].x < 0)data.velocity[i].x = -data.velocity[i].x;
1364                     }
1365                     else
1366                     {
1367                         groups_directions[data.side_move[i].group] = Direction.right;
1368                     }
1369                 }
1370                 else if(data.locations[i].x > space_invaders.map_size.x)
1371                 {
1372                     if(data.side_move[i].group == -1)
1373                     {
1374                         if(data.velocity[i].x > 0)data.velocity[i].x = -data.velocity[i].x;
1375                     }
1376                     else
1377                     {
1378                         groups_directions[data.side_move[i].group] = Direction.left;
1379                     }
1380                 }
1381             }
1382         }
1383     }
1384 }
1385 
1386 struct HitMarkingSystem
1387 {
1388     mixin ECS.System!16;
1389 
1390     struct EntitiesData
1391     {
1392         uint length;
1393         CHitMark[] mark;
1394         CColor[] color;
1395     }
1396 
1397     void onUpdate(EntitiesData data)
1398     {
1399         foreach(i;0..data.length)
1400         {
1401             //if(data.mark[i] < 10)data.mark[i] = 0;
1402             //else data.mark[i] -= 1;
1403             data.mark[i] = cast(ubyte)(data.mark[i] * 0.9);
1404             data.color[i] = 0x80808080 + 0x01010101 * data.mark[i];
1405         }
1406     }
1407 }
1408 
1409 struct HitPointsSystem
1410 {
1411     mixin ECS.System;
1412 
1413     __gshared vec4[] upgrade_laser_frames = [vec4(96,80,16,16)*px,vec4(112,80,16,16)*px,vec4(128,80,16,16)*px,vec4(144,80,16,16)*px,vec4(128,80,16,16)*px,vec4(112,80,16,16)*px];
1414     __gshared vec4[] explosion_laser_frames = [vec4(80,128,16,16)*px,vec4(96,128,16,16)*px,vec4(112,128,16,16)*px,vec4(128,128,16,16)*px,vec4(144,128,16,16)*px,vec4(160,128,16,16)*px,vec4(176,128,16,16)*px,vec4(192,128,16,16)*px,vec4(208,128,16,16)*px];
1415 
1416     EntityTemplate* upgrade_tmpl;
1417     EntityTemplate* explosion_tmpl;
1418 
1419     struct EntitiesData
1420     {
1421         CHitPoints[] hp;
1422     }
1423 
1424     void onCreate()
1425     {
1426         upgrade_tmpl = gEntityManager.allocateTemplate(
1427             [becsID!CVelocity, becsID!CLocation, becsID!CTexCoords, 
1428             becsID!CScale, becsID!CUpgrade, becsID!CAnimation, 
1429             becsID!CAnimationLooped].staticArray);
1430         //tex_comp.tex = space_invaders.texture;//ship_tex;
1431         upgrade_tmpl.getComponent!CTexCoords().value = vec4(0*px,32*px,16*px,16*px);
1432         *upgrade_tmpl.getComponent!CAnimation = CAnimation(upgrade_laser_frames, 0, 1);
1433         upgrade_tmpl.getComponent!CVelocity().value = vec2(0,-0.05);
1434 
1435         explosion_tmpl = gEntityManager.allocateTemplate(
1436             [becsID!CDepth, becsID!CParticle, becsID!CLocation, 
1437             becsID!CTexCoords, becsID!CScale, becsID!CAnimation].staticArray);
1438         //explosion_tmpl.getComponent!(CTexCoords).tex = space_invaders.texture;
1439         *explosion_tmpl.getComponent!CAnimation = CAnimation(explosion_laser_frames, 0, 1.333);
1440         explosion_tmpl.getComponent!(CParticle).life = 600;
1441         *explosion_tmpl.getComponent!CDepth = -1;
1442     }
1443 
1444     void onDestroy()
1445     {
1446         gEntityManager.freeTemplate(upgrade_tmpl);
1447         gEntityManager.freeTemplate(explosion_tmpl);
1448     }
1449 
1450     /*void handleEvent(Entity* entity, EDamage event)
1451     {
1452         CHitPoints* hp = entity.getComponent!CHitPoints;
1453         if(*hp <= 0)return;
1454         *hp -= event.damage;
1455         if(*hp <= 0)
1456         {
1457             gEntityManager.sendEvent(entity.id, EDeath());
1458             //gEntityManager.removeEntity(entity.id);
1459         }
1460         CHitMark* hit_mark = entity.getComponent!CHitMark;
1461         if(hit_mark)hit_mark.value = 127;
1462     }*/
1463     
1464     void handleEvent(Entity* entity, EBulletHit event)
1465     {
1466         CHitPoints* hp = entity.getComponent!CHitPoints;
1467         if(*hp <= 0)return;
1468         gEntityManager.removeEntity(event.id);
1469         *hp -= event.damage;
1470         if(*hp <= 0)
1471         {
1472             gEntityManager.sendEvent(entity.id, EDeath());
1473             //gEntityManager.removeEntity(entity.id);
1474         }
1475         CHitMark* hit_mark = entity.getComponent!CHitMark;
1476         if(hit_mark)hit_mark.value = 127;
1477     }
1478 
1479     void handleEvent(Entity* entity, EDeath event)
1480     {
1481         CEnemy* enemy = entity.getComponent!CEnemy;
1482         if(enemy)
1483         {
1484             CLocation* location = entity.getComponent!CLocation;
1485             if(location)
1486             {
1487                 if(randomRange(0, 1000) < 5)
1488                 {
1489                     gEntityManager.addEntity(upgrade_tmpl,[location.ref_].staticArray);
1490                 }
1491                 gEntityManager.addEntity(explosion_tmpl,[location.ref_].staticArray);
1492             }
1493         }
1494         gEntityManager.removeEntity(entity.id);
1495     }
1496 }
1497 
1498 struct ChildDestroySystem
1499 {
1500     mixin ECS.System;
1501 
1502     struct EntitiesData
1503     {
1504         CTargetParent[] parent;
1505     }
1506 
1507     void handleEvent(Entity* entity, EDeath event)
1508     {
1509         CTargetParent* parent = entity.getComponent!CTargetParent;
1510         if(parent)
1511         {
1512             gEntityManager.sendEvent(parent.parent, EDestroyedChild(entity.id));
1513         }
1514     }
1515 }
1516 
1517 struct ShootWaveSystem
1518 {
1519     mixin ECS.System;
1520 
1521     struct EntitiesData
1522     {
1523         CLocation[] location;
1524         CShootWaveUponDeath[] shoot_wave;
1525     }
1526 
1527     vec2[] dirs;
1528 
1529     void onCreate()
1530     {
1531         enum count = 24;
1532         dirs = Mallocator.makeArray!vec2(count);
1533         float step = 2 * PI / cast(float)count;
1534         foreach(i;0..count)
1535         {
1536             float angle = step * i;
1537             dirs[i] = vec2(sinf(angle),cosf(angle)) * 0.2;
1538         }
1539     }
1540 
1541     void onDestroy()
1542     {
1543         Mallocator.dispose(dirs);
1544     }
1545 
1546     void handleEvent(Entity* entity, EDeath event)
1547     {
1548 
1549         CShootWaveUponDeath* wave = entity.getComponent!CShootWaveUponDeath;
1550         CLocation* location = entity.getComponent!CLocation;
1551         CGuild* guild = entity.getComponent!CGuild;
1552 
1553         //ShootingSystem.bullet_tmpl
1554         EntityTemplate* tmpl = space_invaders.bullet_tmpl[wave.bullet_type];
1555         foreach(dir;dirs)
1556         {
1557             if(guild)gEntityManager.addEntity(tmpl,[location.ref_,guild.ref_,CVelocity(dir).ref_].staticArray);
1558             else gEntityManager.addEntity(tmpl,[location.ref_,CVelocity(dir).ref_].staticArray);
1559         }
1560         //gEntityManager.addEntity(tmpl);//,[location.ref_].staticArray);
1561 
1562         //gEntityManager.addEntity(space_invaders.bullet_tmpl[0]);
1563     }
1564 }
1565 
1566 struct PartsDestroySystem
1567 {
1568     mixin ECS.System;
1569 
1570     struct EntitiesData
1571     {
1572         CInit[] init;
1573         CChildren[] children;
1574         CParts[] parts;
1575     }
1576 
1577     EntityTemplate* flashes_emitter;
1578 
1579     void onCreate()
1580     {
1581         flashes_emitter = gEntityManager.allocateTemplate(
1582             [
1583                 becsID!CVelocity, becsID!CLocation, becsID!CParticleEmitter,
1584                 becsID!CParticleEmitterTime, becsID!CTargetParent, becsID!CDepth
1585             ].staticArray);
1586         *flashes_emitter.getComponent!CParticleEmitter() = CParticleEmitter(vec2(0,0), vec2(800,1600));
1587     }
1588 
1589     void onDestroy()
1590     {
1591         gEntityManager.freeTemplate(flashes_emitter);
1592     }
1593 
1594     void handleEvent(Entity* entity, EDestroyedChild event)
1595     {
1596         CParts* parts = entity.getComponent!CParts;
1597         parts.count--;
1598 
1599         CInit* init = entity.getComponent!CInit;
1600         if(init.type == CInit.Type.boss)
1601         {
1602             CChildren* children = entity.getComponent!CChildren;
1603             foreach(ref EntityID child; children.childern)
1604             {
1605                 if(child == event.id)
1606                 {
1607                     Entity* child_entity = gEntityManager.getEntity(child);
1608                     if(child_entity)
1609                     {
1610                         CLocation location;
1611                         CTargetParent* target_parent = child_entity.getComponent!CTargetParent;
1612                         CDepth* target_depth = child_entity.getComponent!CDepth;
1613                         CLocation* target_location = child_entity.getComponent!CLocation;
1614                         //CVelocity* velocity = child_entity.getComponent!CTargetParent;
1615 
1616                         if(target_location)location = *target_location;
1617 
1618                         *flashes_emitter.getComponent!CTargetParent() = *target_parent;
1619                         if(target_depth)child = gEntityManager.addEntity(flashes_emitter, [target_depth.ref_, location.ref_].staticArray).id;
1620                         else child = gEntityManager.addEntity(flashes_emitter, [location.ref_].staticArray).id;
1621                     }
1622                     break;
1623                 }
1624             }
1625         }
1626 
1627         if(parts.count == 0)
1628         {
1629             if(init.type == CInit.Type.boss)
1630             {
1631                 gEntityManager.addComponents(entity.id, CHitPoints(100), CShootGrid());
1632             }
1633         }
1634     }
1635 }
1636 
1637 struct ClampPositionSystem
1638 {
1639     mixin ECS.System!32;
1640     mixin ECS.ExcludedComponents!(CSideMove);
1641 
1642     struct EntitiesData
1643     {
1644         uint length;
1645         const (Entity)[] entities;
1646         //components are treated as required by default
1647         CLocation[] locations;
1648 
1649         @optional @readonly CColliderScale[] collider_scale;
1650         @optional @readonly CScale[] scale;
1651         @optional const (CBullet)[] laser;
1652         @optional const (CUpgrade)[] upgrade;
1653         //@optional CVelocity[] velocity;
1654         //@optional const (CSideMove)[] side_move;
1655     }
1656 
1657     //ChangeDirectionSystem change_direction_system; 
1658 
1659     void onUpdate(EntitiesData data)
1660     {
1661         if(data.laser || data.upgrade)
1662         {
1663             foreach(i;0..data.length)
1664             {
1665                 if(data.locations[i].x < 0 || data.locations[i].x > space_invaders.map_size.x || 
1666                    data.locations[i].y < 0 || data.locations[i].y > space_invaders.map_size.y)gEntityManager.removeEntity(data.entities[i].id);
1667             }
1668         }
1669         /*else if(data.side_move)
1670         {
1671             foreach(i;0..data.length)
1672             {
1673                 if(data.locations[i].x < 0)
1674                 {
1675                     //data.locations[i].x = 0;
1676                     //gEntityManager.sendEvent(data.entities[i].id,EChangeDirection(Direction.right));
1677                     if(data.side_move[i].group == -1)
1678                     {
1679                         if(data.velocity[i].x < 0)data.velocity[i].x = -data.velocity[i].x;
1680                     }
1681                     else
1682                     {
1683                         change_direction_system.groups_directions[data.side_move[i].group] = Direction.left;
1684                     }
1685                 }
1686                 else if(data.locations[i].x > space_invaders.map_size.x)
1687                 {
1688                     //data.locations[i].x = space_invaders.map_size.x;
1689                     //gEntityManager.sendEvent(data.entities[i].id,EChangeDirection(Direction.left));
1690                     if(data.side_move[i].group == -1)
1691                     {
1692                         if(data.velocity[i].x > 0)data.velocity[i].x = -data.velocity[i].x;
1693                     }
1694                     else
1695                     {
1696                         change_direction_system.groups_directions[data.side_move[i].group] = Direction.right;
1697                     }
1698                 }
1699                 if(data.locations[i].y < 0) data.locations[i].y = 0;
1700                 else if(data.locations[i].y > space_invaders.map_size.y)data.locations[i].y = space_invaders.map_size.y;
1701             }
1702         }*/
1703         else if(data.collider_scale)
1704         {
1705             foreach(i;0..data.length)
1706             {
1707                 vec2 hscale = data.collider_scale[i] * 0.5;
1708                 if(data.locations[i].x - hscale.x < 0)data.locations[i].x = hscale.x;
1709                 else if(data.locations[i].x + hscale.x > space_invaders.map_size.x)data.locations[i].x = space_invaders.map_size.x - hscale.x;
1710                 if(data.locations[i].y - hscale.y < 0)data.locations[i].y = hscale.y;
1711                 else if(data.locations[i].y + hscale.y > space_invaders.map_size.y)data.locations[i].y = space_invaders.map_size.y - hscale.y;
1712             }
1713         }
1714         else if(data.scale)
1715         {
1716             foreach(i;0..data.length)
1717             {
1718                 vec2 hscale = data.scale[i] * 0.5;
1719                 if(data.locations[i].x - hscale.x < 0)data.locations[i].x = hscale.x;
1720                 else if(data.locations[i].x + hscale.x > space_invaders.map_size.x)data.locations[i].x = space_invaders.map_size.x - hscale.x;
1721                 if(data.locations[i].y - hscale.y < 0)data.locations[i].y = hscale.y;
1722                 else if(data.locations[i].y + hscale.y > space_invaders.map_size.y)data.locations[i].y = space_invaders.map_size.y - hscale.y;
1723             }
1724         }
1725         else
1726         {
1727             foreach(i;0..data.length)
1728             {
1729                 if(data.locations[i].x < 0)data.locations[i].x = 0;
1730                 else if(data.locations[i].x > space_invaders.map_size.x)data.locations[i].x = space_invaders.map_size.x;
1731                 if(data.locations[i].y < 0)data.locations[i].y = 0;
1732                 else if(data.locations[i].y > space_invaders.map_size.y)data.locations[i].y = space_invaders.map_size.y;
1733             }
1734         }
1735     }
1736 }
1737 
1738 // struct MovementSystem
1739 // {
1740 //     mixin ECS.System!32;
1741 
1742 //     struct EntitiesData
1743 //     {
1744 //         uint length;
1745 //         //read only components can be marked with @readonly attribute or with const expression instead 
1746 //         const (CVelocity)[] velocity;
1747 //         //components are treated as required by default
1748 //         CLocation[] locations;
1749 //         //@optional const (CBullet)[] laser;
1750 //         const (Entity)[] entities;
1751 
1752 //         //@optional CSideMove[] side_move;
1753 //     }
1754 
1755 //     void onUpdate(EntitiesData data)
1756 //     {
1757 //         foreach(i;0..data.length)
1758 //         {
1759 //             data.locations[i].x += data.velocity[i].x * launcher.delta_time * 0.5;
1760 //             data.locations[i].y += data.velocity[i].y * launcher.delta_time * 0.5;
1761 //         }
1762 //     }
1763 // }
1764 
1765 struct AnimationSystem
1766 {
1767     mixin ECS.System!32;
1768 
1769     struct EntitiesData
1770     {
1771         uint length;
1772         CAnimation[] animation;
1773         //CTexture[] texture;
1774         CTexCoords[] texcoords;
1775         @optional @readonly CAnimationLooped[] looped;
1776     }
1777 
1778     void onUpdate(EntitiesData data)
1779     {
1780         float dt = launcher.deltaTime * 0.01;
1781         if(data.looped)
1782         {
1783             foreach(i;0..data.length)
1784             {
1785                 data.animation[i].time += dt * data.animation[i].speed;
1786                 while(cast(uint)data.animation[i].time >= data.animation[i].frames.length)data.animation[i].time -= cast(float)data.animation[i].frames.length;
1787                 //if(cast(uint)(data.animation[i].time) >= data.animation[i].frames.length)assert(0);
1788                 assert(cast(uint)(data.animation[i].time) < data.animation[i].frames.length);
1789                 uint index = cast(uint)(data.animation[i].time);
1790                 if(index < data.animation[i].frames.length)data.texcoords[i].value = data.animation[i].frames[index];
1791             }
1792         }
1793         else 
1794         {
1795             foreach(i;0..data.length)
1796             {
1797                 data.animation[i].time += dt * data.animation[i].speed;
1798                 if(cast(uint)data.animation[i].time >= data.animation[i].frames.length)data.animation[i].time = data.animation[i].frames.length - 0.9;
1799                 uint index = cast(uint)(data.animation[i].time);
1800                 if(index < data.animation[i].frames.length)data.texcoords[i].value = data.animation[i].frames[index];
1801             }
1802         }
1803 
1804     }
1805 }
1806 
1807 struct ParticleSystem
1808 {
1809     mixin ECS.System!32;
1810 
1811     struct EntitiesData
1812     {
1813         uint length;
1814         @readonly Entity[] entitiy;
1815         CParticle[] particle;
1816     }
1817 
1818     void onUpdate(EntitiesData data)
1819     {
1820         foreach(i;0..data.length)
1821         {
1822             data.particle[i].life -= launcher.deltaTime;
1823             if(data.particle[i].life < 0)gEntityManager.removeEntity(data.entitiy[i].id);
1824         }
1825     }
1826 }
1827 
1828 struct RotateToTargetSystem
1829 {
1830     mixin ECS.System!32;
1831 
1832     struct EntitiesData
1833     {
1834         int length;
1835         @readonly CTarget[] target;
1836         @readonly CLocation[] location;
1837         CRotation[] rotation;
1838     }
1839 
1840     void onUpdate(EntitiesData data)
1841     {
1842         foreach(i;0..data.length)
1843         {
1844             Entity* target = gEntityManager.getEntity(data.target[i].target);
1845             if(target)
1846             {
1847                 CLocation* target_loc = target.getComponent!CLocation;
1848                 if(target_loc)
1849                 {
1850                     vec2 rel_pos = target_loc.value - data.location[i];
1851                     float length = sqrtf(rel_pos.x*rel_pos.x + rel_pos.y*rel_pos.y);
1852                     if(rel_pos.x > 0)data.rotation[i] = acosf(rel_pos.y/length);
1853                     else data.rotation[i] = 2 * PI - acosf(rel_pos.y/length);
1854 
1855                 }
1856             }
1857             //CLocation* target_loc = 
1858             //vec2 rel_pos = d
1859             //data.rotation = 0;
1860         }
1861     }
1862 }
1863 
1864 struct ShipTargetSystem
1865 {
1866     mixin ECS.System!32;
1867 
1868     struct EntitiesData
1869     {
1870         int length;
1871         @readonly CTargetPlayerShip[] target_player;
1872         CTarget[] target;
1873     }
1874 
1875     EntityID player_ship;
1876 
1877     void iterateShips(CShipIterator.EntitiesData data)
1878     {
1879         player_ship = data.entity[0].id;
1880     }
1881 
1882     void onAddEntity(EntitiesData data)
1883     {
1884         foreach(i;0..data.length)
1885         {
1886             data.target[i].target = player_ship;
1887         }
1888     }
1889 
1890     bool onBegin()
1891     {
1892         Entity* ship = gEntityManager.getEntity(player_ship);
1893         if(ship is null)
1894         {
1895             gEntityManager.callEntitiesFunction!CShipIterator(&iterateShips);
1896             ship = gEntityManager.getEntity(player_ship);
1897             if(ship is null)return false;
1898             return true;
1899         }
1900         return false;
1901     }
1902 
1903     void onUpdate(EntitiesData data)
1904     {
1905         foreach(i;0..data.length)
1906         {
1907             data.target[i].target = player_ship;
1908         }
1909     }
1910 }
1911 
1912 struct CShipIterator
1913 {
1914     mixin ECS.System!1;
1915 
1916     struct EntitiesData
1917     {
1918         @readonly Entity[] entity;
1919         @readonly CShip[] ship;
1920     }
1921 
1922     bool onBegin()
1923     {
1924         return false;
1925     }
1926 
1927     void onUpdate(EntitiesData data)
1928     {
1929         
1930     }
1931 }
1932 
1933 /*struct SpawnUponDeathSystem
1934 {
1935     mixin ECS.System;
1936 
1937     struct EntitiesData
1938     {
1939         @readonly CSpawnUponDeath[] spawn;
1940         @optional CTargetParent[] parent;
1941     }
1942 
1943     EntityTemplate* flashes_emitter;
1944 
1945     void onCreate()
1946     {
1947         flashes_emitter = gEntityManager.allocateTemplate(
1948             [
1949                 becsID!CVelocity, becsID!CLocation, becsID!CParticleEmitter,
1950                 becsID!CParticleEmitterTime, becsID!CTargetParent
1951             ].staticArray);
1952         *flashes_emitter.getComponent!CParticleEmitter() = CParticleEmitter(vec2(0,0), vec2(400,400), 0);
1953     }
1954 
1955     void onDestroy()
1956     {
1957         gEntityManager.freeTemplate(flashes_emitter);
1958     }
1959 
1960     void onRemoveEntity(EntitiesData data)
1961     {
1962         //CSpawnUponDeath[] spawn = 
1963         switch(data.spawn[0].type)
1964         {
1965             case CSpawnUponDeath.Type.flashes_emitter:
1966                 if(data.parent)
1967                 {
1968                     /*Entity* parent_entity = gEntityManager.getEntity(data.parent[0].parent);
1969                     CChildren* children = entity.getComponent!CChildren;
1970                     foreach(ref EntityID child; children.childern)
1971                     {
1972                         if(child == event.id)
1973                         {
1974                             Entity* child_entity = gEntityManager.getEntity(child);
1975                             if(child_entity)
1976                             {
1977                                 *flashes_emitter.getComponent!CTargetParent = data.parent[0];
1978                                 gEntityManager.addEntity(flashes_emitter);
1979                                 //child = gEntityManager.addEntity(flashes_emitter);
1980                             }
1981                             break;
1982                         }
1983                     }
1984                 }
1985                 break;
1986             default:break;
1987         }
1988     }
1989 
1990     //void handleEvent(Entity* entity, )
1991 }//*/
1992 
1993 /*#######################################################################################################################
1994 ------------------------------------------------ Functions ------------------------------------------------------------------
1995 #######################################################################################################################*/
1996 
1997 __gshared SpaceInvaders* space_invaders;
1998 
1999 void spaceInvadersRegister()
2000 {
2001     
2002     space_invaders = Mallocator.make!SpaceInvaders;
2003 
2004     space_invaders.texture.create();
2005     space_invaders.texture.load("assets/textures/atlas.png");
2006 
2007     gEntityManager.beginRegister();
2008 
2009     gEntityManager.registerDependency(ShootGridDependency);
2010 
2011     registerRenderingModule(gEntityManager);
2012 
2013     gEntityManager.registerComponent!CLocation;
2014     gEntityManager.registerComponent!CTexCoords;
2015     //gEntityManager.registerComponent!CTexture;
2016     gEntityManager.registerComponent!CInput;
2017     gEntityManager.registerComponent!CShip;
2018     gEntityManager.registerComponent!CEnemy;
2019     gEntityManager.registerComponent!CScale;
2020     gEntityManager.registerComponent!CShootDirection;
2021     gEntityManager.registerComponent!CAutoShoot;
2022     gEntityManager.registerComponent!CWeapon;
2023     gEntityManager.registerComponent!CVelocity;
2024     gEntityManager.registerComponent!CBullet;
2025     gEntityManager.registerComponent!CSideMove;
2026     gEntityManager.registerComponent!CDepth;
2027     gEntityManager.registerComponent!CShootGrid;
2028     gEntityManager.registerComponent!CGuild;
2029     gEntityManager.registerComponent!CHitPoints;
2030     gEntityManager.registerComponent!CHitMark;
2031     gEntityManager.registerComponent!CUpgrade;
2032     gEntityManager.registerComponent!CParticle;
2033     gEntityManager.registerComponent!CMaxHitPoints;
2034     gEntityManager.registerComponent!CAnimation;
2035     gEntityManager.registerComponent!CRotation;
2036     gEntityManager.registerComponent!CAnimationLooped;
2037     gEntityManager.registerComponent!CDamping;
2038     gEntityManager.registerComponent!CTargetParent;
2039     gEntityManager.registerComponent!CTarget;
2040     gEntityManager.registerComponent!CTargetPlayerShip;
2041     gEntityManager.registerComponent!CChildren;
2042     gEntityManager.registerComponent!CWeaponLocation;
2043     gEntityManager.registerComponent!CVelocityFactor;
2044     gEntityManager.registerComponent!CInit;
2045     gEntityManager.registerComponent!CBoss;
2046     gEntityManager.registerComponent!CParts;
2047     gEntityManager.registerComponent!CColliderScale;
2048     gEntityManager.registerComponent!CParticleEmitter;
2049     gEntityManager.registerComponent!CParticleEmitterTime;
2050     gEntityManager.registerComponent!CSpawnUponDeath;
2051     gEntityManager.registerComponent!CShootWaveUponDeath;
2052     gEntityManager.registerComponent!CShootGridMask;
2053 
2054     gEntityManager.registerEvent!EChangeDirection;
2055     gEntityManager.registerEvent!EDamage;
2056     gEntityManager.registerEvent!EUpgrade;
2057     gEntityManager.registerEvent!EDeath;
2058     gEntityManager.registerEvent!EDestroyedChild;
2059     gEntityManager.registerEvent!EBulletHit;
2060 
2061     //gEntityManager.registerSystem!MoveSystem(0);
2062     gEntityManager.registerSystem!DrawSystem(100);
2063     gEntityManager.registerSystem!InputMovementSystem(-100);
2064     //gEntityManager.registerSystem!MovementSystem(-99);
2065     gEntityManager.registerSystem!MoveSystem(-99);
2066     gEntityManager.registerSystem!ClampPositionSystem(-90);
2067     gEntityManager.registerSystem!ShootingSystem(0);
2068     gEntityManager.registerSystem!ChangeDirectionSystem(0);
2069     gEntityManager.registerSystem!BulletsCollisionSystem(-70);
2070     gEntityManager.registerSystem!ShootGridManager(-80);
2071     gEntityManager.registerSystem!ShootGridCleaner(-101);
2072     gEntityManager.registerSystem!HitPointsSystem(0);
2073     gEntityManager.registerSystem!HitMarkingSystem(-100);
2074     gEntityManager.registerSystem!UpgradeCollisionSystem(-70);
2075     gEntityManager.registerSystem!UpgradeSystem(-100);
2076     gEntityManager.registerSystem!ParticleSystem(-100);
2077     gEntityManager.registerSystem!AnimationSystem(-100);
2078     gEntityManager.registerSystem!DampingSystem(-101);
2079     gEntityManager.registerSystem!MoveToParentTargetSystem(-98);
2080     gEntityManager.registerSystem!ParentOwnerSystem(-101);
2081     gEntityManager.registerSystem!ShipWeaponSystem(-100);
2082     gEntityManager.registerSystem!ParticleEmittingSystem(-95);
2083     gEntityManager.registerSystem!RotateToTargetSystem(-100);
2084     gEntityManager.registerSystem!ShipTargetSystem(-110);
2085     gEntityManager.registerSystem!CShipIterator(-100);
2086     gEntityManager.registerSystem!PartsDestroySystem(-80);
2087     gEntityManager.registerSystem!ChildDestroySystem(-110);
2088     gEntityManager.registerSystem!ShootWaveSystem(-100);
2089     //gEntityManager.registerSystem!SpawnUponDeathSystem(-110);
2090     gEntityManager.registerSystem!CollisionMaskSystem(-100);
2091     
2092     gEntityManager.endRegister();
2093 }
2094 
2095 void spaceInvadersStart()
2096 {
2097 
2098     // space_invaders.shoot_grid = Mallocator.make!ShootGrid;
2099     // space_invaders.shoot_grid.create(ivec2(80,60), vec2(5,5));
2100     
2101     space_invaders.shoot_grid = gEntityManager.getSystem!ShootGridManager().grid;
2102 
2103     DrawSystem* draw_system = gEntityManager.getSystem!DrawSystem;
2104     draw_system.default_data.color = 0x80808080;
2105     draw_system.default_data.texture = space_invaders.texture;
2106 
2107     launcher.gui_manager.addComponent(CLocation(),"Location");
2108     launcher.gui_manager.addComponent(CRotation(),"Rotation");
2109     launcher.gui_manager.addComponent(CTexCoords(),"TexCoords");
2110     launcher.gui_manager.addComponent(CInput(),"Input");
2111     launcher.gui_manager.addComponent(CShip(),"Ship");
2112     launcher.gui_manager.addComponent(CEnemy(),"Enemy");
2113     launcher.gui_manager.addComponent(CShootDirection(),"Shoot Direction");
2114     launcher.gui_manager.addComponent(CAutoShoot(),"Auto Shoot");
2115     launcher.gui_manager.addComponent(CWeapon(0, CWeapon.Type.laser),"Weapon (laser)");
2116     launcher.gui_manager.addComponent(CVelocity(vec2(0,0)),"Velocity (0,0)");
2117     launcher.gui_manager.addComponent(CBullet(),"Bullet (dmg1)");
2118     launcher.gui_manager.addComponent(CSideMove(),"Side Move");
2119     launcher.gui_manager.addComponent(CSideMove(0),"Side Move (g1)");
2120     launcher.gui_manager.addComponent(CSideMove(1),"Side Move (g2)");
2121     launcher.gui_manager.addComponent(CDepth(),"Depth");
2122     launcher.gui_manager.addComponent(CShootGrid(),"Shoot Grid");
2123     launcher.gui_manager.addComponent(CGuild(),"Guild (Player)");
2124     launcher.gui_manager.addComponent(CGuild(1),"Guild (Enemy)");
2125     launcher.gui_manager.addComponent(CHitPoints(10),"Hit Points (10)");
2126     launcher.gui_manager.addComponent(CHitMark(),"Hit Mark");
2127     launcher.gui_manager.addComponent(CUpgrade(CUpgrade.Upgrade.laser),"Upgrade (laser)");
2128     launcher.gui_manager.addComponent(CParticle(1000),"Particle (1s)");
2129     launcher.gui_manager.addComponent(CMaxHitPoints(),"Max Hit Points");
2130     launcher.gui_manager.addComponent(CAnimation(),"Animation");
2131     launcher.gui_manager.addComponent(CDamping(0),"Damping (0)");
2132     launcher.gui_manager.addComponent(CDamping(4),"Damping (4)");
2133     launcher.gui_manager.addComponent(CDamping(8),"Damping (8)");
2134     launcher.gui_manager.addComponent(CAnimationLooped(),"Animation loop flag");
2135     launcher.gui_manager.addComponent(CTargetParent(),"Target Parent");
2136     launcher.gui_manager.addComponent(CTargetPlayerShip(),"Target Player Ship");
2137     launcher.gui_manager.addComponent(CTarget(),"Target");
2138     launcher.gui_manager.addComponent(CChildren(),"Children");
2139     launcher.gui_manager.addComponent(CVelocityFactor(),"Velocity Factor");
2140     launcher.gui_manager.addComponent(CWeaponLocation(vec2(0,16)),"Weapon Location (0,16)");
2141     launcher.gui_manager.addComponent(CInit(CInit.Type.space_ship),"Init (Ship)");
2142     launcher.gui_manager.addComponent(CInit(CInit.Type.boss),"Init (Boss)");
2143     launcher.gui_manager.addComponent(CInit(CInit.Type.tower),"Init (Tower)");
2144     launcher.gui_manager.addComponent(CBoss(),"Boss");
2145     launcher.gui_manager.addComponent(CParts(),"Parts");
2146     launcher.gui_manager.addComponent(CColliderScale(),"Collider Scale");
2147     launcher.gui_manager.addComponent(CParticleEmitter(),"Particle Emitter");
2148     launcher.gui_manager.addComponent(CParticleEmitterTime(),"Particle Emitter Time");
2149     launcher.gui_manager.addComponent(CSpawnUponDeath(),"Spawn Upon Death");
2150     launcher.gui_manager.addComponent(CShootWaveUponDeath(CWeapon.Type.canon),"Wave Upon Death");
2151     launcher.gui_manager.addComponent(CShootGridMask(),"Shoot grid mask");
2152 
2153     launcher.gui_manager.addSystem(becsID!DrawSystem,"Draw System");
2154     launcher.gui_manager.addSystem(becsID!InputMovementSystem,"Input Movement");
2155     launcher.gui_manager.addSystem(becsID!ShootingSystem,"Shooting System");
2156     //launcher.gui_manager.addSystem(becsID!MovementSystem,"Movement System");
2157     launcher.gui_manager.addSystem(becsID!MoveSystem,"Move System");
2158     launcher.gui_manager.addSystem(becsID!ClampPositionSystem,"Clamp Position System");
2159     launcher.gui_manager.addSystem(becsID!ChangeDirectionSystem,"Change Direction System");
2160     launcher.gui_manager.addSystem(becsID!BulletsCollisionSystem,"Bullets Collision System");
2161     launcher.gui_manager.addSystem(becsID!ShootGridManager,"Shoot Grid Manager");
2162     launcher.gui_manager.addSystem(becsID!ShootGridCleaner,"Shoot Grid Cleaner");
2163     launcher.gui_manager.addSystem(becsID!HitPointsSystem,"Hit Points System");
2164     launcher.gui_manager.addSystem(becsID!HitMarkingSystem,"Hit Marking System");
2165     launcher.gui_manager.addSystem(becsID!UpgradeCollisionSystem,"Upgrade Collision System");
2166     launcher.gui_manager.addSystem(becsID!UpgradeSystem,"Upgrade System");
2167     launcher.gui_manager.addSystem(becsID!ParticleSystem,"Particle System");
2168     launcher.gui_manager.addSystem(becsID!AnimationSystem,"Animation System");
2169     launcher.gui_manager.addSystem(becsID!DampingSystem,"Damping System");
2170     launcher.gui_manager.addSystem(becsID!MoveToParentTargetSystem,"Move To Target System");
2171     launcher.gui_manager.addSystem(becsID!ParentOwnerSystem,"Parent Owner System");
2172     launcher.gui_manager.addSystem(becsID!ShipWeaponSystem,"Ship Weapon System");
2173     launcher.gui_manager.addSystem(becsID!ParticleEmittingSystem,"Particle Emitting System");
2174     launcher.gui_manager.addSystem(becsID!RotateToTargetSystem,"Rotate To Target System");
2175     launcher.gui_manager.addSystem(becsID!ShipTargetSystem,"Ship Target System");
2176     launcher.gui_manager.addSystem(becsID!PartsDestroySystem,"Parts Destroy System");
2177     launcher.gui_manager.addSystem(becsID!ChildDestroySystem,"Child Destroy System");
2178     launcher.gui_manager.addSystem(becsID!ShootWaveSystem,"Shoot Wave System");
2179     //launcher.gui_manager.addSystem(becsID!SpawnUponDeathSystem,"Child Destroy System");
2180     //launcher.gui_manager.addSystem(becsID!CollisionMaskSystem,"Collision Mask");
2181 
2182     //gEntityManager.getSystem(becsID!CleanSystem).disable();
2183     {
2184         space_invaders.ship_tmpl = gEntityManager.allocateTemplate(
2185                 [becsID!CVelocity, becsID!CColor, becsID!CHitMark, becsID!CHitPoints, 
2186                 becsID!CLocation, becsID!CTexCoords, becsID!CInput, 
2187                 becsID!CShip, becsID!CScale, becsID!CColliderScale,
2188                 becsID!CShootDirection, becsID!CShootGrid, becsID!CGuild,
2189                 becsID!CDamping, becsID!CChildren, becsID!CInit,
2190                 becsID!CShootGridMask, becsID!CVelocityFactor].staticArray
2191                 );
2192         space_invaders.ship_tmpl.getComponent!CTexCoords().value = vec4(0,80,48,32)*px;
2193         space_invaders.ship_tmpl.getComponent!CScale().value = vec2(48,32);
2194         space_invaders.ship_tmpl.getComponent!CHitPoints().value = 1000;
2195         space_invaders.ship_tmpl.getComponent!CDamping().value = 14;
2196         space_invaders.ship_tmpl.getComponent!CInit().type = CInit.Type.space_ship;
2197         space_invaders.ship_tmpl.getComponent!CColliderScale().value = vec2(26,24);
2198         space_invaders.ship_tmpl.getComponent!CVelocityFactor().value = vec2(0.5,0.5);
2199 
2200         gEntityManager.addEntity(space_invaders.ship_tmpl,[CLocation(vec2(64,64)).ref_].staticArray);
2201     }
2202 
2203     {
2204         ushort[6] components = [becsID!CLocation, becsID!CTexCoords, becsID!CVelocity, becsID!CScale, becsID!CBullet, becsID!CGuild];
2205         space_invaders.laser_tmpl = gEntityManager.allocateTemplate(components);
2206 
2207         space_invaders.laser_tmpl.getComponent!CTexCoords().value = vec4(0,24,2,8)*px;
2208         space_invaders.laser_tmpl.getComponent!CScale().value = vec2(2,8);
2209         space_invaders.laser_tmpl.getComponent!CVelocity().value = vec2(0,0.5);
2210     }
2211 
2212     EntityTemplate* enemy_tmpl;
2213     EntityTemplate* grouped_tmpl;
2214     EntityTemplate* tower_tmpl;
2215     EntityTemplate* boss_tmpl;
2216     //EntityTemplate* tower_weapon_tmpl;
2217     EntityID enemy_id;
2218     EntityID grouped_id;
2219 
2220     {
2221         boss_tmpl = gEntityManager.allocateTemplate(
2222             [becsID!CColor, becsID!CHitMark, becsID!CParts, becsID!CLocation, 
2223             becsID!CTexCoords, becsID!CScale, becsID!CEnemy, 
2224             becsID!CBoss, becsID!CGuild, becsID!CInit,
2225             becsID!CChildren, becsID!CSideMove, becsID!CVelocity,
2226             becsID!CDepth].staticArray
2227         );
2228 
2229         //CTexture* tex_comp = boss_tmpl.getComponent!CTexture;
2230         //tex_comp.tex = space_invaders.texture;//ship_tex;
2231         //tex_comp.coords = vec4(128*px,0*px,96*px,48*px);
2232         //CLocation* loc_comp = boss_tmpl.getComponent!CLocation;
2233         //loc_comp.value = vec2(64,space_invaders.map_size.y - 16);
2234         boss_tmpl.getComponent!CTexCoords().value =  vec4(128,0,96,48)*px;
2235         boss_tmpl.getComponent!CGuild().guild = 1;
2236         boss_tmpl.getComponent!CInit().type = CInit.Type.boss;  
2237         boss_tmpl.getComponent!CScale().value = vec2(96,48);  
2238         boss_tmpl.getComponent!CDepth().value = -1;
2239         boss_tmpl.getComponent!CParts().count = 4;
2240         boss_tmpl.getComponent!CVelocity().value =  vec2(0.025,0);
2241     }
2242 
2243     {
2244         tower_tmpl = gEntityManager.allocateTemplate(
2245             [becsID!CColor, becsID!CHitMark, becsID!CHitPoints, becsID!CLocation, 
2246             becsID!CTexCoords, becsID!CScale, becsID!CEnemy, 
2247             becsID!CShootGrid, becsID!CGuild, becsID!CInit,
2248             becsID!CChildren, becsID!CShootGridMask].staticArray
2249         );
2250 
2251         tower_tmpl.getComponent!CTexCoords().value = vec4(96,96,16,16)*px;
2252         tower_tmpl.getComponent!CGuild().guild = 1;
2253         tower_tmpl.getComponent!CInit().type = CInit.Type.tower;  
2254         tower_tmpl.getComponent!CHitPoints().value = 10;
2255     }
2256 
2257     {
2258         space_invaders.enemy_tmpl = gEntityManager.allocateTemplate(
2259             [becsID!CWeaponLocation, becsID!CColor, becsID!CHitMark, becsID!CHitPoints, 
2260             becsID!CVelocity, becsID!CAutoShoot, becsID!CLocation, 
2261             becsID!CTexCoords, becsID!CScale, becsID!CWeapon, 
2262             becsID!CEnemy, becsID!CShootDirection, becsID!CShootGrid, 
2263             becsID!CGuild, becsID!CShootGridMask].staticArray
2264         );
2265 
2266         space_invaders.enemy_tmpl.getComponent!CTexCoords().value = vec4(32,32,16,16)*px;
2267         space_invaders.enemy_tmpl.getComponent!CShootDirection().direction = Direction.down;
2268         space_invaders.enemy_tmpl.getComponent!CVelocity().value = vec2(0.05,0);
2269         space_invaders.enemy_tmpl.getComponent!CGuild().guild = 1;
2270         space_invaders.enemy_tmpl.getComponent!CWeaponLocation().rel_pos = vec2(0,-15);
2271         
2272         Entity* current_entity;
2273 
2274         current_entity = gEntityManager.addEntity(space_invaders.enemy_tmpl,[CLocation(vec2(32,space_invaders.map_size.y - 16)).ref_].staticArray);
2275         gEntityManager.addComponents(current_entity.id,CSideMove(0));
2276         
2277         //loc_comp.value = vec2(128,space_invaders.map_size.y - 16);
2278         current_entity = gEntityManager.addEntity(space_invaders.enemy_tmpl,[CLocation(vec2(128,space_invaders.map_size.y - 16)).ref_].staticArray);
2279         gEntityManager.addComponents(current_entity.id,CSideMove(-1));
2280 
2281         enemy_id = current_entity.id;
2282         //enemy_tmpl = gEntityManager.allocateTemplate(current_entity.id);
2283         
2284         //loc_comp.value = vec2(256,space_invaders.map_size.y - 16);
2285         gEntityManager.addEntity(space_invaders.enemy_tmpl,[CLocation(vec2(256,space_invaders.map_size.y - 16)).ref_].staticArray);
2286 
2287         //loc_comp.value = vec2(0,space_invaders.map_size.y - 16);
2288         current_entity = gEntityManager.addEntity(space_invaders.enemy_tmpl,[CLocation(vec2(0,space_invaders.map_size.y - 16)).ref_].staticArray);
2289         gEntityManager.addComponents(current_entity.id,CSideMove(0));
2290 
2291         grouped_id = current_entity.id;
2292         //grouped_tmpl = gEntityManager.allocateTemplate(current_entity.id);
2293     }
2294     
2295     EntityTemplate* upgrade_tmpl;
2296 
2297     {
2298         upgrade_tmpl = gEntityManager.allocateTemplate([becsID!CVelocity, becsID!CLocation, becsID!CTexCoords, becsID!CScale, becsID!CUpgrade, becsID!CAnimationLooped, becsID!CAnimation].staticArray);
2299         upgrade_tmpl.getComponent!CTexCoords().value = vec4(0,32,16,16)*px;
2300         upgrade_tmpl.getComponent!CVelocity().value = vec2(0,-0.05);
2301         *upgrade_tmpl.getComponent!CAnimation = CAnimation(HitPointsSystem.upgrade_laser_frames, 0, 0.75);
2302     }
2303 
2304     gEntityManager.commit();
2305 
2306     enemy_tmpl = gEntityManager.allocateTemplate(enemy_id);
2307     grouped_tmpl = gEntityManager.allocateTemplate(grouped_id);
2308 
2309     space_invaders.bullet_tmpl[0] = gEntityManager.allocateTemplate(
2310         [becsID!CLocation, becsID!CTexCoords, becsID!CVelocity, 
2311         becsID!CScale, becsID!CBullet, becsID!CGuild].staticArray
2312         );
2313     space_invaders.bullet_tmpl[0].getComponent!CTexCoords().value = vec4(0,24,2,8)*px;
2314     space_invaders.bullet_tmpl[0].getComponent!CScale().value = vec2(2,8);
2315 
2316     space_invaders.bullet_tmpl[1] = gEntityManager.allocateTemplate(space_invaders.bullet_tmpl[0]);
2317     space_invaders.bullet_tmpl[2] = gEntityManager.allocateTemplate(space_invaders.bullet_tmpl[0]);
2318     space_invaders.bullet_tmpl[2].getComponent!CTexCoords().value = vec4(64,32,8,16)*px;
2319     space_invaders.bullet_tmpl[2].getComponent!CScale().value = vec2(8,16);
2320     space_invaders.bullet_tmpl[3] = gEntityManager.allocateTemplate(space_invaders.bullet_tmpl[0]);
2321     space_invaders.bullet_tmpl[3].getComponent!CTexCoords().value = vec4(56,32,2,2)*px;
2322     space_invaders.bullet_tmpl[3].getComponent!CScale().value = vec2(2,2);
2323     // bullet_tmpl[3].getComponent!CTexCoords().value = vec4(48,32,8,8)*px;
2324     // bullet_tmpl[3].getComponent!CScale().value = vec2(8,8);
2325     space_invaders.bullet_tmpl[4] = gEntityManager.allocateTemplate(space_invaders.bullet_tmpl[0]);
2326 
2327     launcher.gui_manager.addTemplate(enemy_tmpl,"Enemy");
2328     launcher.gui_manager.addTemplate(grouped_tmpl,"Grouped enemy");
2329     launcher.gui_manager.addTemplate(gEntityManager.allocateTemplate(space_invaders.ship_tmpl),"Ship");
2330     launcher.gui_manager.addTemplate(gEntityManager.allocateTemplate(space_invaders.laser_tmpl),"Laser");
2331     launcher.gui_manager.addTemplate(upgrade_tmpl,"Upgrade");
2332     launcher.gui_manager.addTemplate(tower_tmpl,"Tower");
2333     launcher.gui_manager.addTemplate(boss_tmpl,"Boss");
2334     launcher.gui_manager.addTemplate(gEntityManager.allocateTemplate(space_invaders.bullet_tmpl[3]),"Cannon bullet");
2335     //launcher.gui_manager.addTemplate(gEntityManager.allocateTemplate(space_invaders.bullet_tmpl[4]),"Laser");
2336     //launcher.gui_manager.addTemplate(gEntityManager.allocateTemplate(space_invaders.bullet_tmpl[5]),"Laser");
2337 }
2338 
2339 void spaceInvadersEnd()
2340 {
2341     /*gEntityManager.getSystem(becsID!DrawSystem).disable();
2342     gEntityManager.getSystem(becsID!InputMovementSystem).disable();
2343     gEntityManager.getSystem(becsID!ShootingSystem).disable();
2344     gEntityManager.getSystem(becsID!MovementSystem).disable();
2345     gEntityManager.getSystem(becsID!ClampPositionSystem).disable();
2346     gEntityManager.getSystem(becsID!ShootGridCleaner).disable();*/
2347 
2348     //gEntityManager.freeTemplate(space_invaders.enemy_tmpl);
2349     Mallocator.dispose(space_invaders);
2350     space_invaders = null;
2351 }
2352 
2353 void spaceInvadersEvent(SDL_Event* event)
2354 {
2355 
2356 }
2357 
2358 bool spaceInvadersLoop()
2359 {
2360     launcher.render_position = (vec2(launcher.window_size.x,launcher.window_size.y)*launcher.scalling - vec2(400,300)) * 0.5;
2361 
2362     /*if(launcher.show_demo_wnd)
2363     {
2364         igSetNextWindowPos(ImVec2(800 - 260, 30), ImGuiCond_Once, ImVec2(0,0));
2365         igSetNextWindowSize(ImVec2(250, 0), ImGuiCond_Once);
2366         if(igBegin("Simple",&launcher.show_demo_wnd,0))
2367         {
2368             if(igCheckbox("Move system",&simple.move_system))
2369             {
2370                 if(simple.move_system)gEntityManager.getSystem(becsID!MoveSystem).enable();
2371                 else gEntityManager.getSystem(becsID!MoveSystem).disable();
2372             }
2373             if(igCheckbox("Draw system",&simple.draw_system))
2374             {
2375                 if(simple.draw_system)gEntityManager.getSystem(becsID!DrawSystem).enable();
2376                 else gEntityManager.getSystem(becsID!DrawSystem).disable();
2377             }
2378             igPushButtonRepeat(true);
2379             igColumns(3,null,0);
2380             if(igButton("Spawn",ImVec2(-1,0)))
2381             {
2382                 spawnEntity();
2383             }
2384             igNextColumn();
2385             if(igButton("+10",ImVec2(-1,0)))
2386             {
2387                 foreach(i;0..10)spawnEntity();
2388             }
2389             igNextColumn();
2390             if(igButton("+100",ImVec2(-1,0)))
2391             {
2392                 foreach(i;0..100)spawnEntity();
2393             }
2394             igPopButtonRepeat();
2395             igColumns(1,null,0);
2396             if(igButton("Clear",ImVec2(-1,0)))
2397             {
2398                 gEntityManager.getSystem(becsID!CleanSystem).enable();
2399                 gEntityManager.begin();
2400                 gEntityManager.update();
2401                 gEntityManager.end();
2402                 gEntityManager.getSystem(becsID!CleanSystem).disable();
2403             }
2404         }
2405         igEnd();
2406     }*/
2407 
2408     /*if(launcher.show_tips)
2409     {
2410         igSetNextWindowPos(ImVec2(800 - 550, 80), ImGuiCond_Once, ImVec2(0,0));
2411         igSetNextWindowSize(ImVec2(300, 0), ImGuiCond_Once);
2412         if(igBegin("Tips",&launcher.show_tips,ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings))
2413         {
2414             igTextWrapped("Use \"space\" to spwan entities.\n\nSystems can be enabled/disabled from \"Simple\" window.");
2415         }
2416         igEnd();
2417     }*/
2418 
2419     gEntityManager.begin();
2420     if(launcher.multithreading)
2421     {
2422         launcher.job_updater.begin();
2423         gEntityManager.updateMT();
2424         launcher.job_updater.call();
2425     }
2426     else
2427     {
2428         gEntityManager.update();
2429     }
2430     gEntityManager.end();
2431 
2432     /*foreach(i;0..1000)//13000)
2433     {
2434         launcher.renderer.draw(simple.texture,vec2(i%100*32,i/100*32),vec2(32,32),vec4(0,0,1,1),0.0);
2435     }*/
2436 
2437     return true;
2438 }
2439 
2440 DemoCallbacks getSpaceInvadersDemo()
2441 {
2442     DemoCallbacks demo;
2443     demo.register = &spaceInvadersRegister;
2444     demo.initialize = &spaceInvadersStart;
2445     demo.deinitialize = &spaceInvadersEnd;
2446     demo.loop = &spaceInvadersLoop;
2447     demo.tips = space_invaders.tips;
2448     return demo;
2449 }