From 6a0087da183b62f97e37336bdbc1cb03e4acdde4 Mon Sep 17 00:00:00 2001 From: lisyarus Date: Tue, 20 Aug 2024 13:16:33 +0300 Subject: [PATCH] Add start menu --- source/application.cpp | 482 +++++++++++++++++++++++++++++------------ 1 file changed, 338 insertions(+), 144 deletions(-) diff --git a/source/application.cpp b/source/application.cpp index 14f13bd..414d293 100644 --- a/source/application.cpp +++ b/source/application.cpp @@ -373,7 +373,7 @@ namespace gmtk struct map { - ecs::container world; + std::unique_ptr world; util::hash_map cards = {}; @@ -547,11 +547,11 @@ namespace gmtk void clear_tile(map & map, location const & l) { - auto entity = map.world.index().find(l); + auto entity = map.world->index().find(l); if (!entity) return; - auto acc = map.world.get(*entity); + auto acc = map.world->get(*entity); if (acc.contains() || acc.contains()) return; @@ -572,7 +572,7 @@ namespace gmtk } } - auto & index = map.world.index(); + auto & index = map.world->index(); for (int y = 0; y < 9; ++y) { @@ -582,22 +582,22 @@ namespace gmtk if (auto e = index.find(p)) { - auto & v = map.world.get(*e).get(); + auto & v = map.world->get(*e).get(); for (auto to : v.belts_to) { - auto & tv = map.world.get(to).get(); + auto & tv = map.world->get(to).get(); if (!within_tile(l, tv.location)) - remove_belt(map.world, to, *tv.belts_to.begin()); - remove_belt(map.world, *e, to); + remove_belt(*map.world, to, *tv.belts_to.begin()); + remove_belt(*map.world, *e, to); } for (auto from : v.belts_from) { - auto & fv = map.world.get(from).get(); + auto & fv = map.world->get(from).get(); if (!within_tile(l, fv.location)) - remove_belt(map.world, *fv.belts_from.begin(), from); - remove_belt(map.world, from, *e); + remove_belt(*map.world, *fv.belts_from.begin(), from); + remove_belt(*map.world, from, *e); } } } @@ -608,17 +608,102 @@ namespace gmtk map.put_card(transformer_to_card(t->type)); } - map.world.destroy(*entity); + map.world->destroy(*entity); } - map starting_map() + map start_menu_map() { map result; - result.world.index(); - result.world.index(); + result.world = std::make_unique(); - result.world.create( + for (int y = 0; y < 3; ++y) + for (int x = 0; x < 3; ++x) + result.world->create( + vertex{0, {x, y}}, + zoomer{} + ); + + result.world->create( + vertex{0, {-1, 1}}, + source{{color_type::black, shape_type::circle}} + ); + + result.world->create( + vertex{0, {3, 1}}, + source{{color_type::black, shape_type::circle}} + ); + + result.world->create( + vertex{1, {1, 1}}, + source{{color_type::red, shape_type::circle}} + ); + + result.world->create( + vertex{1, {7, 7}}, + source{{color_type::yellow, shape_type::circle}} + ); + + result.world->create( + vertex{1, {1, 4}}, + transformer{transformer_type::hue_shifter} + ); + + result.world->create( + vertex{1, {7, 4}}, + transformer{transformer_type::hue_shifter} + ); + + result.world->create( + vertex{1, {1, 7}}, + lab{} + ); + + result.world->create( + vertex{1, {7, 1}}, + lab{} + ); + + auto & index = result.world->index(); + + // Left black to hue shifter + add_belt(*result.world, index.get({1, {-2, 4}}), index.get({1, {-1, 4}})); + add_belt(*result.world, index.get({1, {-1, 4}}), index.get({2, {0, 13}})); + add_belt(*result.world, index.get({2, {0, 13}}), index.get({2, {1, 13}})); + add_belt(*result.world, index.get({2, {1, 13}}), index.get({2, {2, 13}})); + add_belt(*result.world, index.get({2, {2, 13}}), index.get({2, {3, 13}})); + add_belt(*result.world, index.get({2, {3, 13}}), index.get({2, {4, 13}})); + + // Bottom-left red to hue shifter to left lab + add_belt(*result.world, index.get({1, {1, -2}}), index.get({1, {1, -1}})); + add_belt(*result.world, index.get({1, {1, -1}}), index.get({2, {4, 0}})); + add_belt(*result.world, index.get({2, {4, 0}}), index.get({2, {4, 1}})); + for (int y = 1; y < 22; ++y) + add_belt(*result.world, index.get({2, {4, y}}), index.get({2, {4, y + 1}})); + + add_belt(*result.world, index.get({1, {10, 4}}), index.get({1, {9, 4}})); + add_belt(*result.world, index.get({1, {9, 4}}), index.get({2, {26, 13}})); + add_belt(*result.world, index.get({2, {26, 13}}), index.get({2, {25, 13}})); + + for (int y = 4; y < 22; ++y) + add_belt(*result.world, index.get({2, {22, y + 1}}), index.get({2, {22, y}})); + + for (int x = 22; x < 25; ++x) + add_belt(*result.world, index.get({2, {x + 1, 13}}), index.get({2, {x, 13}})); + + return result; + } + + map capmaign_map() + { + map result; + + result.world = std::make_unique(); + + result.world->index(); + result.world->index(); + + result.world->create( vertex{{0, {1, -1}}}, lab{} ); @@ -968,7 +1053,7 @@ namespace gmtk { draw_grid({{{0.f, 3.f}, {0.f, 3.f}}}, view_level, painter); - map.world.apply([&](vertex const & v, zoomer const &) + map.world->apply([&](vertex const & v, zoomer const &) { draw_grid(v.location.bbox(), view_level, painter); }); @@ -976,13 +1061,13 @@ namespace gmtk void draw(map & map, gfx::painter & painter, float pixel_size) { - map.world.apply([&](vertex const & v, crossing const & c) + map.world->apply([&](vertex const & v, crossing const & c) { draw_structure(v.location.bbox(), c, painter); }); for (int i = 0; i < 2; ++i) - map.world.apply([&](path_vertex const & vertex) + map.world->apply([&](path_vertex const & vertex) { float w = (i == 0 ? 0.3f : 0.25f); float w0 = w * std::pow(3.f, 1.f - vertex.location.level); @@ -995,17 +1080,17 @@ namespace gmtk for (auto b : vertex.belts_to) { - auto q = map.world.get(b).get().location; + auto q = map.world->get(b).get().location; float w1 = w * std::pow(3.f, 1.f - q.level); painter.line(vertex.location.center(), q.center(), w0, w1, c, c, false); } }); - map.world.apply([&](path_vertex const & vertex) + map.world->apply([&](path_vertex const & vertex) { for (auto b : vertex.belts_to) { - auto q = map.world.get(b).get().location; + auto q = map.world->get(b).get().location; geom::vector d = q.center() - vertex.location.center(); @@ -1025,7 +1110,7 @@ namespace gmtk } }); - map.world.apply([&](vertex const & v, source const & s) + map.world->apply([&](vertex const & v, source const & s) { geom::vector shift{0.f, 0.f}; if (v.location.coords[0] < 0) @@ -1040,14 +1125,14 @@ namespace gmtk painter.rect(shift + v.location.bbox(-0.225f), color_of(s.type)); }); - map.world.apply([&](vertex const & v, transformer const & t) + map.world->apply([&](vertex const & v, transformer const & t) { auto box = v.location.bbox(); // box = geom::expand(box, 0.125f * animation_factor(t.animate) * box[0].length()); draw_structure(box, t, painter); }); - map.world.apply([&](vertex const & v, lab const & l) + map.world->apply([&](vertex const & v, lab const & l) { geom::vector shift{1.f, -1.f}; @@ -1068,9 +1153,9 @@ namespace gmtk painter.text(pen, std::format("{}/{}", map.resource_count, stages[map.stage].count), {.scale = {vs, -vs}, .c = {0, 0, 0, 255}}); }); - map.world.apply([&](item const & i) + map.world->apply([&](item const & i) { - draw_item(i.type, position(map.world, i), scale(map.world, i), painter); + draw_item(i.type, position(*map.world, i), scale(*map.world, i), painter); }); } @@ -1137,10 +1222,10 @@ namespace gmtk : seed_(make_seed()) , map_rng_{seed_, 0xf24130ddef6fb31full} , item_rng_{seed_, 0xb9fc3979f9860bbdull} - , map_(starting_map()) + , map_(start_menu_map()) { log::info() << "Starting seed: " << seed_; - view_stack_.push_back({-1, {0, 0}}); + set_start_menu(); } void on_event(app::resize_event const & event) override @@ -1150,38 +1235,41 @@ namespace gmtk void on_event(app::mouse_wheel_event const & event) override { - if (event.delta > 0) + if (!in_menu()) { - if (selected_ && !view_transition_) + if (event.delta > 0) { - bool transitioned = false; + if (selected_ && !view_transition_) + { + bool transitioned = false; - if (auto entity = map_.world.index().find(*selected_)) - if (map_.world.get(*entity).contains()) + if (auto entity = map_.world->index().find(*selected_)) + if (map_.world->get(*entity).contains()) + { + view_transition_ = {view_stack_.back()}; + view_stack_.push_back(*selected_); + selected_ = std::nullopt; + transitioned = true; + } + + if (!transitioned && within_grid(*selected_) && selected_->level == view_stack_.back().level + 1 && selected_->up() != view_stack_.back()) { view_transition_ = {view_stack_.back()}; - view_stack_.push_back(*selected_); + view_stack_.back() = selected_->up(); selected_ = std::nullopt; transitioned = true; } - - if (!transitioned && within_grid(*selected_) && selected_->level == view_stack_.back().level + 1 && selected_->up() != view_stack_.back()) - { - view_transition_ = {view_stack_.back()}; - view_stack_.back() = selected_->up(); - selected_ = std::nullopt; - transitioned = true; } } - } - if (event.delta < 0) - { - if (!view_transition_ && view_stack_.size() > 1) + if (event.delta < 0) { - view_transition_ = {view_stack_.back()}; - view_stack_.pop_back(); - selected_ = std::nullopt; + if (!view_transition_ && view_stack_.size() > 1) + { + view_transition_ = {view_stack_.back()}; + view_stack_.pop_back(); + selected_ = std::nullopt; + } } } } @@ -1195,9 +1283,14 @@ namespace gmtk { if (event.down && event.button == app::mouse_button::left) { - if (selected_ && active_card_) + if (selected_button_) { - if (auto entity = map_.world.index().find(*selected_)) + if (*selected_button_ < menu_buttons_.size() && menu_buttons_[*selected_button_].action) + menu_buttons_[*selected_button_].action(); + } + else if (selected_ && active_card_) + { + if (auto entity = map_.world->index().find(*selected_)) { if (*active_card_ == card_type::eraser) { @@ -1214,14 +1307,14 @@ namespace gmtk case card_type::mixer: case card_type::hue_shifter: case card_type::reshaper: - map_.world.create( + map_.world->create( vertex{*selected_}, transformer{card_to_transformer(*active_card_).value()} ); built = true; break; case card_type::crossing: - map_.world.create( + map_.world->create( vertex{*selected_}, crossing{} ); @@ -1229,17 +1322,17 @@ namespace gmtk break; case card_type::zoomer: { - map_.world.create( + map_.world->create( vertex{*selected_}, zoomer{} ); auto c = selected_->down(); - sink_belt(map_.world, c.left()); - sink_belt(map_.world, c.right()); - sink_belt(map_.world, c.bottom()); - sink_belt(map_.world, c.top()); + sink_belt(*map_.world, c.left()); + sink_belt(*map_.world, c.right()); + sink_belt(*map_.world, c.bottom()); + sink_belt(*map_.world, c.top()); built = true; } break; @@ -1281,10 +1374,10 @@ namespace gmtk location belt[4]; for (int i = 0; i <= 3; ++i) belt[i] = s.moved(d * i); - sink(map_.world, belt[0], belt[1]); - sink(map_.world, belt[3], belt[2]); + sink(*map_.world, belt[0], belt[1]); + sink(*map_.world, belt[3], belt[2]); - auto & index = map_.world.index(); + auto & index = map_.world->index(); for (int i = 0; i < 3; ++i) { auto p = belt[i]; @@ -1293,20 +1386,20 @@ namespace gmtk auto s = index.get(p); auto t = index.get(q); - auto & sv = map_.world.get(s).get(); + auto & sv = map_.world->get(s).get(); if (sv.belts_to.contains(t)) { - remove_belt(map_.world, s, t); + remove_belt(*map_.world, s, t); if (tutorial_state_ <= 1) tutorial_state_ = 2; } else { - if (remove_belt(map_.world, t, s)) + if (remove_belt(*map_.world, t, s)) if (tutorial_state_ <= 1) tutorial_state_ = 2; - add_belt(map_.world, s, t); + add_belt(*map_.world, s, t); } } @@ -1364,29 +1457,29 @@ namespace gmtk { map_.spawn_timer -= 1.f; - map_.world.apply( + map_.world->apply( [&](vertex const & v, source & s) { auto p = v.location.down(); - auto t = map_.world.index().get(p); + auto t = map_.world->index().get(p); - if (!map_.world.get(t).contains()) + if (!map_.world->get(t).contains()) { - if (!map_.world.get(t).get().belts_to.empty()) + if (!map_.world->get(t).get().belts_to.empty()) s.animate += 1.f; - auto i = map_.world.create( + auto i = map_.world->create( item{s.type, p} ); - map_.world.attach(t, occupied{i}); + map_.world->attach(t, occupied{i}); } } ); } - if (map_.stage + 1 < std::size(stages) && map_.resource_count >= stages[map_.stage].count) + if (!in_menu() && map_.stage + 1 < std::size(stages) && map_.resource_count >= stages[map_.stage].count) { for (auto card : stages[map_.stage].cards) map_.cards[card] += 1; @@ -1397,7 +1490,7 @@ namespace gmtk auto add = [&](location l) { - if (!map_.world.index().find(l)) + if (!map_.world->index().find(l)) spots.insert(l); }; @@ -1416,7 +1509,7 @@ namespace gmtk if (!spots.empty()) { - map_.world.create( + map_.world->create( vertex{random::uniform_from(map_rng_, spots)}, source{type} ); @@ -1430,23 +1523,23 @@ namespace gmtk tutorial_state_ = 3; } - map_.world.apply([&](vertex const & v, transformer & t) + map_.world->apply([&](vertex const & v, transformer & t) { boost::container::flat_multimap has_inputs; auto c = v.location.down(); - auto ce = map_.world.index().get(c); + auto ce = map_.world->index().get(c); - if (map_.world.get(ce).contains()) + if (map_.world->get(ce).contains()) return; for (auto n : neighbours) { auto p = c.moved(n); - if (auto ne = map_.world.index().find(p)) - if (map_.world.get(*ne).get().belts_to.contains(ce)) - if (auto occ = map_.world.get(*ne).get_if()) - if (auto i = map_.world.get(occ->entity).get_if()) + if (auto ne = map_.world->index().find(p)) + if (map_.world->get(*ne).get().belts_to.contains(ce)) + if (auto occ = map_.world->get(*ne).get_if()) + if (auto i = map_.world->get(occ->entity).get_if()) if (i->start == p) has_inputs.insert({i->type, p}); } @@ -1476,21 +1569,21 @@ namespace gmtk for (int i = 0; i < recipe.inputs.count(type); ++i) { auto l = it->second; - auto e = map_.world.index().get(l); - auto re = map_.world.get(e).get().entity; + auto e = map_.world->index().get(l); + auto re = map_.world->get(e).get().entity; - map_.world.detach(e); - map_.world.destroy(re); + map_.world->detach(e); + map_.world->destroy(re); ++it; } } - auto r = map_.world.create( + auto r = map_.world->create( item{recipe.output, c} ); - map_.world.attach(ce, occupied{r}); + map_.world->attach(ce, occupied{r}); crafted = true; @@ -1506,16 +1599,16 @@ namespace gmtk } }); - map_.world.apply([&](ecs::handle entity, item & i) + map_.world->apply([&](ecs::handle entity, item & i) { if (i.target) { { - auto & v = map_.world.get(i.target).get(); + auto & v = map_.world->get(i.target).get(); if (v.belts_from.empty() && v.belts_to.empty()) { - map_.world.detach(i.target); - map_.world.destroy(entity); + map_.world->detach(i.target); + map_.world->destroy(entity); return; } } @@ -1526,76 +1619,76 @@ namespace gmtk i.state -= 1.f; - i.start = map_.world.get(i.target).get().location; - map_.world.detach(i.target); + i.start = map_.world->get(i.target).get().location; + map_.world->detach(i.target); i.target = ecs::handle::null(); } else { - auto s = map_.world.index().get(i.start); - map_.world.detach(s); + auto s = map_.world->index().get(i.start); + map_.world->detach(s); - auto & v = map_.world.get(s).get(); + auto & v = map_.world->get(s).get(); if (v.belts_to.empty() && v.belts_from.empty()) { - map_.world.destroy(entity); + map_.world->destroy(entity); return; } } - if (auto cell = map_.world.index().find(i.start.up())) + if (auto cell = map_.world->index().find(i.start.up())) { - if (auto l = map_.world.get(*cell).get_if()) + if (auto l = map_.world->get(*cell).get_if()) { if (i.type == stages[map_.stage].type) { map_.resource_count += 1; l->animate += 1.f; - map_.world.destroy(entity); + map_.world->destroy(entity); } else { l->animate_error += 1.f; - map_.world.destroy(entity); + map_.world->destroy(entity); } return; } - if (map_.world.get(*cell).contains()) + if (map_.world->get(*cell).contains()) { auto c = i.start.up().down(); auto d = c.coords - i.start.coords; auto n = c.moved(d); - auto & index = map_.world.index(); + auto & index = map_.world->index(); auto se = index.get(i.start); auto ce = index.get(c); auto ne = index.get(n); - if (map_.world.get(se).get().belts_to.contains(ce)) + if (map_.world->get(se).get().belts_to.contains(ce)) { - if (map_.world.get(ce).get().belts_to.contains(ne) && !map_.world.get(ne).contains()) + if (map_.world->get(ce).get().belts_to.contains(ne) && !map_.world->get(ne).contains()) { i.target = ne; - map_.world.attach(ne, occupied{entity}); + map_.world->attach(ne, occupied{entity}); } else { - map_.world.attach(se, occupied{entity}); + map_.world->attach(se, occupied{entity}); } return; } } - if (map_.world.get(*cell).get_if()) + if (map_.world->get(*cell).get_if()) { - auto se = map_.world.index().get(i.start); - auto ce = map_.world.index().get(i.start.up().down()); + auto se = map_.world->index().get(i.start); + auto ce = map_.world->index().get(i.start.up().down()); - if (map_.world.get(se).get().belts_to.contains(ce)) + if (map_.world->get(se).get().belts_to.contains(ce)) { - map_.world.attach(map_.world.index().get(i.start), occupied{entity}); + map_.world->attach(map_.world->index().get(i.start), occupied{entity}); return; } } @@ -1603,30 +1696,30 @@ namespace gmtk std::vector targets; - for (auto b : map_.world.get(map_.world.index().get(i.start)).get().belts_to) - if (!map_.world.get(b).contains()) + for (auto b : map_.world->get(map_.world->index().get(i.start)).get().belts_to) + if (!map_.world->get(b).contains()) targets.push_back(b); if (!targets.empty()) i.target = random::uniform_from(item_rng_, targets); if (i.target) - map_.world.attach(i.target, occupied{entity}); + map_.world->attach(i.target, occupied{entity}); else - map_.world.attach(map_.world.index().get(i.start), occupied{entity}); + map_.world->attach(map_.world->index().get(i.start), occupied{entity}); }); - map_.world.apply([&](source & s) + map_.world->apply([&](source & s) { s.animate = std::max(0.f, s.animate - 3.f * dt); }); - map_.world.apply([&](transformer & t) + map_.world->apply([&](transformer & t) { t.animate = std::max(0.f, t.animate - 3.f * dt); }); - map_.world.apply([&](lab & l) + map_.world->apply([&](lab & l) { l.animate = std::max(0.f, l.animate - 3.f * dt); l.animate_error = std::max(0.f, l.animate_error - 3.f * dt); @@ -1665,24 +1758,24 @@ namespace gmtk selected_ = std::nullopt; selected_item_ = std::nullopt; - if (!view_transition_) + if (!in_menu() && !view_transition_) { if (geom::contains(geom::shrink(view_box_[0], (view_box_[0].length() - view_box_[1].length()) / 2.f), mouse_world_[0])) - map_.world.apply([&](ecs::handle entity, item const & i) + map_.world->apply([&](ecs::handle entity, item const & i) { - auto box = geom::expand(geom::box::singleton(position(map_.world, i)), scale(map_.world, i) / 9.f); + auto box = geom::expand(geom::box::singleton(position(*map_.world, i)), scale(*map_.world, i) / 9.f); if (geom::contains(box, mouse_world_)) selected_item_ = entity; }); if (selected_item_ && item_killing_spree_) { - auto const & i = map_.world.get(*selected_item_).get(); + auto const & i = map_.world->get(*selected_item_).get(); if (i.target) - map_.world.detach(i.target); + map_.world->detach(i.target); else - map_.world.detach(map_.world.index().get(i.start)); - map_.world.destroy(*selected_item_); + map_.world->detach(map_.world->index().get(i.start)); + map_.world->destroy(*selected_item_); selected_item_ = std::nullopt; } @@ -1710,8 +1803,8 @@ namespace gmtk selected_ = p; while (selected_->level > 0) { - if (auto entity = map_.world.index().find(p.up())) - if (map_.world.get(*entity).contains()) + if (auto entity = map_.world->index().find(p.up())) + if (map_.world->get(*entity).contains()) break; selected_ = std::nullopt; @@ -1722,7 +1815,7 @@ namespace gmtk } } else if (!within_grid(p)) - if (auto entity = map_.world.index().find(p)) + if (auto entity = map_.world->index().find(p)) selected_ = p; } } @@ -1732,6 +1825,13 @@ namespace gmtk float const target = p.first == active_card_; p.second += (target - p.second) * (- std::expm1(- 20.f * dt)); } + + menu_transition_ += ((in_menu() ? 1.f : 0.f) - menu_transition_) * (- std::expm1(- 20.f * dt)); + + for (int i = 0; i < menu_buttons_.size(); ++i) + { + menu_buttons_[i].selected_state += ((selected_button_ == i ? 1.f : 0.f) - menu_buttons_[i].selected_state) * (- std::expm1(- 20.f * dt)); + } } void present() override @@ -1756,9 +1856,9 @@ namespace gmtk { if (selected_) { - if (auto entity = map_.world.index().find(*selected_)) + if (auto entity = map_.world->index().find(*selected_)) { - auto acc = map_.world.get(*entity); + auto acc = map_.world->get(*entity); if (*active_card_ != card_type::eraser || (!acc.contains() && !acc.contains())) { gfx::color_rgba color = {255, 128, 128, 255}; @@ -1795,14 +1895,14 @@ namespace gmtk location p0 = belt_start_->down(); location p1 = p0.moved(d); - sink(map_.world, p0, p1); + sink(*map_.world, p0, p1); - auto e0 = map_.world.index().get(p0); - auto e1 = map_.world.index().get(p1); + auto e0 = map_.world->index().get(p0); + auto e1 = map_.world->index().get(p1); - if (map_.world.get(e0).get().belts_to.contains(e1)) + if (map_.world->get(e0).get().belts_to.contains(e1)) c = {244, 160, 160, 255}; - else if (map_.world.get(e0).get().belts_from.contains(e1)) + else if (map_.world->get(e0).get().belts_from.contains(e1)) c = {244, 244, 160, 255}; float w = 0.25f * std::pow(3.f, 1.f - selected_->level) / 2.f; @@ -1815,8 +1915,9 @@ namespace gmtk draw_selection(belt_start_->bbox(), painter_, {64, 64, 64, 255}); } - draw(map_, painter_, pixel_size); + draw(map_, painter_, in_start_menu_ ? 0.f : pixel_size); + if (!in_menu()) { float w = (view_box_[0].length() - view_box_[1].length()) / 2.f; geom::vector t{view_box_[1].length() / 5.f, 0.f}; @@ -1862,8 +1963,8 @@ namespace gmtk if (selected_item_) { - auto const & i = map_.world.get(*selected_item_).get(); - draw_item(i.type, position(map_.world, i), scale(map_.world, i), painter_, true); + auto const & i = map_.world->get(*selected_item_).get(); + draw_item(i.type, position(*map_.world, i), scale(*map_.world, i), painter_, true); } std::optional shown_recipies; @@ -1875,8 +1976,8 @@ namespace gmtk } else if (selected_) { - if (auto entity = map_.world.index().find(*selected_)) - if (auto t = map_.world.get(*entity).get_if()) + if (auto entity = map_.world->index().find(*selected_)) + if (auto t = map_.world->get(*entity).get_if()) shown_recipies = t->type; } @@ -1955,9 +2056,9 @@ namespace gmtk if (selected_card_ || active_card_) helper_text = card_description(selected_card_.value_or(*active_card_)); else if (selected_) - if (auto entity = map_.world.index().find(*selected_)) + if (auto entity = map_.world->index().find(*selected_)) { - auto acc = map_.world.get(*entity); + auto acc = map_.world->get(*entity); if (auto t = acc.get_if()) helper_text = card_description(transformer_to_card(t->type)); else if (acc.contains()) @@ -1970,7 +2071,7 @@ namespace gmtk helper_text = {"Consumer", "Consumes produced items"}; } - if (helper_text.empty()) + if (!in_menu() && helper_text.empty()) { if (tutorial_state_ == 0) { @@ -2015,12 +2116,105 @@ namespace gmtk } } + selected_button_ = std::nullopt; + + if (in_menu()) + { + painter_.rect(view_box_, gfx::to_coloru8(gfx::color_4f{1.f, 1.f, 1.f, menu_transition_ * 0.5f})); + + float button_width = pixel_size * 500.f; + float button_height = pixel_size * 64.f; + float button_spacing = pixel_size * 32.f; + + float total_height = button_height * menu_buttons_.size() + button_spacing * (menu_buttons_.size() - 1.f); + + auto pen = view_box_.center() + geom::vector{-button_width, total_height} / 2.f; + + for (int i = 0; i < menu_buttons_.size(); ++i) + { + geom::box box; + box[0] = {pen[0], pen[0] + button_width}; + box[1] = {pen[1] - button_height, pen[1]}; + + box = geom::expand(box, menu_buttons_[i].selected_state * 8.f * pixel_size); + + if (geom::contains(box, mouse_world_)) + selected_button_ = i; + + auto text_color = gfx::lerp(gfx::black.as_color_rgba(), gfx::color_rgba{191, 96, 0, 255}, menu_buttons_[i].selected_state); + + painter_.rect(geom::expand(box, pixel_size * 5.f), text_color); + painter_.rect(box, gfx::lerp(gfx::color_rgba{192, 192, 192, 255}, gfx::white.as_color_rgba(), menu_buttons_[i].selected_state)); + + float s = pixel_size * 4.f; + + painter_.text(box.center(), menu_buttons_[i].text, {.scale = {s, -s}, .c = text_color}); + + pen[1] -= button_height; + pen[1] -= button_spacing; + } + } + painter_.render(geom::orthographic_camera{view_box_}.transform()); } private: bool running_ = true; + bool in_start_menu_ = true; + + float menu_transition_ = 1.f; + + struct button + { + std::string text; + std::function action; + float selected_state = 0.f; + }; + + std::vector