From 7fc5aa65adcafab21af55c3da207a31b4b15a3ec Mon Sep 17 00:00:00 2001 From: lowkey Date: Wed, 18 Sep 2019 14:58:26 +0200 Subject: [PATCH] smooth entity movement --- assets/game_assets/assets_particles.map | 5 ++++ assets/game_assets/blueprints/player.json | 7 +++-- .../blueprints/test_particle_emitter.json | 8 +++++ .../particles/test_particle_system.json | 29 ++++++++++++++++++ .../game_assets/particles/test_particles.json | 30 +++++++++++++++++++ src/gameplay/beat_system.cpp | 23 +++++++++++++- src/gameplay/beat_system.hpp | 2 ++ src/gameplay/movement_comp.hpp | 11 ++++++- src/gameplay/movement_system.cpp | 25 ++++++++++++++-- src/gameplay/spring_comp.hpp | 5 ++-- src/level/level_system.cpp | 2 +- src/meta_system.cpp | 3 +- 12 files changed, 138 insertions(+), 12 deletions(-) create mode 100644 assets/game_assets/assets_particles.map create mode 100644 assets/game_assets/blueprints/test_particle_emitter.json create mode 100644 assets/game_assets/particles/test_particle_system.json create mode 100644 assets/game_assets/particles/test_particles.json diff --git a/assets/game_assets/assets_particles.map b/assets/game_assets/assets_particles.map new file mode 100644 index 0000000..112468a --- /dev/null +++ b/assets/game_assets/assets_particles.map @@ -0,0 +1,5 @@ +particle: = particles/*.json + +particle_def:test_particles = particles/test_particles.json +particle_sys:test_particles = particles/test_particle_system.json + diff --git a/assets/game_assets/blueprints/player.json b/assets/game_assets/blueprints/player.json index 5beeaaa..b5e1c16 100644 --- a/assets/game_assets/blueprints/player.json +++ b/assets/game_assets/blueprints/player.json @@ -9,9 +9,10 @@ }, "Movement": { "beats_per_step": 1, - "distance_per_step": 1, - "step_time_percentage": 0.2, - "off_beat_threshold": 0.2 + "distance_per_step": 5, + "step_time_percentage": 0.3, + "off_beat_threshold": 0.2, + "overshoot": 4 }, "Input_controller": {}, "Player": {} diff --git a/assets/game_assets/blueprints/test_particle_emitter.json b/assets/game_assets/blueprints/test_particle_emitter.json new file mode 100644 index 0000000..1f01fc0 --- /dev/null +++ b/assets/game_assets/blueprints/test_particle_emitter.json @@ -0,0 +1,8 @@ +{ + "Transform":{ + "scale": {"x": 1.0, "y": 1.0, "z": 1.0} + }, + "Particle_system": { + "cfg": "particle_sys:test_particles" + } +} diff --git a/assets/game_assets/particles/test_particle_system.json b/assets/game_assets/particles/test_particle_system.json new file mode 100644 index 0000000..26c1377 --- /dev/null +++ b/assets/game_assets/particles/test_particle_system.json @@ -0,0 +1,29 @@ +{ + "emitters": [{ + "spawn": [ + {"particles_per_second": 2000, "stddev":0, "time": 1}, + {"particles_per_second": 0, "stddev":0, "time": 5} + ], + "spawn_loop": true, + + "size": {"x":0, "y":0}, + "direction": {"mean":{"elevation":0.85, "azimuth":-0.25}, "stddev":{"elevation":0.1, "azimuth":0.1}}, + + "ttl": {"mean": 4, "stddev": 0.5}, + + "velocity": {"mean": 32, "stddev": 8.0}, + + "emit_script_id": "comp_shader:particle_spawn_sphere", + + "type_id": "particle_def:test_particles" + }], + + "effectors": [ + { + "force": 10, + "force_dir": {"y":-1}, + "distance_decay": 0, + "scale_with_mass": false + } + ] +} diff --git a/assets/game_assets/particles/test_particles.json b/assets/game_assets/particles/test_particles.json new file mode 100644 index 0000000..07a7a15 --- /dev/null +++ b/assets/game_assets/particles/test_particles.json @@ -0,0 +1,30 @@ +{ + "keyframes": [ + { + "time": 0, + "color": {"mean":{"hue":0, "saturation":1}, "stddev":{"hue":0.5}}, + "size": {"mean": {"x": 0.05, "y":0.15, "z":0.04}, "stddev":{"x": 0.04, "y":0.02, "z":0.02}}, + "rotation": {"mean":{"angle":0}, "stddev":{"elevation":1, "azimuth":1, "angle": 1}}, + "drag": 0.1 + }, + { + "time": 4, + "color": {"mean":{"hue":0, "saturation":1}, "stddev":{"hue":1}}, + "size": {"mean": {"x": 0.01, "y":0.1, "z":0.01}}, + "rotation": {"mean":{"angle":1}, "stddev":{"elevation":1, "azimuth":1, "angle": 1}}, + "drag": 1.0 + } + ], + + "symmetric_scaling": true, + "rotate_with_velocity": false, + "blend": "solid", +/* + "geometry": "billboard", + "material_id": "mat:billboard_material.msf", +*/ + "geometry": "mesh", + "model_id": "model:cube", + + "update_script_id": "comp_shader:particle_update_simple" +} diff --git a/src/gameplay/beat_system.cpp b/src/gameplay/beat_system.cpp index 811d2d5..e7aa910 100644 --- a/src/gameplay/beat_system.cpp +++ b/src/gameplay/beat_system.cpp @@ -3,12 +3,19 @@ #include "../messages.hpp" #include +#include namespace phase_shifter::gameplay { namespace { constexpr auto beat_time = 1.f; - } + + auto smootherstep(float edge0, float edge1, float x) + { + x = std::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f); + return x * x * x * (x * (x * 6.f - 15.f) + 10.f); + } + } // namespace Beat_system::Beat_system(mirrage::util::Message_bus& bus) : _bus(bus) {} @@ -29,6 +36,20 @@ namespace phase_shifter::gameplay { _state = {beat, _acc, beat_time - _acc, beat_time, _state.beats_left}; } + auto Beat_system::graphic_time_scale() const -> float + { + constexpr auto t1_len = 0.1f; + constexpr auto t2_len = 0.6f; + constexpr auto factor = (1.f - (1.f - t1_len - t2_len) * 0.01f) / (t1_len + t2_len) * 2.f; + + auto to = _state.time_to_beat / _state.avg_beat_time; + auto from = _state.time_to_beat / _state.avg_beat_time; + + return mirrage::util::max(0.01f, + factor * (1.f - smootherstep(0.f, t1_len, to)), + factor * (1.f - smootherstep(0.f, t2_len, from))); + } + void Beat_system::decrease_beats_left(int count) { _state.beats_left -= count; } } // namespace phase_shifter::gameplay diff --git a/src/gameplay/beat_system.hpp b/src/gameplay/beat_system.hpp index 795dfd8..995f42d 100644 --- a/src/gameplay/beat_system.hpp +++ b/src/gameplay/beat_system.hpp @@ -25,6 +25,8 @@ namespace phase_shifter::gameplay { void decrease_beats_left(int count); + auto graphic_time_scale() const -> float; + private: mirrage::util::Message_bus& _bus; Beat_state _state; diff --git a/src/gameplay/movement_comp.hpp b/src/gameplay/movement_comp.hpp index 1873ac1..54ba484 100644 --- a/src/gameplay/movement_comp.hpp +++ b/src/gameplay/movement_comp.hpp @@ -15,14 +15,23 @@ namespace phase_shifter::gameplay { float distance_per_step = 1.f; float step_time_percentage = 0.2f; float off_beat_threshold = 0.f; + float overshoot = 0.1f; glm::vec2 aim{0.f, 0.f}; bool move = false; int beats_since_move = 0; float step_time_left = 0; + float step_time = 0; glm::vec2 last_step; + glm::vec2 pos_start; + glm::vec2 pos_end; }; - sf2_structDef(Movement_comp, beats_per_step, distance_per_step, step_time_percentage, off_beat_threshold); + sf2_structDef(Movement_comp, + beats_per_step, + distance_per_step, + step_time_percentage, + off_beat_threshold, + overshoot); } // namespace phase_shifter::gameplay diff --git a/src/gameplay/movement_system.cpp b/src/gameplay/movement_system.cpp index ad59cf3..cfbdf8d 100644 --- a/src/gameplay/movement_system.cpp +++ b/src/gameplay/movement_system.cpp @@ -13,6 +13,19 @@ namespace phase_shifter::gameplay { using mirrage::ecs::components::Transform_comp; + namespace { + float overshoot(float t, float tension) + { + auto a = [](auto t, auto s) { return t * t * ((s + 1) * t - s); }; + auto o = [](auto t, auto s) { return t * t * ((s + 1) * t + s); }; + + if(t < 0.5) + return 0.5 * a(t * 2.0, tension); + else + return 0.5 * (o(t * 2.0 - 2.0, tension) + 2.0); + } + } // namespace + Movement_system::Movement_system(mirrage::util::Message_bus& bus, mirrage::ecs::Entity_manager& ecs, const Beat_system& beat_system) @@ -47,7 +60,9 @@ namespace phase_shifter::gameplay { // start movement move.beats_since_move = 0; move.step_time_left = beat.avg_beat_time * move.step_time_percentage; - move.last_step = (move.aim / aim_len * move.distance_per_step) / move.step_time_left; + move.step_time = move.step_time_left; + move.last_step = + (aim_len > 1.f ? move.aim / aim_len : move.aim) * move.distance_per_step; } } else { @@ -57,10 +72,14 @@ namespace phase_shifter::gameplay { } if(move.step_time_left > 0.f) { + auto t0 = overshoot(1.f - move.step_time_left / move.step_time, move.overshoot); + move.step_time_left -= dt.value(); - transform.position.x += move.last_step.x * dt.value(); - transform.position.z += move.last_step.y * dt.value(); + auto t1 = overshoot(1.f - move.step_time_left / move.step_time, move.overshoot); + + transform.position.x = transform.position.x - move.last_step.x * t0 + move.last_step.x * t1; + transform.position.z = transform.position.z - move.last_step.y * t0 + move.last_step.y * t1; } } } diff --git a/src/gameplay/spring_comp.hpp b/src/gameplay/spring_comp.hpp index f2e4f90..5d3c703 100644 --- a/src/gameplay/spring_comp.hpp +++ b/src/gameplay/spring_comp.hpp @@ -15,5 +15,6 @@ namespace phase_shifter::gameplay { float mass = 1.f; }; - sf2_structDef(Spring_comp, spring_constant); -} \ No newline at end of file + sf2_structDef(Spring_comp, spring_constant, mass); + +} // namespace phase_shifter::gameplay diff --git a/src/level/level_system.cpp b/src/level/level_system.cpp index 01e394c..2695ca3 100644 --- a/src/level/level_system.cpp +++ b/src/level/level_system.cpp @@ -25,7 +25,7 @@ namespace phase_shifter::level { .position(glm::rotate(cam_dir, glm::vec3(0, 0, -1)) * 8.f + position) .post_create([=](ecs::Entity_facet entity) { entity.process([&](auto& transform) { - transform.position = transform.direction() * -10.f + position; + transform.position = transform.direction() * -15.f + position; transform.look_at(position); }); entity.process([=](gameplay::Viewtarget_comp& viewtarget) { diff --git a/src/meta_system.cpp b/src/meta_system.cpp index 011a6a3..63359a8 100644 --- a/src/meta_system.cpp +++ b/src/meta_system.cpp @@ -91,6 +91,7 @@ namespace phase_shifter { .position(glm::rotate(sun_dir, glm::vec3(0, 0, 1)) * 40.f) .create(); + entities().entity_builder("test_particle_emitter").position(glm::vec3(11, 0, 11)).create(); _level_system->load("dummy"); } @@ -116,7 +117,7 @@ namespace phase_shifter { _hud_system->update(dt); _model_loading->update(dt); - _renderer->update(dt); + _renderer->update(dt * _beat_system->graphic_time_scale()); } void Meta_system::draw() { -- GitLab