diff --git a/assets/game_assets/blueprints/player.json b/assets/game_assets/blueprints/player.json new file mode 100644 index 0000000000000000000000000000000000000000..9e933b4aa0700bfba6670319f0ba7fcf7f68eda0 --- /dev/null +++ b/assets/game_assets/blueprints/player.json @@ -0,0 +1,17 @@ +{ + "Transform":{ + "scale": {"x": 0.5, "y": 0.5, "z": 0.5} + }, + "Model": { + "aid": "model:cube" + }, + "Shadowcaster": { + }, + "Movement": { + "beats_per_step": 1, + "distance_per_step": 1, + "step_time_percentage": 0.2, + "off_beat_threshold": 0.2 + }, + "Input_controller": {} +} diff --git a/assets/game_assets/settings/input_mapping.json b/assets/game_assets/settings/input_mapping.json index 008b92dcfc0d563d6b77cf820131ad3931f41fa8..cbd56947d45df4ceb063507c21178d430b6fccf3 100644 --- a/assets/game_assets/settings/input_mapping.json +++ b/assets/game_assets/settings/input_mapping.json @@ -16,25 +16,32 @@ "Left": {"type":"continuous", "action":"move_left"}, "D": {"type":"continuous", "action":"move_right"}, "Right": {"type":"continuous", "action":"move_right"}, + + "Space": {"type":"once_down", "action":"the_button"}, "Caret": {"type":"once", "action":"console"}, - "F11": {"type":"once", "action":"console"}, - - "LShift": {"type":"continuous", "action":"multi_select"} + "F11": {"type":"once", "action":"console"} }, "pad_sticks": { - "left": {"type": "range", "action": "move"}, - "right": {"type": "range", "action": "move"} + "left": {"type": "range", "action": "aim"}, + "right": {"type": "range", "action": "aim"} }, "pad_buttons": { - "x": {"type":"continuous", "action":"jump"} + "left_trigger": {"type":"once_down", "action":"the_button"}, + "right_trigger": {"type":"once_down", "action":"the_button"}, + "left_shoulder": {"type":"once_down", "action":"the_button"}, + "right_shoulder": {"type":"once_down", "action":"the_button"}, + "a": {"type":"once_down", "action":"the_button"}, + "b": {"type":"once_down", "action":"the_button"}, + "x": {"type":"once_down", "action":"the_button"}, + "y": {"type":"once_down", "action":"the_button"}, + "back": {"type":"once", "action":"quit"}, + "start": {"type":"once", "action":"quit"} }, "mouse_buttons": { - {"button":1, "clicks":0}: {"type":"once", "action":"select"}, - {"button":2, "clicks":0}: {"type":"continuous", "action":"rotate"}, - {"button":3, "clicks":1}: {"type":"once", "action":"action"} + {"button":1, "clicks":0}: {"type":"once", "action":"select"} }, "mouse_movement": {"type": "range", "action": "mouse_look"}, "mouse_wheel_up": {"type": "range", "action": "zoom_in"}, diff --git a/external/mirrage b/external/mirrage index 92518bbd87323adbeafeecb250241afbe80255e7..f2ac702cb0a4c321afee8251ed544114f5c29a22 160000 --- a/external/mirrage +++ b/external/mirrage @@ -1 +1 @@ -Subproject commit 92518bbd87323adbeafeecb250241afbe80255e7 +Subproject commit f2ac702cb0a4c321afee8251ed544114f5c29a22 diff --git a/src/game_screen.cpp b/src/game_screen.cpp index 3667c5039035a72c87b45e1e4e9ed72c31a94cdd..8ee4b4a44d54e391778af9bbe0fb37c6b37abc34 100644 --- a/src/game_screen.cpp +++ b/src/game_screen.cpp @@ -29,6 +29,7 @@ namespace phase_shifter { using namespace mirrage; using namespace ecs::components; + using namespace mirrage::input; using namespace mirrage::util::unit_literals; using namespace graphic; @@ -36,6 +37,14 @@ namespace phase_shifter { Game_screen::Game_screen(Engine& engine) : Screen(engine), _mailbox(engine.bus()), _meta_system(static_cast(engine)) { + _mailbox.subscribe_to([&](Once_action& e) { + switch(e.id) { + case "quit"_strid: + // TODO: show pause menu, instead + _engine.screens().leave(); + break; + } + }); } Game_screen::~Game_screen() noexcept = default; diff --git a/src/gameplay/beat_system.cpp b/src/gameplay/beat_system.cpp index 6a30e782d8a8a3811afccb04ab911176b7af99f3..b5bc6ec0966aad577b5ed4464187f483a1b87cec 100644 --- a/src/gameplay/beat_system.cpp +++ b/src/gameplay/beat_system.cpp @@ -1,5 +1,6 @@ #include "beat_system.hpp" +#include namespace phase_shifter::gameplay { @@ -11,10 +12,12 @@ namespace phase_shifter::gameplay { { _acc += dt.value(); auto beat = _acc >= beat_time; - if(beat) + if(beat) { + LOG(plog::debug) << "beat"; _acc = 0; + } - _state = {beat, beat_time - _acc, beat_time - _acc}; + _state = {beat, _acc, beat_time - _acc}; } } // namespace phase_shifter::gameplay diff --git a/src/gameplay/beat_system.hpp b/src/gameplay/beat_system.hpp index 4d1d7ef63a1c76f4c56b88958e7c9bb99e305ae5..95f011af4061acfd41dd3b88c6a72310ecd6a62b 100644 --- a/src/gameplay/beat_system.hpp +++ b/src/gameplay/beat_system.hpp @@ -8,6 +8,7 @@ namespace phase_shifter::gameplay { bool beat = false; float time_since_beat = 0.f; float time_to_beat = 0.f; + float avg_beat_time = 1.f; }; // TODO: replace placeholder logic with actual beat detection diff --git a/src/gameplay/movement_comp.cpp b/src/gameplay/movement_comp.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6d49e6896187550e1329e7e3cc669167642a11c2 --- /dev/null +++ b/src/gameplay/movement_comp.cpp @@ -0,0 +1 @@ +#include "movement_comp.hpp" diff --git a/src/gameplay/movement_comp.hpp b/src/gameplay/movement_comp.hpp new file mode 100644 index 0000000000000000000000000000000000000000..1873ac11c1dd654ab375cdc64d3e52b92965b67c --- /dev/null +++ b/src/gameplay/movement_comp.hpp @@ -0,0 +1,28 @@ +#pragma once + +#include +#include +#include + + +namespace phase_shifter::gameplay { + + struct Movement_comp : public mirrage::ecs::Component { + static constexpr const char* name() { return "Movement"; } + using Component::Component; + + int beats_per_step = 1; + float distance_per_step = 1.f; + float step_time_percentage = 0.2f; + float off_beat_threshold = 0.f; + + glm::vec2 aim{0.f, 0.f}; + bool move = false; + int beats_since_move = 0; + float step_time_left = 0; + glm::vec2 last_step; + }; + + sf2_structDef(Movement_comp, beats_per_step, distance_per_step, step_time_percentage, off_beat_threshold); + +} // namespace phase_shifter::gameplay diff --git a/src/gameplay/movement_system.cpp b/src/gameplay/movement_system.cpp new file mode 100644 index 0000000000000000000000000000000000000000..201926a56349140ec8ca28507f41281e747a7d86 --- /dev/null +++ b/src/gameplay/movement_system.cpp @@ -0,0 +1,65 @@ +#include "movement_system.hpp" + +#include "beat_system.hpp" +#include "movement_comp.hpp" + +#include +#include +#include + + +namespace phase_shifter::gameplay { + + using mirrage::ecs::components::Transform_comp; + + Movement_system::Movement_system(mirrage::ecs::Entity_manager& ecs, const Beat_system& beat_system) + : _ecs(ecs), _beat_system(beat_system) + { + _ecs.register_component_type(); + } + + void Movement_system::update(mirrage::util::Time dt) + { + auto beat = _beat_system.beat_state(); + + for(auto&& [transform, move] : _ecs.list()) { + if(beat.beat) { + move.beats_since_move++; + } + + + if(move.move && move.beats_since_move >= move.beats_per_step + && (beat.beat || move.off_beat_threshold > 0.0001f)) { + + move.move = false; + + auto allowed = beat.beat || beat.time_since_beat <= move.off_beat_threshold + || beat.time_to_beat <= move.off_beat_threshold; + + if(allowed) { + auto aim_len = glm::length(move.aim); + if(aim_len < 0.0001f) { + // TODO: attack + } else { + // 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; + } + + } else { + // TODO: damage + LOG(plog::debug) << "miss"; + } + } + + if(move.step_time_left > 0.f) { + move.step_time_left -= dt.value(); + + transform.position.x += move.last_step.x * dt.value(); + transform.position.z += move.last_step.y * dt.value(); + } + } + } + +} // namespace phase_shifter::gameplay diff --git a/src/gameplay/movement_system.hpp b/src/gameplay/movement_system.hpp new file mode 100644 index 0000000000000000000000000000000000000000..720472db67db2bfe29ed57729c92a148219f12c1 --- /dev/null +++ b/src/gameplay/movement_system.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include + +namespace mirrage::ecs { + class Entity_manager; +} + +namespace phase_shifter::gameplay { + + class Beat_system; + + class Movement_system { + public: + Movement_system(mirrage::ecs::Entity_manager&, const Beat_system&); + + void update(mirrage::util::Time); + + private: + mirrage::ecs::Entity_manager& _ecs; + const Beat_system& _beat_system; + }; + +} // namespace phase_shifter::gameplay diff --git a/src/input/input_controller_comp.cpp b/src/input/input_controller_comp.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/src/input/input_controller_comp.hpp b/src/input/input_controller_comp.hpp new file mode 100644 index 0000000000000000000000000000000000000000..433ce08d57e562832c1174fad4ab5ba856eeb065 --- /dev/null +++ b/src/input/input_controller_comp.hpp @@ -0,0 +1,15 @@ +#pragma once + +#include +#include +#include + + +namespace phase_shifter::input { + + struct Input_controller_comp : public mirrage::ecs::Stateless_tag_component { + static constexpr const char* name() { return "Input_controller"; } + using Stateless_tag_component::Stateless_tag_component; + }; + +} // namespace phase_shifter::input diff --git a/src/input/input_system.cpp b/src/input/input_system.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5d84da3cd9aee62275056111ad8278bdebc7c416 --- /dev/null +++ b/src/input/input_system.cpp @@ -0,0 +1,97 @@ +#include "input_system.hpp" + +#include "input_controller_comp.hpp" + +#include "../gameplay/movement_comp.hpp" + +#include + +using namespace mirrage::input; + +namespace phase_shifter::input { + + namespace { + constexpr auto key_move_delay = 0.04f; + } + + Input_system::Input_system(mirrage::util::Message_bus& bus, mirrage::ecs::Entity_manager& ecs) + : _mailbox(bus), _ecs(ecs) + { + _ecs.register_component_type(); + + _mailbox.subscribe_to([&](Once_action& e) { + switch(e.id) { + case "the_button"_strid: + for(auto&& [_, m] : _ecs.list()) { + m.move = true; + } + break; + } + }); + + + _mailbox.subscribe_to([&](Continuous_action& e) { + switch(e.id) { + case "move_up"_strid: + _key_move_up = e.begin; + _key_move_queued |= e.begin; + break; + case "move_down"_strid: + _key_move_down = e.begin; + _key_move_queued |= e.begin; + break; + case "move_left"_strid: + _key_move_left = e.begin; + _key_move_queued |= e.begin; + break; + case "move_right"_strid: + _key_move_right = e.begin; + _key_move_queued |= e.begin; + break; + } + }); + + _mailbox.subscribe_to([&](Range_action& e) { + switch(e.id) { + case "aim"_strid: + for(auto&& [_, m] : _ecs.list()) { + m.aim = {-e.abs.x, -e.abs.y}; + } + break; + } + }); + } + + + void Input_system::enable() { _mailbox.enable(); } + void Input_system::disable() { _mailbox.disable(); } + + void Input_system::update(mirrage::util::Time dt) + { + _mailbox.update_subscriptions(); + + if(_key_move_queued) { + _key_move_timer += dt.value(); + if(_key_move_timer >= key_move_delay) { + _key_move_timer = 0; + _key_move_queued = false; + + auto aim = glm::vec2{0.f, 0.f}; + if(_key_move_up) + aim.y += 1.f; + if(_key_move_down) + aim.y -= 1.f; + if(_key_move_left) + aim.x += 1.f; + if(_key_move_right) + aim.x -= 1.f; + + for(auto&& [_, m] : _ecs.list()) { + m.aim = aim; + m.move = true; + } + } + } + } + +} // namespace phase_shifter::input diff --git a/src/input/input_system.hpp b/src/input/input_system.hpp new file mode 100644 index 0000000000000000000000000000000000000000..6460aa84fc10e455550a0517a7ab8d6de004c10e --- /dev/null +++ b/src/input/input_system.hpp @@ -0,0 +1,35 @@ +#pragma once + +#include +#include + +namespace mirrage::ecs { + class Entity_manager; +} + +namespace phase_shifter::input { + + class Beat_system; + + class Input_system { + public: + Input_system(mirrage::util::Message_bus&, mirrage::ecs::Entity_manager&); + + void update(mirrage::util::Time); + + void enable(); + void disable(); + + private: + mirrage::util::Mailbox_collection _mailbox; + mirrage::ecs::Entity_manager& _ecs; + + bool _key_move_up = false; + bool _key_move_down = false; + bool _key_move_left = false; + bool _key_move_right = false; + float _key_move_timer = 0.f; + bool _key_move_queued = false; + }; + +} // namespace phase_shifter::input diff --git a/src/meta_system.cpp b/src/meta_system.cpp index 36b675d89d1063a97222bdd5cd74cbd2941a3273..22b0e69357a395c96ba639526e3e1278a6ed6f8b 100644 --- a/src/meta_system.cpp +++ b/src/meta_system.cpp @@ -3,7 +3,9 @@ #include "audio/audio_asset.hpp" #include "game_engine.hpp" #include "gameplay/beat_system.hpp" +#include "gameplay/movement_system.hpp" #include "helper/attachment_system.hpp" +#include "input/input_system.hpp" #include "ui/hud_system.hpp" #include @@ -25,6 +27,8 @@ namespace phase_shifter { , _renderer(engine.renderer_factory().create_renderer(_entities, engine.render_pass_mask())) , _model_loading(std::make_unique(_entities, engine.assets())) , _beat_system(std::make_unique()) + , _movement_system(std::make_unique(_entities, *_beat_system)) + , _input_system(std::make_unique(engine.bus(), _entities)) , _attachment_system(std::make_unique(_entities)) , _hud_system(std::make_unique(engine.gui(), _entities)) { @@ -71,8 +75,8 @@ namespace phase_shifter { // TODO: replace with level-loading / generation code - auto cam_elevation = 0.1f * glm::pi(); - auto cam_azimuth = 0.25f; + auto cam_elevation = 0.3f * glm::pi(); + auto cam_azimuth = 0.0f; auto cam_dir = glm::quat(glm::vec3( (cam_elevation - 2.f) * glm::pi() / 2.f, glm::pi() * cam_azimuth, 0.f)); entities() @@ -97,7 +101,7 @@ namespace phase_shifter { .position(glm::rotate(sun_dir, glm::vec3(0, 0, 1)) * 40.f) .create(); - entities().entity_builder("cube").position({0, 1, 0}).create(); + entities().entity_builder("player").position({0, 1, 0}).create(); entities() .entity_builder("cube") @@ -121,6 +125,8 @@ namespace phase_shifter { _entities.process_queued_actions(); _beat_system->update(dt); + _input_system->update(dt); + _movement_system->update(dt); _attachment_system->update(dt); @@ -136,8 +142,8 @@ namespace phase_shifter { } - void Meta_system::pause() {} - void Meta_system::resume() {} + void Meta_system::pause() { _input_system->disable(); } + void Meta_system::resume() { _input_system->enable(); } void Meta_system::shrink_to_fit() { _renderer->shrink_to_fit(); } diff --git a/src/meta_system.hpp b/src/meta_system.hpp index b384b8a80dc3814eaa2c47a45b419ebee7e4871a..02dac58eacb3e0f7fc7a9318e2e251461c227459 100644 --- a/src/meta_system.hpp +++ b/src/meta_system.hpp @@ -21,10 +21,14 @@ namespace phase_shifter { namespace gameplay { class Beat_system; - } + class Movement_system; + } // namespace gameplay namespace helper { class Attachment_system; } + namespace input { + class Input_system; + } namespace ui { class Hud_system; } @@ -52,6 +56,8 @@ namespace phase_shifter { std::unique_ptr _model_loading; std::unique_ptr _beat_system; + std::unique_ptr _movement_system; + std::unique_ptr _input_system; std::unique_ptr _attachment_system; std::unique_ptr _hud_system; // TODO: add systems here