diff --git a/combat_ui.cpp b/combat_ui.cpp index d0a7c0a..031afd3 100644 --- a/combat_ui.cpp +++ b/combat_ui.cpp @@ -3,13 +3,15 @@ #include "color.hpp" namespace gui { + using namespace guecs; + CombatUI::CombatUI(GameLevel level) : $level(level) { $gui.position(RAY_VIEW_X, RAY_VIEW_HEIGHT, RAY_VIEW_WIDTH, SCREEN_HEIGHT - RAY_VIEW_HEIGHT); $gui.layout( "[*%(100,150)button_attack1 | *%(100,150)button_attack2 | *%(100,150)button_attack3 | *%(100,150)button_heal]" - "[ >.%(100,50)label_hp | *%.(100,50)bar_hp | _ ]"); + "[ >.%(100,50)label_hp | *%.(190,50)bar_hp | _ ]"); } void CombatUI::render(TexturePack& textures) { @@ -21,12 +23,12 @@ namespace gui { world.set(button, cell); world.set(button, {"trash_button"}); world.set(button, {100}); - world.set(button, {name}); + world.set(button, {"Button"}); } else if(name.starts_with("bar_")) { - auto meter = $gui.entity(name); - world.set(meter, cell); - world.set(meter, {}); - world.set(meter, {}); + $meter = $gui.entity(name); + world.set($meter, cell); + world.set($meter, {}); + world.set($meter, {}); } else { // ignored, it's just space $gui.entity(name); @@ -39,4 +41,10 @@ namespace gui { void CombatUI::draw(sf::RenderWindow& window) { $gui.render(window); } + + void CombatUI::set_damage(float percent) { + fmt::println("combat ui sets damage: {}", percent); + auto& meter = $gui.world().get($meter); + meter.percent = percent; + } } diff --git a/combat_ui.hpp b/combat_ui.hpp index 7fe3331..1380e6b 100644 --- a/combat_ui.hpp +++ b/combat_ui.hpp @@ -3,12 +3,13 @@ #include "levelmanager.hpp" #include #include -#include "ecs_gui.hpp" +#include "guecs.hpp" namespace gui { class CombatUI { public: - GUECS $gui; + guecs::UI $gui; + DinkyECS::Entity $meter; GameLevel $level; CombatUI(GameLevel level); @@ -17,5 +18,6 @@ namespace gui { void draw(sf::RenderWindow& window); void update_level(GameLevel &level) { $level = level; } void click(int x, int y); + void set_damage(float percent); }; } diff --git a/ecs_gui.cpp b/ecs_gui.cpp deleted file mode 100644 index 84b874f..0000000 --- a/ecs_gui.cpp +++ /dev/null @@ -1,78 +0,0 @@ -#include "ecs_gui.hpp" -#include "constants.hpp" - -GUECS::GUECS() { - $font = make_shared(FONT_FILE_NAME); -} - -void GUECS::position(int x, int y, int width, int height) { - $parser.position(x, y, width, height); -} - -void GUECS::layout(std::string grid) { - $grid = grid; - $parser.parse($grid); -} - -DinkyECS::Entity GUECS::entity(std::string name) { - auto entity = $world.entity(); - $world.set(entity, {name}); - return entity; -} - -void GUECS::init(TexturePack& textures) { - $world.query([](auto, auto& cell, auto& rect) { - rect.init(cell); - }); - - $world.query([this](auto, auto& cell, auto& text) { - text.init(cell, $font); - }); - - $world.query([&](auto, auto &cell, auto &sprite) { - auto sprite_texture = textures.get(sprite.name); - sprite.texture = sprite_texture.texture; - sprite.sprite = make_shared(*sprite.texture); - sprite.sprite->setPosition({float(cell.x + 5), float(cell.y + 5)}); - auto size = sprite.texture->getSize(); - sprite.sprite->setScale({float(cell.w - 10) / size.x, float(cell.h - 10) / size.y}); - }); -} - -void GUECS::render(sf::RenderWindow& window) { - $world.query([&](auto ent, auto& cell, const auto &meter) { - if($world.has(ent)) { - float level = meter.percent * float(cell.w); - auto& target = $world.get(ent); - // ZED: this 6 is a border width, make it a thing - target.shape->setSize({std::max(level, 0.0f), float(cell.h - 6)}); - } - }); - - $world.query([&](auto, auto& rect) { - window.draw(*rect.shape); - }); - - $world.query([&](auto, auto& sprite) { - window.draw(*sprite.sprite); - }); - - $world.query([&](auto, auto& text) { - window.draw(*text.text); - }); -} - -void GUECS::mouse(sf::RenderWindow &window) { - if(sf::Mouse::isButtonPressed(sf::Mouse::Button::Left)) { - sf::Vector2f pos = window.mapPixelToCoords(sf::Mouse::getPosition(window)); - $world.query([&](auto ent, auto& cell, auto &clicked) { - if((pos.x >= cell.x && pos.x <= cell.x + cell.w) && - (pos.y >= cell.y && pos.y <= cell.y + cell.h)) - { - auto& cn = $world.get(ent); - fmt::println("clicked on entity {} with name {} and event {}", - ent, cn.name, clicked.event); - } - }); - } -} diff --git a/ecs_gui.hpp b/ecs_gui.hpp deleted file mode 100644 index 7c724f6..0000000 --- a/ecs_gui.hpp +++ /dev/null @@ -1,84 +0,0 @@ -#pragma once -#include "color.hpp" -#include "dinkyecs.hpp" -#include "lel.hpp" -#include -#include -#include -#include "texture.hpp" - -using std::shared_ptr, std::make_shared; - -struct Textual { - std::string label; - shared_ptr font = nullptr; - shared_ptr text = nullptr; - - void init(lel::Cell &cell, shared_ptr font_ptr) { - font = font_ptr; - text = make_shared(*font, label); - - auto bounds = text->getLocalBounds(); - auto text_cell = lel::center(bounds.size.x, bounds.size.y, cell); - // this stupid / 2 is because SFML renders from baseline rather than from the claimed bounding box - text->setPosition({float(text_cell.x), float(text_cell.y) - text_cell.h / 2}); - } -}; - -struct Clickable { - int event = 0; -}; - -struct Sprite { - std::string name; - std::shared_ptr sprite = nullptr; - std::shared_ptr texture = nullptr; -}; - -struct Rectangle { - shared_ptr shape = nullptr; - - void init(lel::Cell& cell) { - sf::Vector2f size{(float)cell.w, (float)cell.h}; - if(shape == nullptr) shape = make_shared(size); - shape->setPosition({float(cell.x + 3), float(cell.y + 3)}); - shape->setSize({float(cell.w - 6), float(cell.h - 6)}); - shape->setFillColor(ColorValue::DARK_MID); - shape->setOutlineColor(ColorValue::MID); - shape->setOutlineThickness(1); - } -}; - -struct Meter { - float percent = 100.0; -}; - -struct CellName { - std::string name; -}; - -class GUECS { - public: - DinkyECS::World $world; - shared_ptr $font = nullptr; - lel::Parser $parser; - std::string $grid = ""; - - GUECS(); - - void position(int x, int y, int width, int height); - void layout(std::string grid); - DinkyECS::Entity entity(std::string name); - - inline lel::CellMap& cells() { - return $parser.cells; - } - - inline DinkyECS::World& world() { - return $world; - } - - void init(TexturePack& textures); - void render(sf::RenderWindow& window); - void mouse(sf::RenderWindow &window); -}; diff --git a/guecs.cpp b/guecs.cpp new file mode 100644 index 0000000..09913ce --- /dev/null +++ b/guecs.cpp @@ -0,0 +1,86 @@ +#include "guecs.hpp" +#include "constants.hpp" + +namespace guecs { + UI::UI() { + $font = make_shared(FONT_FILE_NAME); + } + + void UI::position(int x, int y, int width, int height) { + $parser.position(x, y, width, height); + } + + void UI::layout(std::string grid) { + $grid = grid; + $parser.parse($grid); + } + + DinkyECS::Entity UI::entity(std::string name) { + auto entity = $world.entity(); + $world.set(entity, {name}); + return entity; + } + + void UI::init(TexturePack& textures) { + $world.query([](auto, auto& cell, auto& rect) { + rect.init(cell); + }); + + $world.query([](auto, auto& bg, auto &) { + bg.shape->setFillColor(ColorValue::BLACK); + }); + + $world.query([](auto, auto &cell, auto& meter) { + meter.init(cell); + }); + + $world.query([this](auto, auto& cell, auto& text) { + text.init(cell, $font); + }); + + $world.query([&](auto, auto &cell, auto &sprite) { + auto sprite_texture = textures.get(sprite.name); + sprite.texture = sprite_texture.texture; + sprite.sprite = make_shared(*sprite.texture); + sprite.sprite->setPosition({float(cell.x + 5), float(cell.y + 5)}); + auto size = sprite.texture->getSize(); + sprite.sprite->setScale({float(cell.w - 10) / size.x, float(cell.h - 10) / size.y}); + }); + } + + void UI::render(sf::RenderWindow& window) { + $world.query([&](auto, auto& rect) { + window.draw(*rect.shape); + }); + + $world.query([&](auto, auto& cell, const auto &meter) { + float level = std::clamp(meter.percent, 0.0f, 1.0f) * float(cell.w); + // ZED: this 6 is a border width, make it a thing + meter.bar.shape->setSize({std::max(level, 0.0f), float(cell.h - 6)}); + window.draw(*meter.bar.shape); + }); + + $world.query([&](auto, auto& sprite) { + window.draw(*sprite.sprite); + }); + + $world.query([&](auto, auto& text) { + window.draw(*text.text); + }); + } + + void UI::mouse(sf::RenderWindow &window) { + if(sf::Mouse::isButtonPressed(sf::Mouse::Button::Left)) { + sf::Vector2f pos = window.mapPixelToCoords(sf::Mouse::getPosition(window)); + $world.query([&](auto ent, auto& cell, auto &clicked) { + if((pos.x >= cell.x && pos.x <= cell.x + cell.w) && + (pos.y >= cell.y && pos.y <= cell.y + cell.h)) + { + auto& cn = $world.get(ent); + fmt::println("clicked on entity {} with name {} and event {}", + ent, cn.name, clicked.event); + } + }); + } + } +} diff --git a/guecs.hpp b/guecs.hpp new file mode 100644 index 0000000..fc1b1c8 --- /dev/null +++ b/guecs.hpp @@ -0,0 +1,91 @@ +#pragma once +#include "color.hpp" +#include "dinkyecs.hpp" +#include "lel.hpp" +#include +#include +#include +#include "texture.hpp" + +namespace guecs { + using std::shared_ptr, std::make_shared; + + struct Textual { + std::string label; + shared_ptr font = nullptr; + shared_ptr text = nullptr; + + void init(lel::Cell &cell, shared_ptr font_ptr) { + font = font_ptr; + text = make_shared(*font, label); + + auto bounds = text->getLocalBounds(); + auto text_cell = lel::center(bounds.size.x, bounds.size.y, cell); + // this stupid / 2 is because SFML renders from baseline rather than from the claimed bounding box + text->setPosition({float(text_cell.x), float(text_cell.y) - text_cell.h / 2}); + } + }; + + struct Clickable { + int event = 0; + }; + + struct Sprite { + std::string name; + std::shared_ptr sprite = nullptr; + std::shared_ptr texture = nullptr; + }; + + struct Rectangle { + shared_ptr shape = nullptr; + + void init(lel::Cell& cell) { + sf::Vector2f size{(float)cell.w, (float)cell.h}; + if(shape == nullptr) shape = make_shared(size); + shape->setPosition({float(cell.x + 3), float(cell.y + 3)}); + shape->setSize({float(cell.w - 6), float(cell.h - 6)}); + shape->setFillColor(ColorValue::DARK_MID); + shape->setOutlineColor(ColorValue::MID); + shape->setOutlineThickness(1); + } + }; + + struct Meter { + float percent = 1.0f; + Rectangle bar; + + void init(lel::Cell& cell) { + bar.init(cell); + } + }; + + struct CellName { + std::string name; + }; + + class UI { + public: + DinkyECS::World $world; + shared_ptr $font = nullptr; + lel::Parser $parser; + std::string $grid = ""; + + UI(); + + void position(int x, int y, int width, int height); + void layout(std::string grid); + DinkyECS::Entity entity(std::string name); + + inline lel::CellMap& cells() { + return $parser.cells; + } + + inline DinkyECS::World& world() { + return $world; + } + + void init(TexturePack& textures); + void render(sf::RenderWindow& window); + void mouse(sf::RenderWindow &window); + }; +} diff --git a/gui.cpp b/gui.cpp index cc06e97..7ce55bf 100644 --- a/gui.cpp +++ b/gui.cpp @@ -159,7 +159,7 @@ namespace gui { state(State::MAPPING); break; case ATTACK: - fmt::println("ATTACK IGNORED"); + state(State::ATTACKING); break; case START_COMBAT: state(State::IN_COMBAT); @@ -269,6 +269,7 @@ namespace gui { auto player = $level.world->get_the(); auto& player_combat = $level.world->get(player.entity); player_combat.hp = player_combat.max_hp; + $combat_view.set_damage(float(player_combat.hp) / float(player_combat.max_hp)); } break; default: break; // ignored @@ -398,6 +399,9 @@ namespace gui { if(damage.enemy_did > 0) { $status_view.log(fmt::format("Enemy HIT YOU for {} damage!", damage.enemy_did)); $status_view.log(fmt::format("-- Enemy has {} HP left.", enemy_combat.hp)); + auto player = world.get_the(); + auto player_combat = world.get(player.entity); + $combat_view.set_damage(float(player_combat.hp) / float(player_combat.max_hp)); } else { $status_view.log("Enemy MISSED YOU."); } @@ -407,8 +411,6 @@ namespace gui { } else { $status_view.log("You MISSED the enemy."); } - - // this is where we tell the combat ui about the damage } break; case eGUI::COMBAT_START: diff --git a/meson.build b/meson.build index f95aaca..5ab9bf8 100644 --- a/meson.build +++ b/meson.build @@ -61,7 +61,7 @@ sources = [ 'config.cpp', 'dbc.cpp', 'devices.cpp', - 'ecs_gui.cpp', + 'guecs.cpp', 'gui.cpp', 'inventory.cpp', 'lel.cpp', @@ -92,7 +92,7 @@ executable('runtests', sources + [ 'tests/base.cpp', 'tests/dbc.cpp', 'tests/dinkyecs.cpp', - 'tests/ecs_gui.cpp', + 'tests/guecs.cpp', 'tests/fsm.cpp', 'tests/inventory.cpp', 'tests/lel.cpp', diff --git a/tests/ecs_gui.cpp b/tests/guecs.cpp similarity index 92% rename from tests/ecs_gui.cpp rename to tests/guecs.cpp index 720c04b..c01c135 100644 --- a/tests/ecs_gui.cpp +++ b/tests/guecs.cpp @@ -1,12 +1,14 @@ #include #include #include "constants.hpp" -#include "ecs_gui.hpp" +#include "guecs.hpp" #include "texture.hpp" +using namespace guecs; TEST_CASE("prototype one gui", "[ecs-gui]") { - GUECS gui; + guecs::UI gui; + TexturePack textures; textures.load_sprites();