Commit a5556908 authored by Georg Schäfer's avatar Georg Schäfer

Merge branch 'develop' into feature/22-level-collision-detection

parents 03be0527 2a815341
Pipeline #3253 failed with stage
in 1 minute and 56 seconds
......@@ -13,5 +13,6 @@
"step_time_percentage": 0.2,
"off_beat_threshold": 0.2
},
"Input_controller": {}
"Input_controller": {},
"Player": {}
}
#include "game_screen.hpp"
#include "game_engine.hpp"
#include "level/level_system.hpp"
#include "gameover_screen.hpp"
#include "messages.hpp"
#include "meta_system.hpp"
#include "win_screen.hpp"
#include <mirrage/renderer/animation_comp.hpp>
#include <mirrage/renderer/light_comp.hpp>
......@@ -46,6 +48,15 @@ namespace phase_shifter {
break;
}
});
_mailbox.subscribe_to([&](Win_msg& e) {
// TODO: fade out...
_engine.screens().enter<Win_screen>();
});
_mailbox.subscribe_to([&](Lose_msg& e) {
// TODO: fade out...
_engine.screens().enter<Gameover_screen>();
});
}
Game_screen::~Game_screen() noexcept = default;
......@@ -53,8 +64,6 @@ namespace phase_shifter {
{
_meta_system.shrink_to_fit();
_mailbox.enable();
_meta_system.level_system().load("dummy");
}
void Game_screen::_on_leave(mirrage::util::maybe<Screen&>) { _mailbox.disable(); }
......
#include "gameover_screen.hpp"
#include "game_engine.hpp"
#include "game_screen.hpp"
#include "sync_screen.hpp"
#include <mirrage/gui/gui.hpp>
#include <mirrage/input/input_manager.hpp>
#include <mirrage/renderer/pass/clear_pass.hpp>
#include <mirrage/utils/log.hpp>
#include <mirrage/utils/maybe.hpp>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <chrono>
#include <cstdlib>
#include <iomanip>
#include <sstream>
#include <thread>
namespace phase_shifter {
using namespace mirrage;
using namespace ecs::components;
using namespace mirrage::input;
using namespace mirrage::util::unit_literals;
using namespace graphic;
Gameover_screen::Gameover_screen(Engine& engine)
: Screen(engine)
, _mailbox(engine.bus())
, _renderer(dynamic_cast<Game_engine&>(engine).renderer_factory().create_renderer(
mirrage::util::nothing, {renderer::render_pass_id_of<renderer::Clear_pass_factory>()}))
{
_mailbox.subscribe_to([&](Once_action& e) {
switch(e.id) {
case "quit"_strid:
// TODO: show pause menu, instead
_engine.screens().leave();
break;
}
});
}
Gameover_screen::~Gameover_screen() noexcept = default;
void Gameover_screen::_on_enter(mirrage::util::maybe<Screen&>) { _mailbox.enable(); }
void Gameover_screen::_on_leave(mirrage::util::maybe<Screen&>) { _mailbox.disable(); }
void Gameover_screen::_update(mirrage::util::Time dt)
{
std::this_thread::sleep_for(std::chrono::milliseconds(8));
_mailbox.update_subscriptions();
_renderer->update(dt);
}
void Gameover_screen::_draw()
{
_renderer->draw(); //< clear screen
ImGui::PositionNextWindow(
glm::vec2(500, 500), ImGui::WindowPosition_X::center, ImGui::WindowPosition_Y::center);
if(ImGui::Begin("Gameover")) {
ImGui::TextUnformatted("TODO");
if(ImGui::Button("Start")) {
_engine.screens().enter<Game_screen>();
}
if(ImGui::Button("Sync")) {
_engine.screens().enter<Sync_screen>();
}
if(ImGui::Button("Quit")) {
_engine.screens().leave();
}
}
ImGui::End();
}
} // namespace phase_shifter
#pragma once
#include <mirrage/engine.hpp>
#include <mirrage/gui/gui.hpp>
#include <mirrage/renderer/deferred_renderer.hpp>
#include <mirrage/utils/console_command.hpp>
#include <mirrage/utils/maybe.hpp>
namespace phase_shifter {
class Gameover_screen : public mirrage::Screen {
public:
Gameover_screen(mirrage::Engine& engine);
~Gameover_screen() noexcept override;
auto name() const -> std::string override { return "Gameover"; }
protected:
void _update(mirrage::util::Time delta_time) override;
void _draw() override;
void _on_enter(mirrage::util::maybe<Screen&> prev) override;
void _on_leave(mirrage::util::maybe<Screen&> next) override;
auto _prev_screen_policy() const noexcept -> mirrage::Prev_screen_policy override
{
return mirrage::Prev_screen_policy::discard;
}
protected:
mirrage::util::Mailbox_collection _mailbox;
std::unique_ptr<mirrage::renderer::Deferred_renderer> _renderer;
};
} // namespace phase_shifter
#include "beat_system.hpp"
#include "../messages.hpp"
#include <mirrage/utils/log.hpp>
namespace phase_shifter::gameplay {
......@@ -8,16 +10,25 @@ namespace phase_shifter::gameplay {
constexpr auto beat_time = 1.f;
}
Beat_system::Beat_system(mirrage::util::Message_bus& bus) : _bus(bus) {}
void Beat_system::update(mirrage::util::Time dt)
{
_acc += dt.value();
auto beat = _acc >= beat_time;
if(beat) {
_state.beats_left--;
LOG(plog::debug) << "beat";
_acc = 0;
if(_state.beats_left == 0) {
_bus.send<Lose_msg>();
}
}
_state = {beat, _acc, beat_time - _acc, beat_time};
_state = {beat, _acc, beat_time - _acc, beat_time, _state.beats_left};
}
void Beat_system::decrease_beats_left(int count) { _state.beats_left -= count; }
} // namespace phase_shifter::gameplay
#pragma once
#include <mirrage/utils/messagebus.hpp>
#include <mirrage/utils/units.hpp>
namespace phase_shifter::gameplay {
......@@ -9,20 +10,25 @@ namespace phase_shifter::gameplay {
float time_since_beat = 0.f;
float time_to_beat = 0.f;
float avg_beat_time = 1.f;
int beats_left = 999.f;
};
// TODO: replace placeholder logic with actual beat detection
class Beat_system {
public:
Beat_system() = default;
Beat_system(mirrage::util::Message_bus&);
void update(mirrage::util::Time);
auto beat_state() const { return _state; }
void decrease_beats_left(int count);
private:
Beat_state _state;
float _acc = 0.f;
mirrage::util::Message_bus& _bus;
Beat_state _state;
float _acc = 0.f;
};
} // namespace phase_shifter::gameplay
#include "combat_system.hpp"
#include "player_comp.hpp"
namespace phase_shifter::gameplay {
namespace {
constexpr auto damage_beat_penalty = 10;
}
Combat_system::Combat_system(mirrage::util::Message_bus& bus,
mirrage::ecs::Entity_manager& ecs,
Beat_system& beats)
: _mailbox(bus), _ecs(ecs), _beat_system(beats)
{
_ecs.register_component_type<Player_comp>();
_mailbox.subscribe_to([&](Damaged_msg& e) {
_ecs.get(e.entity).process([&](auto& entity) {
entity.process([&](Player_comp&) { _beat_system.decrease_beats_left(damage_beat_penalty); });
});
});
}
void Combat_system::update(mirrage::util::Time)
{
_mailbox.update_subscriptions();
// TODO
}
} // namespace phase_shifter::gameplay
#pragma once
#include "beat_system.hpp"
#include <mirrage/ecs/entity_handle.hpp>
#include <mirrage/utils/messagebus.hpp>
#include <mirrage/utils/units.hpp>
namespace mirrage::ecs {
class Entity_manager;
}
namespace phase_shifter::gameplay {
struct Damaged_msg {
mirrage::ecs::Entity_handle entity;
};
class Combat_system {
public:
Combat_system(mirrage::util::Message_bus&, mirrage::ecs::Entity_manager&, Beat_system&);
void update(mirrage::util::Time);
private:
mirrage::util::Mailbox_collection _mailbox;
mirrage::ecs::Entity_manager& _ecs;
Beat_system& _beat_system;
};
} // namespace phase_shifter::gameplay
#include "movement_system.hpp"
#include "beat_system.hpp"
#include "combat_system.hpp"
#include "movement_comp.hpp"
#include <mirrage/ecs/components/transform_comp.hpp>
......@@ -12,8 +13,10 @@ 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)
Movement_system::Movement_system(mirrage::util::Message_bus& bus,
mirrage::ecs::Entity_manager& ecs,
const Beat_system& beat_system)
: _bus(bus), _ecs(ecs), _beat_system(beat_system)
{
_ecs.register_component_type<Movement_comp>();
}
......@@ -28,13 +31,13 @@ namespace phase_shifter::gameplay {
}
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)
&& move.beats_since_move >= move.beats_per_step;
auto allowed = beat.beat || beat.time_since_beat <= move.off_beat_threshold
|| beat.time_to_beat <= move.off_beat_threshold;
if(move.move && (allowed || move.off_beat_threshold > 0.0001f)) {
move.move = false;
if(allowed) {
auto aim_len = glm::length(move.aim);
......@@ -48,7 +51,7 @@ namespace phase_shifter::gameplay {
}
} else {
// TODO: damage
_bus.send<Damaged_msg>(transform.owner_handle());
LOG(plog::debug) << "miss";
}
}
......
#pragma once
#include <mirrage/utils/messagebus.hpp>
#include <mirrage/utils/units.hpp>
namespace mirrage::ecs {
......@@ -12,11 +13,12 @@ namespace phase_shifter::gameplay {
class Movement_system {
public:
Movement_system(mirrage::ecs::Entity_manager&, const Beat_system&);
Movement_system(mirrage::util::Message_bus&, mirrage::ecs::Entity_manager&, const Beat_system&);
void update(mirrage::util::Time);
private:
mirrage::util::Message_bus& _bus;
mirrage::ecs::Entity_manager& _ecs;
const Beat_system& _beat_system;
};
......
#include "player_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 Player_comp : public mirrage::ecs::Stateless_tag_component<Player_comp> {
static constexpr const char* name() { return "Player"; }
using Stateless_tag_component::Stateless_tag_component;
};
} // namespace phase_shifter::gameplay
......@@ -11,7 +11,7 @@ using namespace mirrage::input;
namespace phase_shifter::input {
namespace {
constexpr auto key_move_delay = 0.04f;
constexpr auto key_move_delay = 0.01f;
}
Input_system::Input_system(mirrage::util::Message_bus& bus, mirrage::ecs::Entity_manager& ecs)
......
#include "intro_screen.hpp"
#include "game_engine.hpp"
#include "game_screen.hpp"
#include "sync_screen.hpp"
#include <mirrage/gui/gui.hpp>
#include <mirrage/input/input_manager.hpp>
#include <mirrage/renderer/pass/clear_pass.hpp>
#include <mirrage/utils/log.hpp>
#include <mirrage/utils/maybe.hpp>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <chrono>
#include <cstdlib>
#include <iomanip>
#include <sstream>
#include <thread>
namespace phase_shifter {
using namespace mirrage;
using namespace ecs::components;
using namespace mirrage::input;
using namespace mirrage::util::unit_literals;
using namespace graphic;
Intro_screen::Intro_screen(Engine& engine)
: Screen(engine)
, _mailbox(engine.bus())
, _renderer(dynamic_cast<Game_engine&>(engine).renderer_factory().create_renderer(
mirrage::util::nothing, {renderer::render_pass_id_of<renderer::Clear_pass_factory>()}))
{
_mailbox.subscribe_to([&](Once_action& e) {
switch(e.id) {
case "quit"_strid:
// TODO: show pause menu, instead
_engine.screens().leave();
break;
}
});
}
Intro_screen::~Intro_screen() noexcept = default;
void Intro_screen::_on_enter(mirrage::util::maybe<Screen&>) { _mailbox.enable(); }
void Intro_screen::_on_leave(mirrage::util::maybe<Screen&>) { _mailbox.disable(); }
void Intro_screen::_update(mirrage::util::Time dt)
{
std::this_thread::sleep_for(std::chrono::milliseconds(8));
_mailbox.update_subscriptions();
_renderer->update(dt);
}
void Intro_screen::_draw()
{
_renderer->draw(); //< clear screen
ImGui::PositionNextWindow(
glm::vec2(500, 500), ImGui::WindowPosition_X::center, ImGui::WindowPosition_Y::center);
if(ImGui::Begin("Intro")) {
ImGui::TextUnformatted("TODO");
if(ImGui::Button("Start")) {
_engine.screens().enter<Game_screen>();
}
if(ImGui::Button("Sync")) {
_engine.screens().enter<Sync_screen>();
}
if(ImGui::Button("Quit")) {
_engine.screens().leave();
}
}
ImGui::End();
}
} // namespace phase_shifter
#pragma once
#include <mirrage/engine.hpp>
#include <mirrage/gui/gui.hpp>
#include <mirrage/renderer/deferred_renderer.hpp>
#include <mirrage/utils/console_command.hpp>
#include <mirrage/utils/maybe.hpp>
namespace phase_shifter {
class Intro_screen : public mirrage::Screen {
public:
Intro_screen(mirrage::Engine& engine);
~Intro_screen() noexcept override;
auto name() const -> std::string override { return "Gameover"; }
protected:
void _update(mirrage::util::Time delta_time) override;
void _draw() override;
void _on_enter(mirrage::util::maybe<Screen&> prev) override;
void _on_leave(mirrage::util::maybe<Screen&> next) override;
auto _prev_screen_policy() const noexcept -> mirrage::Prev_screen_policy override
{
return mirrage::Prev_screen_policy::discard;
}
protected:
mirrage::util::Mailbox_collection _mailbox;
std::unique_ptr<mirrage::renderer::Deferred_renderer> _renderer;
};
} // namespace phase_shifter
......@@ -9,6 +9,10 @@
#include "game_engine.hpp"
#include "game_screen.hpp"
#include "gameover_screen.hpp"
#include "intro_screen.hpp"
#include "sync_screen.hpp"
#include "win_screen.hpp"
#include <mirrage/info.hpp>
......@@ -25,8 +29,8 @@
#include <exception>
#include <iostream>
using namespace mirrage; // import engine namespace
using namespace phase_shifter; // import game namespace
using namespace mirrage; // import engine namespace
using namespace phase_shifter; // import game namespace
using namespace std::string_literals;
......@@ -145,6 +149,14 @@ namespace {
global_commands->add("screen.enter.game | Enters the game screen",
[&]() { engine->screens().enter<Game_screen>(); });
global_commands->add("screen.enter.gameover | Enters the gameover screen",
[&]() { engine->screens().enter<Gameover_screen>(); });
global_commands->add("screen.enter.intro | Enters the intro screen",
[&]() { engine->screens().enter<Intro_screen>(); });
global_commands->add("screen.enter.sync | Enters the sync screen",
[&]() { engine->screens().enter<Sync_screen>(); });
global_commands->add("screen.enter.win | Enters the win screen",
[&]() { engine->screens().enter<Win_screen>(); });
if(argc > 1 && argv[1] == "game"s)
engine->screens().enter<Game_screen>();
......
#pragma once
namespace phase_shifter {
struct Win_msg {
};
struct Lose_msg {
};
} // namespace phase_shifter
......@@ -4,6 +4,7 @@
#include "game_engine.hpp"
#include "gameplay/beat_system.hpp"
#include "gameplay/camera_system.hpp"
#include "gameplay/combat_system.hpp"
#include "gameplay/movement_system.hpp"
#include "helper/attachment_system.hpp"
#include "input/input_system.hpp"
......@@ -28,9 +29,10 @@ namespace phase_shifter {
, _audio()
, _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))
, _beat_system(std::make_unique<gameplay::Beat_system>(engine.bus()))
, _movement_system(std::make_unique<gameplay::Movement_system>(engine.bus(), _entities, *_beat_system))
, _input_system(std::make_unique<input::Input_system>(engine.bus(), _entities))
, _combat_system(std::make_unique<gameplay::Combat_system>(engine.bus(), _entities, *_beat_system))
, _attachment_system(std::make_unique<helper::Attachment_system>(_entities))
, _hud_system(std::make_unique<ui::Hud_system>(engine.gui(), _entities, *_beat_system))
, _level_system(std::make_unique<level::Level_system>(_entities, engine.assets()))
......@@ -88,6 +90,9 @@ namespace phase_shifter {
.rotation(sun_dir)
.position(glm::rotate(sun_dir, glm::vec3(0, 0, 1)) * 40.f)
.create();
_level_system->load("dummy");
}
Meta_system::~Meta_system()
......@@ -103,6 +108,7 @@ namespace phase_shifter {
_beat_system->update(dt);
_input_system->update(dt);
_movement_system->update(dt);
_combat_system->update(dt);
_camera_system->update(dt);
_attachment_system->update(dt);
......
......@@ -23,6 +23,7 @@ namespace phase_shifter {
class Beat_system;
class Movement_system;
class Camera_system;