bubel-ecs/demos/source/demos/particles.d
Mergul 74179b4fc8 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
2020-07-08 22:09:10 +02:00

591 lines
No EOL
17 KiB
D

module demos.particles;
import app;
import bindbc.sdl;
import cimgui.cimgui;
import bubel.ecs.attributes;
import bubel.ecs.core;
import bubel.ecs.entity;
import bubel.ecs.manager;
import bubel.ecs.std;
import ecs_utils.gfx.texture;
import ecs_utils.math.vector;
import ecs_utils.utils;
import game_core.basic;
import game_core.rendering;
import gui.attributes;
extern(C):
private enum float px = 1.0/512.0;
/*#######################################################################################################################
------------------------------------------------ Components ------------------------------------------------------------------
#######################################################################################################################*/
/*struct CLocation
{
mixin ECS.Component;
alias location this;
vec2 location;
}
struct CColor
{
mixin ECS.Component;
alias value this;
@GUIColor uint value = uint.max;
}
struct CTexCoords
{
mixin ECS.Component;
vec4 value;
}*/
// struct CVelocity
// {
// mixin ECS.Component;
// alias value this;
// vec2 value = vec2(0);
// }
struct CForceRange
{
mixin ECS.Component;
vec2 range = vec2(20,200);
}
struct CAttractor
{
mixin ECS.Component;
//alias value this;
float strength = 0.2;
}
struct CVortex
{
mixin ECS.Component;
float strength = 0.6;
}
// struct CDamping
// {
// mixin ECS.Component;
// alias power this;
// @GUIRange(0,9) ubyte power = 0;
// }
struct CGravity
{
mixin ECS.Component;
}
struct CParticleLife
{
mixin ECS.Component;
this(float life_in_secs)
{
life = cast(int)(life_in_secs * 1000_000);
}
alias life this;
int life = 1000000;
}
/*#######################################################################################################################
------------------------------------------------ Systems ------------------------------------------------------------------
#######################################################################################################################*/
/*
struct DrawSystem
{
mixin ECS.System!32;
struct EntitiesData
{
uint length;
//uint thread_id;
uint job_id;
//@readonly CTexCoords[] coords;
@readonly CLocation[] locations;
@optional @readonly CColor[] color;
}
void onUpdate(EntitiesData data)
{
if(launcher.renderer.prepared_items >= launcher.renderer.MaxObjects)return;//simple leave loop if max visible objects count was reached
import ecs_utils.gfx.renderer;
Renderer.DrawData draw_data;
draw_data.size = vec2(2,2);
draw_data.coords = vec4(246,64,2,2)*px;
draw_data.color = 0x80808080;
draw_data.material_id = 2;
draw_data.thread_id = data.job_id;
draw_data.texture = particles_demo.texture;
if(!data.color)
{
foreach(i; 0..data.length)
{
draw_data.position = data.locations[i];
launcher.renderer.draw(draw_data);//particles_demo.texture, data.locations[i], vec2(2,2), vec4(246,64,2,2)*px, 0, 0x80808080, 0, 2, 0, data.job_id);
}
}
else
{
foreach(i; 0..data.length)
{
draw_data.position = data.locations[i];
draw_data.color = data.color[i].value;
launcher.renderer.draw(draw_data);//particles_demo.texture, data.locations[i], vec2(2,2), vec4(246,64,2,2)*px, 0, data.color[i].value, 0, 2, 0, data.job_id);
}
}
}
}*/
// struct MoveSystem
// {
// mixin ECS.System!64;
// struct EntitiesData
// {
// uint length;
// CLocation[] locations;
// @readonly CVelocity[] velocity;
// }
// void onUpdate(EntitiesData data)
// {
// foreach(i; 0..data.length)
// {
// data.locations[i] += data.velocity[i] * launcher.delta_time;
// }
// }
// }
struct MouseAttractSystem
{
mixin ECS.System!64;
struct EntitiesData
{
uint length;
@readonly CLocation[] locations;
CVelocity[] velocity;
}
vec2 mouse_pos;
bool onBegin()
{
if(!launcher.getKeyState(SDL_SCANCODE_SPACE))return false;
mouse_pos = launcher.mouse.position;
mouse_pos = vec2(mouse_pos.x, mouse_pos.y) * launcher.scalling - launcher.render_position;
return true;
}
void onUpdate(EntitiesData data)
{
float speed = launcher.delta_time * 0.01;
foreach(i;0..data.length)
{
vec2 rel_pos = mouse_pos - data.locations[i];
float len2 = rel_pos.x * rel_pos.x + rel_pos.y * rel_pos.y;
if(len2 < 0.1)len2 = 0.1;
data.velocity[i] = data.velocity[i] + rel_pos / len2 * speed;
}
}
}
struct AttractSystem
{
mixin ECS.System!64;
struct EntitiesData
{
uint length;
@readonly CLocation[] locations;
CVelocity[] velocity;
}
struct Updater
{
AttractSystem.EntitiesData data;
void onUpdate(AttractorIterator.EntitiesData adata)
{
float speed = launcher.delta_time * 0.00004;
if(adata.vortex)
{
foreach(i;0..data.length)
{
foreach(j;0..adata.length)
{
vec2 rel_pos = data.locations[i] - adata.locations[j];
float len2 = rel_pos.length2();
float inv_len = rsqrt(len2);
if(1 < adata.force_range[j].range.y*inv_len)
{
float dist = (adata.force_range[j].range.y - 0.4)*inv_len - 1;
vec2 vec = rel_pos * inv_len;
vec2 cvec = vec2(-vec.y,vec.x);
float sign = -1;
if(1 < adata.force_range[j].range.x*inv_len)sign = 1;
float str = adata.attractor[j].strength * sign;
float vortex_str = adata.vortex[j].strength;
data.velocity[i] = data.velocity[i] + (rel_pos * str + cvec * vortex_str) * speed * dist;
}
}
}
}
else
{
foreach(i;0..data.length)
{
foreach(j;0..adata.length)
{
vec2 rel_pos = data.locations[i] - adata.locations[j];
float len2 = rel_pos.length2();
float inv_len = rsqrt(len2);
if(1 < adata.force_range[j].range.y*inv_len)
{
float dist = (adata.force_range[j].range.y - 0.4)*inv_len - 1;
vec2 vec = rel_pos;
float sign = -1;
if(1 < adata.force_range[j].range.x*inv_len)sign = 1;
float str = adata.attractor[j].strength * speed * dist * sign;
data.velocity[i] = data.velocity[i] + vec * str;
}
}
}
}
}
}
void onUpdate(EntitiesData data)
{
Updater updater;
updater.data = data;
launcher.manager.callEntitiesFunction!AttractorIterator(&updater.onUpdate);
}
}
struct AttractorIterator
{
mixin ECS.System!1;
struct EntitiesData
{
uint length;
@readonly CLocation[] locations;
@readonly CAttractor[] attractor;
@readonly CForceRange[] force_range;
@optional @readonly CVortex[] vortex;
}
bool onBegin()
{
return false;
}
void onUpdate(EntitiesData data)
{
}
}
struct PlayAreaSystem
{
mixin ECS.System!32;
struct EntitiesData
{
uint length;
Entity[] entity;
@readonly CLocation[] locations;
}
void onUpdate(EntitiesData data)
{
foreach(i; 0..data.length)
{
if(data.locations[i].x > 440)launcher.manager.removeEntity(data.entity[i].id);
else if(data.locations[i].x < -40)launcher.manager.removeEntity(data.entity[i].id);
if(data.locations[i].y > 340)launcher.manager.removeEntity(data.entity[i].id);
else if(data.locations[i].y < -40)launcher.manager.removeEntity(data.entity[i].id);
}
}
}
// struct DampingSystem
// {
// mixin ECS.System!32;
// struct EntitiesData
// {
// uint length;
// const (Entity)[] entity;
// @readonly CDamping[] damping;
// CVelocity[] velocity;
// }
// float[10] damp = 0;
// bool onBegin()
// {
// foreach(i;0..10)
// {
// damp[i] = powf((0.99 - cast(float)i * 0.01),launcher.delta_time*0.1);
// }
// return true;
// }
// void onUpdate(EntitiesData data)
// {
// foreach(i; 0..data.length)
// {
// data.velocity[i] = data.velocity[i] * damp[data.damping[i]];
// }
// }
// }
struct ParticleLifeSystem
{
mixin ECS.System!32;
struct EntitiesData
{
uint length;
const (Entity)[] entity;
CParticleLife[] life;
}
int delta_time;
bool onBegin()
{
delta_time = cast(int)(launcher.delta_time * 1000);
return true;
}
void onUpdate(EntitiesData data)
{
foreach(i; 0..data.length)
{
data.life[i] -= delta_time;
if(data.life[i] < 0)launcher.manager.removeEntity(data.entity[i].id);
}
}
}
struct GravitySystem
{
mixin ECS.System!32;
struct EntitiesData
{
uint length;
const (Entity)[] entity;
@readonly CGravity[] gravity;
CVelocity[] velocity;
}
void onUpdate(EntitiesData data)
{
float delta_time = launcher.delta_time * 0.00_092;
foreach(i; 0..data.length)
{
data.velocity[i].y -= delta_time;
}
}
}
/*#######################################################################################################################
------------------------------------------------ Functions ------------------------------------------------------------------
#######################################################################################################################*/
struct ParticlesDemo
{
__gshared const (char)* tips = "Use \"space\" to spwan entities.\n\nSystems can be enabled/disabled from \"Simple\" window.";
Texture texture;
}
__gshared ParticlesDemo* particles_demo;
void particlesRegister()
{
particles_demo = Mallocator.make!ParticlesDemo;
particles_demo.texture.create();
particles_demo.texture.load("assets/textures/atlas.png");
launcher.manager.beginRegister();
registerRenderingModule(launcher.manager);
launcher.manager.registerComponent!CLocation;
//launcher.manager.registerComponent!CTexCoords;
launcher.manager.registerComponent!CColor;
launcher.manager.registerComponent!CVelocity;
launcher.manager.registerComponent!CScale;
launcher.manager.registerComponent!CTexCoords;
launcher.manager.registerComponent!CTexCoordsIndex;
launcher.manager.registerComponent!CRotation;
launcher.manager.registerComponent!CDepth;
launcher.manager.registerComponent!CAttractor;
launcher.manager.registerComponent!CDamping;
launcher.manager.registerComponent!CGravity;
launcher.manager.registerComponent!CVortex;
launcher.manager.registerComponent!CParticleLife;
launcher.manager.registerComponent!CForceRange;
launcher.manager.registerComponent!CMaterialIndex;
launcher.manager.registerSystem!MoveSystem(0);
launcher.manager.registerSystem!DrawSystem(100);
launcher.manager.registerSystem!PlayAreaSystem(102);
launcher.manager.registerSystem!AttractSystem(-1);
launcher.manager.registerSystem!MouseAttractSystem(1);
launcher.manager.registerSystem!DampingSystem(101);
launcher.manager.registerSystem!ParticleLifeSystem(-10);
launcher.manager.registerSystem!GravitySystem(-2);
launcher.manager.registerSystem!AttractorIterator(-1);
launcher.manager.endRegister();
}
void particlesStart()
{
DrawSystem* draw_system = launcher.manager.getSystem!DrawSystem;
draw_system.default_data.size = vec2(2,2);
draw_system.default_data.coords = vec4(246,64,2,2)*px;
draw_system.default_data.material_id = 2;
draw_system.default_data.texture = particles_demo.texture;
launcher.gui_manager.addSystem(MoveSystem.system_id,"Move System");
launcher.gui_manager.addSystem(DrawSystem.system_id,"Draw System");
launcher.gui_manager.addSystem(PlayAreaSystem.system_id,"Play Area System");
launcher.gui_manager.addSystem(AttractSystem.system_id,"Attract System");
launcher.gui_manager.addSystem(MouseAttractSystem.system_id,"Mouse Attract System");
launcher.gui_manager.addSystem(DampingSystem.system_id,"Damping System");
launcher.gui_manager.addSystem(ParticleLifeSystem.system_id,"Particle Life System");
// launcher.gui_manager.addComponent(CColor(),"Color (white)");
// launcher.gui_manager.addComponent(CColor(0xFF101540),"Color (red)");
// launcher.gui_manager.addComponent(CColor(0xFF251010),"Color (blue)");
// launcher.gui_manager.addComponent(CColor(0xFF102010),"Color (green)");
launcher.gui_manager.addComponent(CColor(0xFF101540),"Color");
launcher.gui_manager.addComponent(CAttractor(0.1),"Attractor");
launcher.gui_manager.addComponent(CForceRange(vec2(5,40)),"ForceRange");
launcher.gui_manager.addComponent(CVelocity(),"Velocity");
launcher.gui_manager.addComponent(CDamping(),"Damping");
launcher.gui_manager.addComponent(CVortex(),"Vortex");
launcher.gui_manager.addComponent(CParticleLife(),"Particle Life");
launcher.gui_manager.addComponent(CGravity(),"Gravity");
EntityTemplate* tmpl;
EntityTemplate* base_tmpl = launcher.manager.allocateTemplate([CTexCoords.component_id, CLocation.component_id, CColor.component_id, CVelocity.component_id, CDamping.component_id, CScale.component_id, CMaterialIndex.component_id].staticArray);
base_tmpl.getComponent!CColor().value = 0xFF251010;
base_tmpl.getComponent!CScale().value = vec2(2);
base_tmpl.getComponent!CTexCoords().value = vec4(246,64,2,2)*px;
base_tmpl.getComponent!CMaterialIndex().value = 2;
launcher.gui_manager.addTemplate(base_tmpl,"Particle");
// tmpl = launcher.manager.allocateTemplate(base_tmpl);
// tmpl.getComponent!CColor().value = 0xFF251010;
// launcher.gui_manager.addTemplate(tmpl,"Particle (blue)");
// tmpl = launcher.manager.allocateTemplate(base_tmpl);
// tmpl.getComponent!CColor().value = 0xFF102010;
// launcher.gui_manager.addTemplate(tmpl,"Particle (green)");
// tmpl = launcher.manager.allocateTemplate(base_tmpl);
// tmpl.getComponent!CColor().value = 0xFF101540;
// launcher.gui_manager.addTemplate(tmpl,"Particle (red)");
// tmpl = launcher.manager.allocateTemplate(tmpl, [CDamping.component_id].staticArray);
// launcher.gui_manager.addTemplate(tmpl,"Particle (damping)");
// tmpl = launcher.manager.allocateTemplate(tmpl);
// tmpl.getComponent!CDamping().power = 4;
// launcher.gui_manager.addTemplate(tmpl,"Particle (damping!)");
tmpl = launcher.manager.allocateTemplate([CAttractor.component_id, CLocation.component_id, CForceRange.component_id, CScale.component_id].staticArray);
tmpl.getComponent!CScale().value = vec2(4);
launcher.gui_manager.addTemplate(tmpl,"Attractor");
tmpl = launcher.manager.allocateTemplate(tmpl, [CVortex.component_id].staticArray);
launcher.gui_manager.addTemplate(tmpl,"Vortex");
// tmpl = launcher.manager.allocateTemplate(tmpl);
// tmpl.getComponent!CVortex().strength = -0.6;
// launcher.gui_manager.addTemplate(tmpl,"Vortex (reversed)");
}
void particlesEnd()
{
particles_demo.texture.destroy();
//launcher.manager.freeTemplate(simple.tmpl);
Mallocator.dispose(particles_demo);
}
void particlesEvent(SDL_Event* event)
{
}
bool particlesLoop()
{
launcher.render_position = (vec2(launcher.window_size.x,launcher.window_size.y)*launcher.scalling - vec2(400,300)) * 0.5;
launcher.manager.begin();
if(launcher.multithreading)
{
launcher.job_updater.begin();
launcher.manager.updateMT();
launcher.job_updater.call();
}
else
{
launcher.manager.update();
}
launcher.manager.end();
return true;
}
DemoCallbacks getParticlesDemo()
{
DemoCallbacks demo;
demo.register = &particlesRegister;
demo.initialize = &particlesStart;
demo.deinitialize = &particlesEnd;
demo.loop = &particlesLoop;
demo.tips = ParticlesDemo.tips;
return demo;
}