Mouse-based cards UI

This commit is contained in:
Nikita Lisitsa 2024-08-19 16:11:04 +03:00
parent 7034b2bde2
commit 8953b56970

View file

@ -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<float, 2> 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<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<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<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<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<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<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<item const>([&](ecs::handle entity, item const & i)
{
auto box = geom::expand(geom::box<float, 2>::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<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<transformer_type> 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<index>().find(*selected_))
if (auto t = map_.world.get(*entity).get_if<transformer>())
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<float, 2> 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<float, 2> 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<float, 2> pen = view_box_.corner(1, 1) + geom::vector{-1.f, -1.f} * view_box_[1].length() / 10.f;
geom::point<float, 2> 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<float, 2>::singleton(pen), step), type, painter_);
geom::box<float, 2> 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<int, 2> screen_size_{1, 1};
geom::point<int, 2> mouse_{0, 0};
geom::point<float, 2> mouse_world_{0, 0};
bool item_killing_spree_ = false;
gfx::painter painter_;
@ -1520,6 +1593,10 @@ namespace gmtk
std::optional<location> selected_;
std::optional<location> belt_start_;
std::optional<ecs::handle> selected_item_;
std::optional<card_type> selected_card_;
std::optional<card_type> active_card_;
util::hash_map<card_type, float> card_animation_;
};
}