Zoomer belt fixes

This commit is contained in:
Nikita Lisitsa 2024-08-18 14:48:59 +03:00
parent 1f1dc2b35f
commit b0ab5c3d5b

View file

@ -60,6 +60,31 @@ namespace gmtk
return {{{(coords[0] - extra) * s, (coords[0] + 1.f + extra) * s}, {(coords[1] - extra) * s, (coords[1] + 1.f + extra) * s}}};
}
location left() const
{
return {level, {coords[0] - 1, coords[1]}};
}
location right() const
{
return {level, {coords[0] + 1, coords[1]}};
}
location bottom() const
{
return {level, {coords[0], coords[1] - 1}};
}
location top() const
{
return {level, {coords[0], coords[1] + 1}};
}
location moved(geom::vector<int, 2> const & delta) const
{
return {level, coords + delta};
}
location down() const
{
return {level + 1, {coords[0] * 3 + 1, coords[1] * 3 + 1}};
@ -115,9 +140,22 @@ namespace gmtk
struct location location;
boost::container::flat_set<ecs::handle> belts = {};
boost::container::flat_set<ecs::handle> belts_to = {};
boost::container::flat_set<ecs::handle> belts_from = {};
};
void add_belt(ecs::container & world, ecs::handle from, ecs::handle to)
{
world.get(from).get<path_vertex>().belts_to.insert(to);
world.get(to).get<path_vertex>().belts_from.insert(from);
}
void remove_belt(ecs::container & world, ecs::handle from, ecs::handle to)
{
world.get(from).get<path_vertex>().belts_to.erase(to);
world.get(to).get<path_vertex>().belts_from.erase(from);
}
struct occupied
{
psemek_ecs_declare_uuid("occupied")
@ -226,6 +264,75 @@ namespace gmtk
using index = index_base<vertex, util::make_uuid("vertex_index")>;
using path_index = index_base<path_vertex, util::make_uuid("path_vertex_index")>;
void sink_belt(ecs::container & world, location m)
{
if (auto entity = world.index<index>().find(m.up()); !entity || !world.get(*entity).contains<zoomer>())
return;
auto & index = world.index<path_index>();
auto c = m.up().down();
auto d = m.coords - c.coords;
auto ce = index.get(c);
auto me = index.get(m);
auto & cv = world.get(ce).get<path_vertex>();
if (cv.belts_to.contains(me))
{
auto & mv = world.get(me).get<path_vertex>();
auto ne = *mv.belts_to.begin();
remove_belt(world, ce, me);
remove_belt(world, me, ne);
auto cd = m.down();
auto md = cd.moved(d);
auto cde = index.get(cd);
auto mde = index.get(md);
add_belt(world, cde, mde);
add_belt(world, mde, ne);
sink_belt(world, md);
}
else if (cv.belts_from.contains(me))
{
auto & mv = world.get(me).get<path_vertex>();
auto ne = *mv.belts_from.begin();
remove_belt(world, ne, me);
remove_belt(world, me, ce);
auto cd = m.down();
auto md = cd.moved(d);
auto cde = index.get(cd);
auto mde = index.get(md);
add_belt(world, ne, mde);
add_belt(world, mde, cde);
sink_belt(world, md);
}
}
void sink(ecs::container & world, location & c, location & m)
{
if (auto entity = world.index<index>().find(m.up()); !entity || !world.get(*entity).contains<zoomer>())
return;
auto d = m.coords - c.coords;
c = m.down();
m = c.moved(d);
sink(world, c, m);
}
void generate_next_task(random::generator & rng, map & map)
{
color type;
@ -307,7 +414,7 @@ namespace gmtk
map.world.apply<path_vertex const>([&](path_vertex const & vertex)
{
for (auto b : vertex.belts)
for (auto b : vertex.belts_to)
{
auto q = map.world.get(b).get<path_vertex const>().location;
float w0 = 0.3f * std::pow(3.f, 1.f - vertex.location.level);
@ -319,7 +426,7 @@ namespace gmtk
map.world.apply<path_vertex const>([&](path_vertex const & vertex)
{
for (auto b : vertex.belts)
for (auto b : vertex.belts_to)
{
auto q = map.world.get(b).get<path_vertex const>().location;
@ -381,15 +488,15 @@ namespace gmtk
});
}
void draw_selection(location const & l, gfx::painter & painter)
void draw_selection(location const & l, gfx::painter & painter, gfx::color_rgba const & color)
{
auto b = l.bbox();
float s = std::pow(3.f, -l.level) * 0.1f;
painter.line(b.corner(0, 0), b.corner(1, 0), s, {255, 0, 255, 255}, true);
painter.line(b.corner(1, 0), b.corner(1, 1), s, {255, 0, 255, 255}, true);
painter.line(b.corner(1, 1), b.corner(0, 1), s, {255, 0, 255, 255}, true);
painter.line(b.corner(0, 1), b.corner(0, 0), s, {255, 0, 255, 255}, true);
painter.line(b.corner(0, 0), b.corner(1, 0), s, color, true);
painter.line(b.corner(1, 0), b.corner(1, 1), s, color, true);
painter.line(b.corner(1, 1), b.corner(0, 1), s, color, true);
painter.line(b.corner(0, 1), b.corner(0, 0), s, color, true);
}
struct application
@ -474,58 +581,31 @@ namespace gmtk
auto d = selected_->coords - belt_start_->coords;
if (std::abs(d[0]) + std::abs(d[1]) == 1)
{
bool from_zoom = false;
bool to_zoom = false;
auto s = belt_start_->down();
if (auto entity = map_.world.index<index>().find(*belt_start_))
if (map_.world.get(*entity).contains<zoomer>())
from_zoom = true;
(void)from_zoom;
if (auto entity = map_.world.index<index>().find(*selected_))
if (map_.world.get(*entity).contains<zoomer>())
to_zoom = true;
auto vx = [&](int i)
{
auto p = belt_start_->down();
if (i < 2 && from_zoom)
{
p.coords += d;
p = p.down();
}
if (i >= 2 && to_zoom)
{
p.coords += d;
p = p.down();
}
p.coords += d * i;
return p;
};
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]);
auto & index = map_.world.index<path_index>();
for (int i = 0; i < 3; ++i)
{
auto p = vx(i);
auto q = vx(i + 1);
auto p = belt[i];
auto q = belt[i + 1];
auto s = index.get(p);
auto t = index.get(q);
auto & sv = map_.world.get(s).get<path_vertex>();
auto & tv = map_.world.get(t).get<path_vertex>();
if (sv.belts.contains(t))
sv.belts.erase(t);
if (sv.belts_to.contains(t))
remove_belt(map_.world, s, t);
else
{
if (tv.belts.contains(s))
tv.belts.erase(s);
sv.belts.insert(t);
remove_belt(map_.world, t, s);
add_belt(map_.world, s, t);
}
}
}
@ -575,6 +655,13 @@ namespace gmtk
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());
}
}
@ -648,7 +735,7 @@ namespace gmtk
{
{
auto & v = map_.world.get(map_.world.index<path_index>().get(i.start)).get<path_vertex const>();
if (!v.belts.contains(i.target))
if (!v.belts_to.contains(i.target))
{
map_.world.detach<occupied>(i.target);
map_.world.destroy(entity);
@ -672,19 +759,10 @@ namespace gmtk
map_.world.detach<occupied>(s);
auto & v = map_.world.get(s).get<path_vertex const>();
if (v.belts.empty())
if (v.belts_to.empty() && v.belts_from.empty())
{
bool should_destroy = true;
map_.world.apply<path_vertex const>([&](path_vertex const & v){
if (v.belts.contains(s))
should_destroy = false;
});
if (should_destroy)
{
map_.world.destroy(entity);
return;
}
map_.world.destroy(entity);
return;
}
}
@ -707,7 +785,7 @@ namespace gmtk
std::vector<ecs::handle> targets;
for (auto b : map_.world.get(map_.world.index<path_index>().get(i.start)).get<path_vertex>().belts)
for (auto b : map_.world.get(map_.world.index<path_index>().get(i.start)).get<path_vertex>().belts_to)
if (!map_.world.get(b).contains<occupied>())
targets.push_back(b);
@ -787,7 +865,10 @@ namespace gmtk
draw(map_, view_level, painter_);
if (selected_)
draw_selection(*selected_, painter_);
draw_selection(*selected_, painter_, {255, 0, 255, 255});
if (belt_start_)
draw_selection(*belt_start_, painter_, {255, 255, 0, 255});
painter_.render(geom::orthographic_camera{view_box_}.transform());
}