Mouse-based cards UI
This commit is contained in:
parent
7034b2bde2
commit
8953b56970
1 changed files with 211 additions and 134 deletions
|
|
@ -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_;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue