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 }