DinkyECS is now controlling the game and can handle multiple enemies easily. Next is to clean this up so it's not just one gross pile of code in the gui.
This commit is contained in:
parent
86c98c43c2
commit
33327154ad
9 changed files with 195 additions and 149 deletions
153
gui.cpp
153
gui.cpp
|
@ -25,6 +25,32 @@ using namespace fmt;
|
|||
using namespace std::chrono_literals;
|
||||
using namespace ftxui;
|
||||
|
||||
struct Player {
|
||||
DinkyECS::Entity entity;
|
||||
};
|
||||
|
||||
struct Position {
|
||||
Point location;
|
||||
};
|
||||
|
||||
struct Motion {
|
||||
int dx;
|
||||
int dy;
|
||||
};
|
||||
|
||||
struct Combat {
|
||||
int hp;
|
||||
int damage;
|
||||
};
|
||||
|
||||
struct Treasure {
|
||||
int amount;
|
||||
};
|
||||
|
||||
struct Tile {
|
||||
std::string chr = "!";
|
||||
};
|
||||
|
||||
std::array<sf::Color, 10> VALUES{
|
||||
sf::Color{1, 4, 2}, // black
|
||||
sf::Color{9, 29, 16}, // dark dark
|
||||
|
@ -69,22 +95,18 @@ GUI::GUI() : $game_map(GAME_MAP_X, GAME_MAP_Y),
|
|||
$map_text.setFillColor(color(Value::MID));
|
||||
|
||||
$game_map.generate();
|
||||
$player.location = $game_map.place_entity(0);
|
||||
$enemy.location = $game_map.place_entity(1);
|
||||
$goal = $game_map.place_entity($game_map.room_count() - 1);
|
||||
}
|
||||
|
||||
void GUI::create_renderer() {
|
||||
$map_view = Renderer([&] {
|
||||
auto player = $world.get<Player>();
|
||||
|
||||
$map_view = Renderer([&, player] {
|
||||
const auto& player_position = $world.component<Position>(player.entity);
|
||||
Matrix &walls = $game_map.walls();
|
||||
$game_map.set_target($player.location);
|
||||
$game_map.set_target(player_position.location);
|
||||
$game_map.make_paths();
|
||||
Matrix &paths = $game_map.paths();
|
||||
|
||||
if($player.in_state(EntityState::DEAD)) {
|
||||
$status_text = "DEAD!";
|
||||
}
|
||||
|
||||
for(size_t x = 0; x < walls[0].size(); ++x) {
|
||||
for(size_t y = 0; y < walls.size(); ++y) {
|
||||
string tile = walls[y][x] == 1 ? WALL_TILE : format("{}", paths[y][x]);
|
||||
|
@ -99,18 +121,19 @@ void GUI::create_renderer() {
|
|||
}
|
||||
}
|
||||
|
||||
$canvas.DrawText($enemy.location.x*2, $enemy.location.y*4, ENEMY_TILE);
|
||||
$canvas.DrawText($player.location.x*2, $player.location.y*4, PLAYER_TILE);
|
||||
$canvas.DrawText($goal.x*2, $goal.y*4, "$");
|
||||
$world.system<Position, Tile>([&](const auto &ent, auto &pos, auto &tile) {
|
||||
$canvas.DrawText(pos.location.x*2, pos.location.y*4, tile.chr);
|
||||
});
|
||||
|
||||
return canvas($canvas);
|
||||
});
|
||||
|
||||
$document = Renderer([&]{
|
||||
$document = Renderer([&, player]{
|
||||
const auto& player_combat = $world.component<Combat>(player.entity);
|
||||
return hbox({
|
||||
hflow(
|
||||
vbox(
|
||||
text(format("HP: {}", $player.hp)) | border,
|
||||
text(format("HP: {}", player_combat.hp)) | border,
|
||||
text($status_text) | border
|
||||
) | xflex_grow
|
||||
),
|
||||
|
@ -122,46 +145,61 @@ void GUI::create_renderer() {
|
|||
|
||||
void GUI::handle_events() {
|
||||
sf::Event event;
|
||||
auto player = $world.get<Player>();
|
||||
auto& player_motion = $world.component<Motion>(player.entity);
|
||||
|
||||
while($window.pollEvent(event)) {
|
||||
if(event.type == sf::Event::Closed) {
|
||||
$window.close();
|
||||
} else if(event.type == sf::Event::KeyPressed) {
|
||||
size_t x = $player.location.x;
|
||||
size_t y = $player.location.y;
|
||||
|
||||
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Left)) {
|
||||
x -= 1;
|
||||
player_motion.dx = -1;
|
||||
} else if(sf::Keyboard::isKeyPressed(sf::Keyboard::Right)) {
|
||||
x += 1;
|
||||
player_motion.dx = 1;
|
||||
} else if(sf::Keyboard::isKeyPressed(sf::Keyboard::Up)) {
|
||||
y -= 1;
|
||||
player_motion.dy = -1;
|
||||
} else if(sf::Keyboard::isKeyPressed(sf::Keyboard::Down)) {
|
||||
y += 1;
|
||||
player_motion.dy = 1;
|
||||
}
|
||||
|
||||
if($game_map.inmap(x,y) && !$game_map.iswall(x,y)) {
|
||||
$game_map.clear_target($player.location);
|
||||
$player.move({x, y});
|
||||
} else {
|
||||
$shake_it = true;
|
||||
$hit_sound.play();
|
||||
}
|
||||
// COMPOSE system? You create a bunch of callbacks and then combine them into
|
||||
// a single run over the data?
|
||||
|
||||
// move $enemy here
|
||||
// BUG: when the enemy has no path it goes through walls, which means
|
||||
// this neighbors function is not working right. Probably updating
|
||||
// enemy.location in an out parameter isn't the best idea.
|
||||
bool found = $game_map.neighbors($enemy.location, true);
|
||||
if(!found) {
|
||||
$status_text = "ENEMY STUCK!";
|
||||
}
|
||||
// move enemies system
|
||||
$world.system<Position, Motion>([&](const auto &ent, auto &position, auto &motion) {
|
||||
if(ent != player.entity) {
|
||||
Point out = position.location;
|
||||
$game_map.neighbors(out, false);
|
||||
motion = { int(out.x - position.location.x), int(out.y - position.location.y)};
|
||||
}
|
||||
});
|
||||
|
||||
if($enemy.location.x == $player.location.x && $enemy.location.y == $player.location.y) {
|
||||
$player.event(EntityEvent::HIT);
|
||||
$burn_baby_burn = true;
|
||||
} else if($goal.x == $player.location.x && $goal.y == $player.location.y) {
|
||||
$status_text = "YOU WIN!";
|
||||
}
|
||||
// motion system
|
||||
$world.system<Position, Motion>([&](const auto &ent, auto &position, auto &motion) {
|
||||
Point move_to = {
|
||||
position.location.x + motion.dx,
|
||||
position.location.y + motion.dy
|
||||
};
|
||||
motion = {0,0}; // clear it after getting it
|
||||
|
||||
if($game_map.inmap(move_to.x, move_to.y) && !$game_map.iswall(move_to.x,move_to.y)) {
|
||||
$game_map.clear_target(position.location);
|
||||
position.location = move_to;
|
||||
}
|
||||
});
|
||||
|
||||
// combat system
|
||||
auto combatSystem = [&]() {
|
||||
const auto& player_position = $world.component<Position>(player.entity);
|
||||
$world.system<Position, Combat>([&](const auto &ent, auto &pos, auto &combat) {
|
||||
if(ent != player.entity && pos.location.x == player_position.location.x &&
|
||||
pos.location.y == player_position.location.y) {
|
||||
$burn_baby_burn = true;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
combatSystem();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -187,6 +225,7 @@ void GUI::draw_screen(bool clear, float map_off_x, float map_off_y) {
|
|||
}
|
||||
|
||||
void GUI::shake() {
|
||||
$hit_sound.play();
|
||||
for(int i = 0; i < 10; ++i) {
|
||||
int x = Random::uniform<int>(-10,10);
|
||||
int y = Random::uniform<int>(-10,10);
|
||||
|
@ -196,6 +235,35 @@ void GUI::shake() {
|
|||
}
|
||||
}
|
||||
|
||||
void GUI::configure_world() {
|
||||
dbc::check($game_map.room_count() > 1, "not enough rooms in map.");
|
||||
// configure a player as a fact of the world
|
||||
Player player{$world.entity()};
|
||||
$world.set<Player>(player);
|
||||
|
||||
$world.assign<Position>(player.entity, {$game_map.place_entity(0)});
|
||||
$world.assign<Motion>(player.entity, {0, 0});
|
||||
$world.assign<Combat>(player.entity, {100, 10});
|
||||
$world.assign<Tile>(player.entity, {PLAYER_TILE});
|
||||
|
||||
auto enemy = $world.entity();
|
||||
$world.assign<Position>(enemy, {$game_map.place_entity(1)});
|
||||
$world.assign<Motion>(enemy, {0,0});
|
||||
$world.assign<Combat>(enemy, {20, 10});
|
||||
$world.assign<Tile>(enemy, {ENEMY_TILE});
|
||||
|
||||
auto enemy2 = $world.entity();
|
||||
$world.assign<Position>(enemy2, {$game_map.place_entity(2)});
|
||||
$world.assign<Motion>(enemy2, {0,0});
|
||||
$world.assign<Combat>(enemy2, {20, 10});
|
||||
$world.assign<Tile>(enemy2, {"*"});
|
||||
|
||||
auto gold = $world.entity();
|
||||
$world.assign<Position>(gold, {$game_map.place_entity($game_map.room_count() - 1)});
|
||||
$world.assign<Treasure>(gold, {100});
|
||||
$world.assign<Tile>(gold, {"$"});
|
||||
}
|
||||
|
||||
void GUI::render_scene() {
|
||||
Render($map_screen, $map_view->Render());
|
||||
Render($screen, $document->Render());
|
||||
|
@ -222,6 +290,7 @@ void GUI::render_scene() {
|
|||
}
|
||||
|
||||
int GUI::main() {
|
||||
configure_world();
|
||||
create_renderer();
|
||||
|
||||
while($window.isOpen()) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue