From 9580ee9af9fd40b32651488e3882843f306fff7e Mon Sep 17 00:00:00 2001 From: Mergul Date: Tue, 12 May 2020 18:21:25 +0200 Subject: [PATCH] Add bullets collision system to SpaceInvaders demo --- demos/source/demos/space_invaders.d | 252 ++++++++++++++++++++++++++-- 1 file changed, 236 insertions(+), 16 deletions(-) diff --git a/demos/source/demos/space_invaders.d b/demos/source/demos/space_invaders.d index 30891c8..004a3eb 100644 --- a/demos/source/demos/space_invaders.d +++ b/demos/source/demos/space_invaders.d @@ -16,10 +16,14 @@ import ecs_utils.gfx.texture; import ecs_utils.math.vector; import ecs_utils.utils; +import std.array : staticArray; + enum float px = 1.0/512.0; extern(C): +enum ShootGridDependency = "ShootGridDependency"; + /*####################################################################################################################### ------------------------------------------------ Types ------------------------------------------------------------------ #######################################################################################################################*/ @@ -33,11 +37,18 @@ struct SpaceInvaders EntityTemplate* laser_tmpl; Texture texture; + ShootGrid* shoot_grid; + bool move_system = true; bool draw_system = true; const vec2 map_size = vec2(400,300); const float cell_size = 60; + + ~this() @nogc nothrow + { + if(shoot_grid)Mallocator.dispose(shoot_grid); + } } struct SceneGrid @@ -147,7 +158,7 @@ struct CGuild { mixin ECS.Component; - int guild; + byte guild; } struct CLaser @@ -188,6 +199,11 @@ struct CDepth short depth; } +struct CShootGrid +{ + mixin ECS.Component; +} + /*####################################################################################################################### ------------------------------------------------ Events ------------------------------------------------------------------ #######################################################################################################################*/ @@ -208,6 +224,158 @@ struct EChangeDirection ------------------------------------------------ Systems ------------------------------------------------------------------ #######################################################################################################################*/ +struct ShootGrid +{ + + ~this() @nogc nothrow + { + if(nodes)Mallocator.dispose(nodes); + if(masks)Mallocator.dispose(masks); + } + + struct Node + { + alias entity this; + + EntityID entity; + } + + void create(ivec2 nodes_count, vec2 node_size) + { + this.size = nodes_count; + this.node_size = node_size; + inv_node_size = vec2(1.0/node_size.x, 1.0/node_size.y); + nodes = Mallocator.makeArray!Node(nodes_count.x * nodes_count.y); + masks = Mallocator.makeArray!ubyte(nodes.length); + } + + void mark(EntityID id, vec2 beg, vec2 end, byte mask) + { + ivec2 ibeg = cast(ivec2)(beg * inv_node_size); + ivec2 iend = cast(ivec2)((end * inv_node_size) + 0.5); + if(ibeg.x < 0)ibeg.x = 0; + if(ibeg.y < 0)ibeg.y = 0; + if(iend.x > size.x)iend.x = size.x; + if(iend.y > size.y)iend.y = size.y; + foreach(i; ibeg.y .. iend.y) + { + foreach(j; ibeg.x .. iend.x) + { + nodes[i * size.x + j] = id; + masks[i * size.x +j] = mask; + } + } + } + + void clear() + { + size_t size = nodes.length * EntityID.sizeof; + memset(nodes.ptr, 0, size); + memset(masks.ptr, 0, masks.length); + } + + bool test(out EntityID id, vec2 beg, vec2 end) + { + ivec2 ibeg = cast(ivec2)(beg * inv_node_size); + ivec2 iend = cast(ivec2)((end * inv_node_size) + 0.5); + if(ibeg.x < 0)ibeg.x = 0; + if(ibeg.y < 0)ibeg.y = 0; + if(iend.x > size.x)iend.x = size.x; + if(iend.y > size.y)iend.y = size.y; + foreach(i; ibeg.y .. iend.y) + { + foreach(j; ibeg.x .. iend.x) + { + if(nodes[i * size.x + j].id != 0) + { + id = nodes[i * size.x + j]; + return true; + } + } + } + return false; + } + + bool test(out EntityID id, vec2 pos, ubyte mask) + { + ivec2 ipos = cast(ivec2)(pos * inv_node_size - 0.5); + if(ipos.x < 0)ipos.x = 0; + if(ipos.y < 0)ipos.y = 0; + if(ipos.x >= size.x)ipos.x = size.x - 1; + if(ipos.y >= size.y)ipos.y = size.y - 1; + size_t index = ipos.y * size.x + ipos.x; + if((masks[index] & mask) == 0)return false; + if(nodes[index].id != 0) + { + id = nodes[index]; + return true; + } + return false; + } + + vec2 inv_node_size; + ivec2 size; + vec2 node_size; + Node[] nodes; + ubyte[] masks; +} + +struct ShootGridCleaner +{ + mixin ECS.System!1; + + struct EntitiesData + { + + } + + void onUpdate(EntitiesData data) + { + if(space_invaders.shoot_grid)space_invaders.shoot_grid.clear(); + } +} + +struct ShootGridManager +{ + mixin ECS.System!32; + + mixin ECS.WritableDependencies!(ShootGridDependency); + + struct EntitiesData + { + uint length; + uint thread_id; + const (Entity)[] entity; + @readonly CLocation[] locations; + @readonly CScale[] scale; + @readonly CShootGrid[] grid_flag; + @readonly CGuild[] guild; + } + + ShootGrid* grid; + + void onCreate() + { + grid = space_invaders.shoot_grid; + } + + bool onBegin() + { + if(!grid)return false; + //grid.clear(); + return true; + } + + void onUpdate(EntitiesData data) + { + foreach(i; 0..data.length) + { + vec2 half_scale = data.scale[i] * 0.5; + grid.mark(data.entity[i].id, data.locations[i] - half_scale, data.locations[i] + half_scale, cast(ubyte)(1 << data.guild[i].guild)); + } + } +} + struct DrawSystem { mixin ECS.System!32; @@ -260,10 +428,11 @@ struct LaserShootingSystem mixin ECS.System!32; bool shoot = false; - float[10] laser_shoot_times = [2000,1500,1000,700,500,300,100,50,10,1]; + static float[10] laser_shoot_times = [2000,1500,1000,700,500,300,100,50,10,1]; CLocation* laser_location; CVelocity* laser_velocity; + CGuild* laser_guild; struct EntitiesData { @@ -272,6 +441,7 @@ struct LaserShootingSystem @readonly CShootDirection[] shoot_direction; @readonly @optional CAutoShoot[] auto_shoot; @readonly CLocation[] location; + @readonly CGuild[] guild; CLaserWeapon[] laser; } @@ -285,6 +455,7 @@ struct LaserShootingSystem { laser_location = space_invaders.laser_tmpl.getComponent!CLocation; laser_velocity = space_invaders.laser_tmpl.getComponent!CVelocity; + laser_guild = space_invaders.laser_tmpl.getComponent!CGuild; if(launcher.getKeyState(SDL_SCANCODE_SPACE)) { shoot = true; @@ -307,6 +478,7 @@ struct LaserShootingSystem laser.shoot_time -= laser_shoot_times[laser.level - 1]; laser_location.value = data.location[i]; laser_velocity.value = vec2(randomf()*0.5-0.25,data.shoot_direction[i].direction == Direction.up ? 1.0 : -1.0); + laser_guild.guild = data.guild[i].guild; launcher.manager.addEntity(space_invaders.laser_tmpl); } } @@ -324,6 +496,36 @@ struct LaserShootingSystem } } +struct LaserCollisionSystem +{ + mixin ECS.System!32; + + mixin ECS.ReadOnlyDependencies!(ShootGridDependency); + + struct EntitiesData + { + ///variable named "length" contain entites count + uint length; + const (Entity)[] entity; + @readonly CLocation[] location; + @readonly CLaser[] laser; + @readonly CGuild[] guild; + } + + void onUpdate(EntitiesData data) + { + EntityID id; + foreach(i; 0..data.length) + { + if(space_invaders.shoot_grid.test(id, data.location[i], cast(ubyte)(~(1 << data.guild[i].guild)))) + { + launcher.manager.removeEntity(data.entity[i].id); + } + } + } + +} + struct ChangeDirectionSystem { mixin ECS.System!32; @@ -591,6 +793,8 @@ struct MovementSystem } } +import core.stdc.math; + /** *System is responsible for movement of objects with CInput component. *In this example every entity has same speed when using movement system. @@ -620,22 +824,24 @@ struct InputMovementSystem move_vector = vec2(0,0); if(launcher.getKeyState(SDL_SCANCODE_W)) { - move_vector = vec2(0,1); - return true; + move_vector += vec2(0,1); } else if(launcher.getKeyState(SDL_SCANCODE_S)) { - move_vector = vec2(0,-1); - return true; + move_vector += vec2(0,-1); } - else if(launcher.getKeyState(SDL_SCANCODE_A)) + if(launcher.getKeyState(SDL_SCANCODE_A)) { - move_vector = vec2(-1,0); - return true; + move_vector += vec2(-1,0); } else if(launcher.getKeyState(SDL_SCANCODE_D)) { - move_vector = vec2(1,0); + move_vector += vec2(1,0); + } + + if(move_vector.x != 0 ||move_vector.y != 0) + { + move_vector = move_vector / sqrtf(move_vector.x * move_vector.x + move_vector.y * move_vector.y); return true; } //don't call system update because no key pressed @@ -682,6 +888,9 @@ void spaceInvadersStart() space_invaders.texture.create(); space_invaders.texture.load("assets/textures/atlas.png"); + space_invaders.shoot_grid = Mallocator.make!ShootGrid; + space_invaders.shoot_grid.create(ivec2(80,60), vec2(5,5)); + launcher.manager.beginRegister(); launcher.manager.registerComponent!CLocation; @@ -696,16 +905,22 @@ void spaceInvadersStart() launcher.manager.registerComponent!CVelocity; launcher.manager.registerComponent!CLaser; launcher.manager.registerComponent!CSideMove; + launcher.manager.registerComponent!CDepth; + launcher.manager.registerComponent!CShootGrid; + launcher.manager.registerComponent!CGuild; launcher.manager.registerEvent!EChangeDirection; //launcher.manager.registerSystem!MoveSystem(0); launcher.manager.registerSystem!DrawSystem(100); launcher.manager.registerSystem!InputMovementSystem(-100); + launcher.manager.registerSystem!MovementSystem(-99); + launcher.manager.registerSystem!ClampPositionSystem(-90); launcher.manager.registerSystem!LaserShootingSystem(0); - launcher.manager.registerSystem!MovementSystem(0); - launcher.manager.registerSystem!ClampPositionSystem(1); launcher.manager.registerSystem!ChangeDirectionSystem(0); + launcher.manager.registerSystem!LaserCollisionSystem(-70); + launcher.manager.registerSystem!ShootGridManager(-80); + launcher.manager.registerSystem!ShootGridCleaner(-101); launcher.manager.endRegister(); @@ -718,7 +933,7 @@ void spaceInvadersStart() //launcher.manager.getSystem(CleanSystem.system_id).disable(); { - ushort[7] components = [CLocation.component_id, CTexture.component_id, CInput.component_id, CShip.component_id, CScale.component_id, CLaserWeapon.component_id, CShootDirection.component_id]; + ushort[9] components = [CLocation.component_id, CTexture.component_id, CInput.component_id, CShip.component_id, CScale.component_id, CLaserWeapon.component_id, CShootDirection.component_id, CShootGrid.component_id, CGuild.component_id]; space_invaders.ship_tmpl = launcher.manager.allocateTemplate(components); CScale* scale_comp = space_invaders.ship_tmpl.getComponent!CScale; @@ -735,7 +950,7 @@ void spaceInvadersStart() } { - ushort[5] components = [CLocation.component_id, CTexture.component_id, CVelocity.component_id, CScale.component_id, CLaser.component_id]; + ushort[6] components = [CLocation.component_id, CTexture.component_id, CVelocity.component_id, CScale.component_id, CLaser.component_id, CGuild.component_id]; space_invaders.laser_tmpl = launcher.manager.allocateTemplate(components); CTexture* tex_comp = space_invaders.laser_tmpl.getComponent!CTexture; @@ -753,7 +968,7 @@ void spaceInvadersStart() EntityID grouped_id; { - ushort[8] components = [CVelocity.component_id, CAutoShoot.component_id, CLocation.component_id, CTexture.component_id, CScale.component_id, CLaserWeapon.component_id, CEnemy.component_id, CShootDirection.component_id];//, CVelocity.component_id]; + ushort[10] components = [CVelocity.component_id, CAutoShoot.component_id, CLocation.component_id, CTexture.component_id, CScale.component_id, CLaserWeapon.component_id, CEnemy.component_id, CShootDirection.component_id, CShootGrid.component_id, CGuild.component_id]; space_invaders.enemy_tmpl = launcher.manager.allocateTemplate(components); CTexture* tex_comp = space_invaders.enemy_tmpl.getComponent!CTexture; @@ -765,6 +980,7 @@ void spaceInvadersStart() shoot_dir_comp.direction = Direction.down; CVelocity* vel_comp = space_invaders.enemy_tmpl.getComponent!CVelocity; vel_comp.value = vec2(0.1,0); + space_invaders.enemy_tmpl.getComponent!CGuild().guild = 1; Entity* current_entity; @@ -802,7 +1018,6 @@ void spaceInvadersStart() void spaceInvadersEnd() { - launcher.manager.getSystem(DrawSystem.system_id).disable(); launcher.manager.getSystem(InputMovementSystem.system_id).disable(); launcher.manager.getSystem(LaserShootingSystem.system_id).disable(); @@ -827,6 +1042,11 @@ void spaceInvadersTool(vec2 position, Tool tool, int size) position.y += (randomf - 0.5) * size; *location = position; } + CLaserWeapon* laser_weapon = tmpl.getComponent!CLaserWeapon; + if(laser_weapon) + { + laser_weapon.shoot_time = randomf * LaserShootingSystem.laser_shoot_times[laser_weapon.level - 1]; + } launcher.manager.addEntity(tmpl); } break;