Demo update

-added 'dot' function to vector math
-fixed Circle tool rendering
-fixed some potentiall memory leaks
-added 'collision' module which now separates ShootGrid from SpaceInvaders demo
-separate some systems from demos to 'basic' module to better demos functionality sharing
-slow down snake
-added new graphics
-BrickBreaker demo now works (without blocks breaking and with bugged collision detection)

-some bug fixes
This commit is contained in:
Mergul 2020-07-08 22:09:10 +02:00
parent a0efa4e67d
commit 74179b4fc8
14 changed files with 871 additions and 468 deletions

View file

@ -0,0 +1,232 @@
module game_core.collision;
import bubel.ecs.attributes;
import bubel.ecs.core;
import bubel.ecs.std;
import ecs_utils.math.vector;
import game_core.basic;
void registerCollisionModule(EntityManager* manager)
{
manager.registerDependency(ShootGridDependency);
manager.registerComponent!CShootGrid;
manager.registerComponent!CShootGridMask;
manager.registerComponent!CColliderScale;
manager.registerSystem!ShootGridManager(-80);
manager.registerSystem!ShootGridCleaner(-101);
}
enum ShootGridDependency = "ShootGridDependency";
struct CShootGrid
{
mixin ECS.Component;
}
struct CShootGridMask
{
mixin ECS.Component;
alias value this;
ubyte value;
}
struct CColliderScale
{
mixin ECS.Component;
alias value this;
vec2 value = vec2(16,16);
}
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, ubyte 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, ubyte 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)
{
uint index = i * size.x + j;
if(nodes[index].id != 0)
{
if((masks[index] & mask) == 0)continue;
id = nodes[index];
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
{
}
ShootGrid* grid;
bool onBegin()
{
grid = gEM.getSystem!ShootGridManager().grid;
if(grid != null)return true;
else return false;
}
void onUpdate(EntitiesData data)
{
if(grid)grid.clear();
}
}
struct ShootGridManager
{
mixin ECS.System!128;
mixin ECS.WritableDependencies!(ShootGridDependency);
struct EntitiesData
{
uint length;
//uint thread_id;
const (Entity)[] entity;
@readonly CLocation[] locations;
@readonly CShootGrid[] grid_flag;
//@readonly CGuild[] guild;
@optional @readonly CShootGridMask[] mask;
@optional @readonly CScale[] scale;
@optional @readonly CColliderScale[] collider_scale;
}
ShootGrid* grid;
void onCreate()
{
//grid = space_invaders.shoot_grid;
grid = Mallocator.make!ShootGrid;
grid.create(ivec2(80,60), vec2(5,5));
}
void onDestroy()
{
Mallocator.dispose(grid);
}
// bool onBegin()
// {
// //if(!grid)return false;
// //grid.clear();
// return true;
// }
void onUpdate(EntitiesData data)
{
vec2[] scale;
if(data.collider_scale)scale = cast(vec2[])data.collider_scale;
else if(data.scale)scale = cast(vec2[])data.scale;
else return;
if(data.mask is null)
{
foreach(i; 0..data.length)
{
vec2 half_scale = scale[i] * 0.5;
grid.mark(data.entity[i].id, data.locations[i] - half_scale, data.locations[i] + half_scale, ubyte.max);//cast(ubyte)(1 << data.guild[i].guild));
}
}
else foreach(i; 0..data.length)
{
vec2 half_scale = scale[i] * 0.5;
grid.mark(data.entity[i].id, data.locations[i] - half_scale, data.locations[i] + half_scale, data.mask[i]);//cast(ubyte)(1 << data.guild[i].guild));
}
}
}