From 8953b56970336bd96bf7f373ee35f811781c26a0 Mon Sep 17 00:00:00 2001 From: lisyarus Date: Mon, 19 Aug 2024 16:11:04 +0300 Subject: [PATCH] Mouse-based cards UI --- source/application.cpp | 345 +++++++++++++++++++++++++---------------- 1 file changed, 211 insertions(+), 134 deletions(-) diff --git a/source/application.cpp b/source/application.cpp index f9fc356..552de59 100644 --- a/source/application.cpp +++ b/source/application.cpp @@ -67,11 +67,12 @@ namespace gmtk ) psemek_declare_enum(card_type, std::uint32_t, - (crossing) (mixer) (square_maker) (hue_shifter) + (crossing) (zoomer) + (eraser) ) gfx::color_rgba color_of(color_type c) @@ -340,6 +341,9 @@ namespace gmtk bool take_card(card_type type) { + if (type == card_type::eraser) + return true; + if (!cards.contains(type)) return false; @@ -580,6 +584,8 @@ namespace gmtk lab{} ); + result.cards[card_type::eraser] = 1; + return result; } @@ -700,6 +706,18 @@ namespace gmtk case card_type::zoomer: draw_grid(bbox, -1.f, painter, true); break; + case card_type::eraser: + { + float const w = 0.075f * bbox[0].length(); + + float s = 0.2f; + float t = 0.8f; + + gfx::color_rgba color = {255, 128, 128, 255}; + painter.line(bbox.corner(s, s), bbox.corner(t, t), w, color); + painter.line(bbox.corner(t, s), bbox.corner(s, t), w, color); + } + break; } } @@ -797,10 +815,9 @@ namespace gmtk }); } - void draw_selection(location const & l, gfx::painter & painter, gfx::color_rgba const & color, bool solid = false) + void draw_selection(geom::box const & b, gfx::painter & painter, gfx::color_rgba const & color, bool solid = false) { - auto b = l.bbox(); - float w = std::pow(3.f, -l.level) * 0.05f; + float w = b[0].length() * 0.05f; if (solid) { @@ -898,13 +915,72 @@ namespace gmtk { if (event.down && event.button == app::mouse_button::left) { - if (selected_item_) - item_killing_spree_ = true; - - if (!selected_item_ && selected_ && !belt_start_) + if (selected_ && active_card_) { - belt_start_ = *selected_; + if (auto entity = map_.world.index().find(*selected_)) + { + if (*active_card_ == card_type::eraser) + { + clear_tile(map_, *selected_); + } + } + else + { + if (map_.take_card(*active_card_)) + { + switch (*active_card_) + { + case card_type::mixer: + map_.world.create( + vertex{*selected_}, + transformer{transformer_type::mixer} + ); + break; + case card_type::hue_shifter: + map_.world.create( + vertex{*selected_}, + transformer{transformer_type::hue_shifter} + ); + break; + case card_type::square_maker: + map_.world.create( + vertex{*selected_}, + transformer{transformer_type::square_maker} + ); + break; + case card_type::crossing: + map_.world.create( + vertex{*selected_}, + crossing{} + ); + break; + case card_type::zoomer: + { + 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()); + } + break; + case card_type::eraser: + break; + } + } + } } + else if (selected_card_) + active_card_ = *selected_card_; + else if (selected_item_) + item_killing_spree_ = true; + else if (selected_ && !belt_start_) + belt_start_ = *selected_; } if (!event.down && event.button == app::mouse_button::left) @@ -947,6 +1023,9 @@ namespace gmtk } belt_start_ = std::nullopt; } + + if (event.down && event.button == app::mouse_button::right) + active_card_ = std::nullopt; } void on_event(app::key_event const & event) override @@ -956,83 +1035,6 @@ namespace gmtk for (auto type : card_type_values()) map_.cards[type] += 10; } - - if (event.down && event.key == app::keycode::F) - { - if (selected_ && !map_.world.index().find(*selected_)) - { - if (map_.take_card(card_type::mixer)) - map_.world.create( - vertex{*selected_}, - transformer{transformer_type::mixer} - ); - } - } - - if (event.down && event.key == app::keycode::G) - { - if (selected_ && !map_.world.index().find(*selected_)) - { - if (map_.take_card(card_type::hue_shifter)) - map_.world.create( - vertex{*selected_}, - transformer{transformer_type::hue_shifter} - ); - } - } - - if (event.down && event.key == app::keycode::H) - { - if (selected_ && !map_.world.index().find(*selected_)) - { - if (map_.take_card(card_type::square_maker)) - map_.world.create( - vertex{*selected_}, - transformer{transformer_type::square_maker} - ); - } - } - - if (event.down && event.key == app::keycode::T) - { - if (selected_ && !map_.world.index().find(*selected_)) - { - if (map_.take_card(card_type::crossing)) - map_.world.create( - vertex{*selected_}, - crossing{} - ); - } - } - - if (event.down && event.key == app::keycode::Z) - { - if (selected_ && !map_.world.index().find(*selected_)) - { - if (map_.take_card(card_type::zoomer)) - { - 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()); - } - } - } - - if (event.down && event.key == app::keycode::X) - { - if (selected_) - { - clear_tile(map_, *selected_); - } - } } bool running() const override @@ -1300,20 +1302,20 @@ namespace gmtk view_box_[0] = geom::expand(view_box_[0], (view_box_[1].length() * aspect_ratio - view_box_[0].length()) / 2.f); + mouse_world_ = view_box_.corner( + mouse_[0] * 1.f / screen_size_[0], + 1.f - mouse_[1] * 1.f / screen_size_[1] + ); + selected_ = std::nullopt; selected_item_ = std::nullopt; if (!view_transition_) { - auto m = view_box_.corner( - mouse_[0] * 1.f / screen_size_[0], - 1.f - mouse_[1] * 1.f / screen_size_[1] - ); - 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); - if (geom::contains(box, m)) + if (geom::contains(box, mouse_world_)) selected_item_ = entity; }); @@ -1331,6 +1333,8 @@ namespace gmtk { float s = std::pow(3.f, 1 + view_stack_.back().level); + auto m = mouse_world_; + m[0] *= s; m[1] *= s; @@ -1366,6 +1370,12 @@ namespace gmtk selected_ = p; } } + + for (auto & p : card_animation_) + { + float const target = p.first == active_card_; + p.second += (target - p.second) * (- std::expm1(- 20.f * dt)); + } } void present() override @@ -1383,20 +1393,39 @@ namespace gmtk draw_grids(map_, view_level, painter_); - if (selected_) + if (active_card_) { - gfx::color_rgba color = {128, 128, 128, 255}; - if (belt_start_) + if (selected_) { - auto d = selected_->coords - belt_start_->coords; - if (selected_->level != belt_start_->level || std::abs(d[0]) + std::abs(d[1]) != 1) - color = {255, 128, 128, 255}; + if (map_.world.index().find(*selected_)) + { + gfx::color_rgba color = {255, 128, 128, 255}; + draw_selection(selected_->bbox(), painter_, color, true); + } + else if (*active_card_ != card_type::eraser) + { + gfx::color_rgba color = {64, 64, 64, 255}; + draw_selection(selected_->bbox(), painter_, color, true); + } } - draw_selection(*selected_, painter_, color); } + else + { + if (selected_) + { + gfx::color_rgba color = {128, 128, 128, 255}; + if (belt_start_) + { + auto d = selected_->coords - belt_start_->coords; + if (selected_->level != belt_start_->level || std::abs(d[0]) + std::abs(d[1]) != 1) + color = {255, 128, 128, 255}; + } + draw_selection(selected_->bbox(), painter_, color); + } - if (belt_start_) - draw_selection(*belt_start_, painter_, {64, 64, 64, 255}); + if (belt_start_) + draw_selection(belt_start_->bbox(), painter_, {64, 64, 64, 255}); + } draw(map_, painter_); @@ -1433,56 +1462,99 @@ namespace gmtk draw_item(i.type, position(map_.world, i), scale(map_.world, i), painter_, true); } - if (selected_) + std::optional shown_recipies; + + if (selected_card_ || active_card_) + { + switch (selected_card_.value_or(*active_card_)) + { + case card_type::crossing: + case card_type::zoomer: + case card_type::eraser: + break; + case card_type::mixer: + shown_recipies = transformer_type::mixer; + break; + case card_type::hue_shifter: + shown_recipies = transformer_type::hue_shifter; + break; + case card_type::square_maker: + shown_recipies = transformer_type::square_maker; + break; + } + } + else if (selected_) + { if (auto entity = map_.world.index().find(*selected_)) if (auto t = map_.world.get(*entity).get_if()) + shown_recipies = t->type; + } + + if (shown_recipies) + { + float const scale = std::pow(3.f, -1.f - view_level); + float const step = 1.5f * scale / 9.f; + + geom::point pen = view_box_.corner(0, 1) + geom::vector{1.f, -1.f} * view_box_[1].length() / 10.f; + for (auto const & recipe : recipies.at(*shown_recipies)) + { + int i = 0; + for (auto type : recipe.inputs) { - float const scale = std::pow(3.f, -1.f - view_level); - float const step = 1.5f * scale / 9.f; - - geom::point pen = view_box_.corner(0, 1) + geom::vector{1.f, -1.f} * view_box_[1].length() / 10.f; - for (auto const & recipe : recipies.at(t->type)) - { - int i = 0; - for (auto type : recipe.inputs) - { - draw_item(type, pen + geom::vector{i * step, 0.f}, scale, painter_); - ++i; - } - - i = 3; - painter_.triangle( - pen + geom::vector{(i - 0.4f) * step, -0.4f * step}, - pen + geom::vector{(i - 0.4f) * step, 0.4f * step}, - pen + geom::vector{(i + 0.4f) * step, 0.f}, - {127, 127, 127, 255} - ); - - i = 4; - draw_item(recipe.output, pen + geom::vector{i * step, 0.f}, scale, painter_); - - pen[1] -= step; - } + draw_item(type, pen + geom::vector{i * step, 0.f}, scale, painter_); + ++i; } + i = 3; + painter_.triangle( + pen + geom::vector{(i - 0.25f) * step, -0.25f * step}, + pen + geom::vector{(i - 0.25f) * step, 0.25f * step}, + pen + geom::vector{(i + 0.25f) * step, 0.f}, + {127, 127, 127, 255} + ); + + i = 4; + draw_item(recipe.output, pen + geom::vector{i * step, 0.f}, scale, painter_); + + pen[1] -= step; + } + } + + selected_card_ = std::nullopt; + { - float const step = std::pow(3.f, - 2.f - view_level); + float const step = 0.5f * std::pow(3.f, - 1.f - view_level); float vs = std::pow(3.f, - 1.f - view_level) * 0.01f; - geom::point pen = view_box_.corner(1, 1) + geom::vector{-1.f, -1.f} * view_box_[1].length() / 10.f; + geom::point pen = view_box_.corner(1, 1) - geom::vector{step, step} / 2.f; for (auto type : card_type_values()) { if (!map_.cards.contains(type)) continue; - draw_card(geom::expand(geom::box::singleton(pen), step), type, painter_); + geom::box box{{{pen[0] - step, pen[0]}, {pen[1] - step, pen[1]}}}; + box[0] -= step * card_animation_[type] / 2.f; - auto color = (type != card_type::crossing) ? gfx::black : gfx::white; + if (active_card_ == type) + { + draw_selection(box, painter_, {64, 64, 64, 255}, true); + } + else if (geom::contains(box, mouse_world_)) + { + selected_card_ = type; + draw_selection(box, painter_, {128, 128, 128, 255}); + } - painter_.text(pen, std::to_string(map_.cards.at(type)), {.scale = {vs, -vs}, .c = color}); + draw_card(box, type, painter_); - pen[1] -= step * 2.f; + if (type != card_type::eraser) + { + auto color = (type != card_type::crossing) ? gfx::black : gfx::white; + painter_.text(box.center(), std::to_string(map_.cards.at(type)), {.scale = {vs, -vs}, .c = color}); + } + + pen[1] -= step; } } @@ -1501,6 +1573,7 @@ namespace gmtk geom::vector screen_size_{1, 1}; geom::point mouse_{0, 0}; + geom::point mouse_world_{0, 0}; bool item_killing_spree_ = false; gfx::painter painter_; @@ -1520,6 +1593,10 @@ namespace gmtk std::optional selected_; std::optional belt_start_; std::optional selected_item_; + std::optional selected_card_; + std::optional active_card_; + + util::hash_map card_animation_; }; }