-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
591 lines
No EOL
17 KiB
D
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;
|
|
} |