Add explosion effect in 2d physics engine

This commit is contained in:
Nikita Lisitsa 2020-11-29 16:49:15 +03:00
parent 7cf2a1d5ca
commit 980d3e856b
3 changed files with 40 additions and 12 deletions

View file

@ -70,7 +70,7 @@ struct physics_2d_app
float const inf = std::numeric_limits<float>::infinity();
material = physics.add_material({1.f, 0.5f, 0.9f});
material = physics.add_material({1.f, 0.5f, 0.5f});
ball_shape = physics.add_shape(phys2d::ball{ball_radius});
ball_group = physics.create_group();
@ -78,12 +78,14 @@ struct physics_2d_app
box_shape = physics.add_shape(phys2d::box{box_width, box_height});
box_group = physics.create_group();
if(false)
for (int x = -4; x <= 4; ++x)
int nx = std::ceil(simulation_box[0].length() / box_width);
int ny = std::ceil(simulation_box[1].length() / box_height);
for (int x = 0; x < nx; ++x)
{
for (int y = 0; y < 3; ++y)
for (int y = 0; y < ny / 3; ++y)
{
geom::point<float, 2> pos{simulation_box[0].center() + x * box_width, simulation_box[1].min + (y + 0.5f) * box_height};
geom::point<float, 2> pos{simulation_box.corner((x + 0.5f) / nx, (y + 0.5f) / ny)};
physics.add_object(box_group, box_shape, material, {pos, 0.f}, {});
}
}
@ -103,9 +105,9 @@ struct physics_2d_app
auto wall_3_shape = physics.add_shape(phys2d::half_space{{0.f, -1.f}, -simulation_box[1].max});
physics.add_object(wall_group, wall_3_shape, wall_material, {}, {});
auto task = util::recursive([this, dx = 0.1f](auto && self) mutable -> void {
// physics.add_object(box_group, box_shape, material, {simulation_box.corner(0.5f, 0.9f) + geom::vector{dx, 0.f}, 0.f}, {});
physics.add_object(ball_group, ball_shape, material, {simulation_box.corner(0.5f, 0.9f) + geom::vector{dx, 0.f}, 0.f}, {});
auto task = util::recursive([this, dx = box_width * 0.4f](auto && self) mutable -> void {
physics.add_object(box_group, box_shape, material, {simulation_box.corner(0.5f, 0.9f) + geom::vector{dx, 0.f}, 0.f}, {});
// physics.add_object(ball_group, ball_shape, material, {simulation_box.corner(0.5f, 0.9f) + geom::vector{dx, 0.f}, 0.f}, {});
// float r = pcg::uniform_distribution<float>{0.05f, 0.5f}(gen);
// auto new_shape = physics.add_shape(phys2d::ball{r});
@ -113,8 +115,8 @@ struct physics_2d_app
// radiuses.push_back(r);
dx *= -1.f;
if (physics.group_size(box_group) < 200)
loop.dispatch_at(std::chrono::system_clock::now() + std::chrono::milliseconds{250}, self);
if (physics.group_size(box_group) < 100)
loop.dispatch_at(std::chrono::system_clock::now() + std::chrono::milliseconds{100}, self);
});
(void)task;
// task();
@ -138,7 +140,7 @@ struct physics_2d_app
if (mouse)
{
physics.add_object(ball_group, ball_shape, material, {*mouse, 0.f}, {});
physics.add_object(ball_group, ball_shape, material, {*mouse, 0.f}, {{0.f, 0.f}, 25.f});
}
}
@ -153,7 +155,7 @@ struct physics_2d_app
if (mouse)
{
physics.add_object(box_group, box_shape, material, {*mouse, 0.f}, {});
physics.explode(*mouse, 10.f, 1.f);
}
}

View file

@ -53,6 +53,10 @@ namespace psemek::phys2d
void set_gravity(geom::vector<float, 2> const & g);
// Effects
void explode(geom::point<float, 2> const & center, float strength, float attenuation);
// Main update
void update(float dt);

View file

@ -337,6 +337,8 @@ namespace psemek::phys2d
std::optional<geom::vector<float, 2>> gravity;
void explode(geom::point<float, 2> const & center, float strength, float attenuation);
void update(float dt);
void apply_gravity(float dt);
@ -347,6 +349,21 @@ namespace psemek::phys2d
float energy();
};
void engine::impl::explode(geom::point<float, 2> const & center, float strength, float attenuation)
{
for (auto & g : groups)
{
for (std::size_t i = 0; i < g.infos.size(); ++i)
{
auto r = g.static_states[i].position - center;
float l = geom::length(r);
auto J = (r / l) * strength / (1.f + l * l * attenuation);
g.dynamic_states[i].velocity += J * g.infos[i].inv_mass;
}
}
}
void engine::impl::update(float dt)
{
apply_gravity(dt);
@ -640,6 +657,11 @@ namespace psemek::phys2d
impl().gravity = g;
}
void engine::explode(geom::point<float, 2> const & center, float strength, float attenuation)
{
impl().explode(center, strength, attenuation);
}
void engine::update(float dt)
{
impl().update(dt);