Event system now accepts any data and the GUI receives simpler events with data for them.

main
Zed A. Shaw 2 weeks ago
parent 0e79288afc
commit ed9d0de8e0
  1. 6
      dinkyecs.hpp
  2. 7
      events.hpp
  3. 35
      gui.cpp
  4. 4
      status.txt
  5. 31
      systems.cpp
  6. 2
      systems.hpp
  7. 15
      tests/dinkyecs.cpp

@ -18,6 +18,7 @@ namespace DinkyECS {
struct Event {
int event = 0;
Entity entity = 0;
std::any data;
};
typedef std::queue<Event> EventQueue;
@ -105,9 +106,9 @@ namespace DinkyECS {
}
template<typename Comp>
void send(Comp event, Entity entity) {
void send(Comp event, Entity entity, std::any data) {
EventQueue &queue = queue_map_for<Comp>();
queue.push({event, entity});
queue.push({event, entity, data});
}
template<typename Comp>
@ -115,6 +116,7 @@ namespace DinkyECS {
EventQueue &queue = queue_map_for<Comp>();
Event evt = queue.front();
queue.pop();
// I could use tie here to auto extract the any
return evt;
}

@ -2,6 +2,11 @@
namespace Events {
enum GUI {
START, HIT, MISS, DEAD, LOOT
START, COMBAT, LOOT
};
struct Combat {
int player_did;
int enemy_did;
};
}

@ -104,31 +104,30 @@ void GUI::handle_world_events() {
auto player = $world.get_the<Player>();
while($world.has_event<eGUI>()) {
auto [evt, entity] = $world.recv<eGUI>();
auto [evt, entity, data] = $world.recv<eGUI>();
switch(evt) {
case eGUI::HIT: {
auto combat = $world.get<Combat>(entity);
case eGUI::COMBAT: {
auto &damage = std::any_cast<Events::Combat&>(data);
auto enemy_combat = $world.get<Combat>(entity);
if(entity == player.entity) {
$log.log(format("Enemy HIT YOU, you have {} HP!", combat.hp));
if(damage.enemy_did > 0) {
$log.log(format("Enemy HIT YOU for {} damage!", damage.enemy_did));
$log.log(format("-- Enemy has {} HP left.", enemy_combat.hp));
$sounds.play("hit");
} else {
$log.log(format("You HIT enemy, they have {} HP!", combat.hp));
$sounds.play("hit");
$log.log("Enemy MISSED YOU.");
}
} break;
case eGUI::MISS:
if(entity == player.entity) {
$log.log("You MISSED the enemy.");
if(damage.player_did > 0) {
$log.log(format("You HIT enemy for {} damage!", damage.player_did));
$sounds.play("hit");
} else {
$log.log("Enemy MISSED YOU.");
$log.log("You MISSED the enemy.");
}
break;
case eGUI::DEAD:
$log.log("--- ENEMY DEAD!");
break;
} break;
case eGUI::LOOT: {
auto loot = $world.get<Loot>(entity);
auto &loot = std::any_cast<Loot&>(data);
auto inventory = $world.get<Inventory>(player.entity);
$log.log(format("You found {} gold. You have {} now.",
loot.amount, inventory.gold));
@ -182,7 +181,7 @@ void GUI::run_systems() {
auto player = $world.get_the<Player>();
System::enemy_pathing($world, $game_map, player);
System::motion($world, $game_map);
System::combat($world, player);
System::collision($world, player);
System::death($world);
}

@ -2,9 +2,7 @@ NOTES:
TODO:
* Event system could take additional data so that the events can be more coarse and simpler.
* Simplify the combat/collision system so that it's not a bunch of if-cases.
* Save file isn't saving gold.
* Inventory needs to be better, but need some kinds of "weapons" or other loot to get and not just gold.
* Run the ansi_parser on the whole UI so I can use colors and other glyphs.
* Create a few more enemy types to fight.

@ -91,7 +91,7 @@ void System::death(DinkyECS::World &world) {
});
}
void System::combat(DinkyECS::World &world, Player &player) {
void System::collision(DinkyECS::World &world, Player &player) {
auto& collider = world.get_the<spatial_map>();
const auto& player_position = world.get<Position>(player.entity);
auto& player_combat = world.get<Combat>(player.entity);
@ -100,36 +100,23 @@ void System::combat(DinkyECS::World &world, Player &player) {
auto [found, nearby] = collider.neighbors(player_position.location);
if(found) {
// save some keystrokes
using eGUI = Events::GUI;
for(auto entity : nearby) {
if(world.has<Combat>(entity)) {
auto& enemy_combat = world.get<Combat>(entity);
int player_dmg = player_combat.attack(enemy_combat);
if(player_dmg > 0) {
world.send<eGUI>(eGUI::HIT, entity);
} else {
world.send<eGUI>(eGUI::MISS, entity);
}
if(enemy_combat.hp > 0) {
int enemy_dmg = enemy_combat.attack(player_combat);
Events::Combat result {
player_combat.attack(enemy_combat),
enemy_combat.attack(player_combat)
};
if(enemy_dmg > 0) {
world.send<eGUI>(eGUI::HIT, player.entity);
} else {
world.send<eGUI>(eGUI::MISS, player.entity);
}
} else {
world.send<eGUI>(eGUI::DEAD, entity);
}
world.send<Events::GUI>(Events::GUI::COMBAT, entity, result);
} else if(world.has<Loot>(entity)) {
world.send<eGUI>(eGUI::LOOT, entity);
auto &loot = world.get<Loot>(entity);
auto loot = world.get<Loot>(entity);
auto &loot_pos = world.get<Position>(entity);
auto &inventory = world.get<Inventory>(player.entity);
world.send<Events::GUI>(Events::GUI::LOOT, entity, loot);
inventory.gold += loot.amount;
collider.remove(loot_pos.location);
} else {

@ -8,7 +8,7 @@ using namespace components;
namespace System {
void motion(DinkyECS::World &world, Map &game_map);
void combat(DinkyECS::World &world, Player &player);
void collision(DinkyECS::World &world, Player &player);
void death(DinkyECS::World &world);
void enemy_pathing(DinkyECS::World &world, Map &game_map, Player &player);
void draw_map(DinkyECS::World &world, Map &game_map, ftxui::Canvas &canvas, size_t view_x, size_t view_y);

@ -5,9 +5,10 @@
using namespace fmt;
using DinkyECS::Entity;
using std::string;
struct Player {
std::string name;
string name;
Entity eid;
};
@ -129,22 +130,18 @@ enum GUIEvent {
TEST_CASE("confirm that the event system works", "[ecs]") {
DinkyECS::World world;
DinkyECS::Entity gui_ent = world.entity();
DinkyECS::Entity player = world.entity();
GUIEvent gui{GUIEvent::HIT};
world.set<GUIEvent>(gui_ent, gui);
auto &gui_test = world.get<GUIEvent>(gui_ent);
REQUIRE(gui == gui_test);
world.send<GUIEvent>(GUIEvent::HIT, player);
world.send<GUIEvent>(GUIEvent::HIT, player, string{"hello"});
bool ready = world.has_event<GUIEvent>();
REQUIRE(ready == true);
auto [event, entity] = world.recv<GUIEvent>();
auto [event, entity, data] = world.recv<GUIEvent>();
REQUIRE(event == GUIEvent::HIT);
REQUIRE(entity == player);
auto &str_data = std::any_cast<string&>(data);
REQUIRE(string{"hello"} == str_data);
ready = world.has_event<GUIEvent>();
REQUIRE(ready == false);

Loading…
Cancel
Save