Commit 9f93e3d8 authored by Florian Oetke's avatar Florian Oetke
Browse files

Merge branch 'feature/2-basic-movement' into 'develop'

Resolve "Basic Movement"

Closes #2

See merge request !3
parents fc1d7cf2 9dcce845
Pipeline #3223 passed with stage
in 7 minutes and 36 seconds
{
"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": {}
}
......@@ -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"},
......
Subproject commit 92518bbd87323adbeafeecb250241afbe80255e7
Subproject commit f2ac702cb0a4c321afee8251ed544114f5c29a22
......@@ -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<Game_engine&>(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;
......
#include "beat_system.hpp"
#include <mirrage/utils/log.hpp>
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
......@@ -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
......
#include "movement_comp.hpp"
#pragma once
#include <mirrage/ecs/ecs.hpp>
#include <mirrage/utils/sf2_glm.hpp>
#include <mirrage/utils/units.hpp>
namespace phase_shifter::gameplay {
struct Movement_comp : public mirrage::ecs::Component<Movement_comp> {
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
#include "movement_system.hpp"
#include "beat_system.hpp"
#include "movement_comp.hpp"
#include <mirrage/ecs/components/transform_comp.hpp>
#include <mirrage/ecs/ecs.hpp>
#include <mirrage/ecs/entity_set_view.hpp>
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<Movement_comp>();
}
void Movement_system::update(mirrage::util::Time dt)
{
auto beat = _beat_system.beat_state();
for(auto&& [transform, move] : _ecs.list<Transform_comp, Movement_comp>()) {
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
#pragma once
#include <mirrage/utils/units.hpp>
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
#pragma once
#include <mirrage/ecs/ecs.hpp>
#include <mirrage/utils/sf2_glm.hpp>
#include <mirrage/utils/units.hpp>
namespace phase_shifter::input {
struct Input_controller_comp : public mirrage::ecs::Stateless_tag_component<Input_controller_comp> {
static constexpr const char* name() { return "Input_controller"; }
using Stateless_tag_component::Stateless_tag_component;
};
} // namespace phase_shifter::input
#include "input_system.hpp"
#include "input_controller_comp.hpp"
#include "../gameplay/movement_comp.hpp"
#include <mirrage/input/events.hpp>
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<Input_controller_comp>();
_mailbox.subscribe_to([&](Once_action& e) {
switch(e.id) {
case "the_button"_strid:
for(auto&& [_, m] : _ecs.list<Input_controller_comp, gameplay::Movement_comp>()) {
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<Input_controller_comp, gameplay::Movement_comp>()) {
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<Input_controller_comp, gameplay::Movement_comp>()) {
m.aim = aim;
m.move = true;
}
}
}
}
} // namespace phase_shifter::input
#pragma once
#include <mirrage/utils/messagebus.hpp>
#include <mirrage/utils/units.hpp>
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
......@@ -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 <context.hpp>
......@@ -25,6 +27,8 @@ namespace phase_shifter {
, _renderer(engine.renderer_factory().create_renderer(_entities, engine.render_pass_mask()))
, _model_loading(std::make_unique<renderer::Loading_system>(_entities, engine.assets()))
, _beat_system(std::make_unique<gameplay::Beat_system>())
, _movement_system(std::make_unique<gameplay::Movement_system>(_entities, *_beat_system))
, _input_system(std::make_unique<input::Input_system>(engine.bus(), _entities))
, _attachment_system(std::make_unique<helper::Attachment_system>(_entities))
, _hud_system(std::make_unique<ui::Hud_system>(engine.gui(), _entities))
{
......@@ -71,8 +75,8 @@ namespace phase_shifter {
// TODO: replace with level-loading / generation code
auto cam_elevation = 0.1f * glm::pi<float>();
auto cam_azimuth = 0.25f;
auto cam_elevation = 0.3f * glm::pi<float>();
auto cam_azimuth = 0.0f;
auto cam_dir = glm::quat(glm::vec3(
(cam_elevation - 2.f) * glm::pi<float>() / 2.f, glm::pi<float>() * 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(); }
......
......@@ -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<mirrage::renderer::Loading_system> _model_loading;
std::unique_ptr<gameplay::Beat_system> _beat_system;
std::unique_ptr<gameplay::Movement_system> _movement_system;
std::unique_ptr<input::Input_system> _input_system;
std::unique_ptr<helper::Attachment_system> _attachment_system;
std::unique_ptr<ui::Hud_system> _hud_system;
// TODO: add systems here
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment