Zoomies wip
This commit is contained in:
parent
2468495fc6
commit
1f1dc2b35f
2 changed files with 245 additions and 57 deletions
2
psemek
2
psemek
|
|
@ -1 +1 @@
|
|||
Subproject commit 82f7d5d429f7f04a82235dd0b7023b23feb39eae
|
||||
Subproject commit a2c83633ae09f3db5c1e4d115a417021d38914ae
|
||||
|
|
@ -54,10 +54,10 @@ namespace gmtk
|
|||
return {(coords[0] + 0.5f) * s, (coords[1] + 0.5f) * s};
|
||||
}
|
||||
|
||||
geom::box<float, 2> bbox() const
|
||||
geom::box<float, 2> bbox(float extra = 0.f) const
|
||||
{
|
||||
float s = std::pow(3.f, -level);
|
||||
return {{{(coords[0] + 0) * s, (coords[0] + 1) * s}, {(coords[1] + 0) * s, (coords[1] + 1) * s}}};
|
||||
return {{{(coords[0] - extra) * s, (coords[0] + 1.f + extra) * s}, {(coords[1] - extra) * s, (coords[1] + 1.f + extra) * s}}};
|
||||
}
|
||||
|
||||
location down() const
|
||||
|
|
@ -104,6 +104,11 @@ namespace gmtk
|
|||
color output;
|
||||
};
|
||||
|
||||
struct zoomer
|
||||
{
|
||||
psemek_ecs_declare_uuid("zoomer")
|
||||
};
|
||||
|
||||
struct path_vertex
|
||||
{
|
||||
psemek_ecs_declare_uuid("path_vertex")
|
||||
|
|
@ -133,7 +138,7 @@ namespace gmtk
|
|||
bool within_grid(location const & l)
|
||||
{
|
||||
int max = std::pow(3, l.level + 1);
|
||||
return l.coords[0] >= 0 && l.coords[0] < max && l.coords[1] >= 0 && l.coords[1] < 3;
|
||||
return l.coords[0] >= 0 && l.coords[0] < max && l.coords[1] >= 0 && l.coords[1] < max;
|
||||
}
|
||||
|
||||
struct timestamp
|
||||
|
|
@ -169,9 +174,6 @@ namespace gmtk
|
|||
{
|
||||
ecs::container world;
|
||||
|
||||
int current_level = 0;
|
||||
geom::point<int, 2> current_origin = {0, 0};
|
||||
|
||||
timestamp time = {};
|
||||
|
||||
float spawn_timer = 0.f;
|
||||
|
|
@ -277,22 +279,41 @@ namespace gmtk
|
|||
return result;
|
||||
}
|
||||
|
||||
void draw(map & map, gfx::painter & painter)
|
||||
void draw_grid(location origin, float view_level, gfx::painter & painter)
|
||||
{
|
||||
float const grid_width = 0.1f;
|
||||
origin.level += 1;
|
||||
origin.coords[0] *= 3;
|
||||
origin.coords[1] *= 3;
|
||||
|
||||
float const grid_width = 0.1f * std::pow(3.f, -std::max<float>(view_level + 1.f, origin.level));
|
||||
|
||||
auto box = origin.bbox();
|
||||
|
||||
for (int x = 0; x <= 3; ++x)
|
||||
{
|
||||
painter.line({x, 0.f}, {x, 3.f}, grid_width, gfx::black, true);
|
||||
painter.line({0.f, x}, {3.f, x}, grid_width, gfx::black, true);
|
||||
painter.line(box.corner(x, 0), box.corner(x, 3), grid_width, gfx::black, true);
|
||||
painter.line(box.corner(0, x), box.corner(3, x), grid_width, gfx::black, true);
|
||||
}
|
||||
}
|
||||
|
||||
void draw(map & map, float view_level, gfx::painter & painter)
|
||||
{
|
||||
draw_grid({-1, {0, 0}}, view_level, painter);
|
||||
|
||||
map.world.apply<vertex const, zoomer const>([&](vertex const & v, zoomer const &)
|
||||
{
|
||||
draw_grid(v.location, view_level, painter);
|
||||
});
|
||||
|
||||
map.world.apply<path_vertex const>([&](path_vertex const & vertex)
|
||||
{
|
||||
for (auto b : vertex.belts)
|
||||
{
|
||||
auto q = map.world.get(b).get<path_vertex const>().location;
|
||||
painter.line(vertex.location.center(), q.center(), 0.3f, {191, 191, 191, 255}, true);
|
||||
float w0 = 0.3f * std::pow(3.f, 1.f - vertex.location.level);
|
||||
float w1 = 0.3f * std::pow(3.f, 1.f - q.level);
|
||||
gfx::color_rgba c{191, 191, 191, 255};
|
||||
painter.line(vertex.location.center(), q.center(), w0, w1, c, c, true);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -319,42 +340,56 @@ namespace gmtk
|
|||
|
||||
map.world.apply<vertex const, source const>([&](vertex const & v, source const & s)
|
||||
{
|
||||
painter.rect(geom::shrink(v.location.bbox(), 0.2f), to_color(s.type));
|
||||
painter.text(v.location.center(), "180/m", {.scale = {0.01f, -0.01f}, .c = {0, 0, 0, 255}});
|
||||
float vs = std::pow(3.f, - v.location.level) * 0.01f;
|
||||
painter.rect(v.location.bbox(-0.2f), to_color(s.type));
|
||||
painter.text(v.location.center(), "180/m", {.scale = {vs, -vs}, .c = {0, 0, 0, 255}});
|
||||
});
|
||||
|
||||
map.world.apply<vertex const, transformer const>([&](vertex const & v, transformer const & t)
|
||||
{
|
||||
auto box = geom::shrink(v.location.bbox(), 0.2f);
|
||||
auto box = v.location.bbox(-0.2f);
|
||||
painter.triangle(box.corner(0, 0), box.corner(1, 1), box.corner(0, 1), to_color(t.input));
|
||||
painter.triangle(box.corner(0, 0), box.corner(1, 0), box.corner(1, 1), to_color(t.output));
|
||||
});
|
||||
|
||||
map.world.apply<vertex const, task const>([&](vertex const & v, task const & t)
|
||||
{
|
||||
painter.rect(geom::shrink(v.location.bbox(), 0.2f), to_color(t.type));
|
||||
painter.text(v.location.center(), std::format("{}/m", t.received.size() * task::freq), {.scale = {0.01f, -0.01f}, .c = {0, 0, 0, 255}});
|
||||
float vs = std::pow(3.f, - v.location.level) * 0.01f;
|
||||
painter.rect(v.location.bbox(-0.2f), to_color(t.type));
|
||||
painter.text(v.location.center(), std::format("{}/m", t.received.size() * task::freq), {.scale = {vs, -vs}, .c = {0, 0, 0, 255}});
|
||||
});
|
||||
|
||||
map.world.apply<item const>([&](item const & i)
|
||||
{
|
||||
geom::point<float, 2> pos;
|
||||
float scale;
|
||||
if (i.target)
|
||||
pos = geom::lerp(i.start.center(), map.world.get(i.target).get<path_vertex const>().location.center(), i.state);
|
||||
{
|
||||
auto end = map.world.get(i.target).get<path_vertex const>().location;
|
||||
pos = geom::lerp(i.start.center(), end.center(), i.state);
|
||||
scale = std::pow(3.f, -geom::lerp<float>(i.start.level, end.level, i.state));
|
||||
}
|
||||
else
|
||||
{
|
||||
pos = i.start.center();
|
||||
painter.circle(pos, 0.075f, {0, 0, 0, 255});
|
||||
painter.circle(pos, 0.05f, to_color(i.type));
|
||||
scale = std::pow(3.f, -i.start.level);
|
||||
}
|
||||
scale *= 3.f;
|
||||
|
||||
painter.circle(pos, 0.075f * scale, {0, 0, 0, 255});
|
||||
painter.circle(pos, 0.05f * scale, to_color(i.type));
|
||||
});
|
||||
}
|
||||
|
||||
void draw_selection(location const & l, gfx::painter & painter)
|
||||
{
|
||||
auto p = l.coords;
|
||||
painter.line({p[0], p[1]}, {p[0] + 1.f, p[1]}, 0.1f, {255, 0, 255, 255}, true);
|
||||
painter.line({p[0] + 1.f, p[1]}, {p[0] + 1.f, p[1] + 1.f}, 0.1f, {255, 0, 255, 255}, true);
|
||||
painter.line({p[0] + 1.f, p[1] + 1.f}, {p[0], p[1] + 1.f}, 0.1f, {255, 0, 255, 255}, true);
|
||||
painter.line({p[0], p[1] + 1.f}, {p[0], p[1]}, 0.1f, {255, 0, 255, 255}, true);
|
||||
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);
|
||||
}
|
||||
|
||||
struct application
|
||||
|
|
@ -363,7 +398,9 @@ namespace gmtk
|
|||
application(options const &, context const &)
|
||||
: rng_{random::device{}}
|
||||
, map_(starting_map(rng_))
|
||||
{}
|
||||
{
|
||||
view_stack_.push_back({-1, {0, 0}});
|
||||
}
|
||||
|
||||
void on_event(app::resize_event const & event) override
|
||||
{
|
||||
|
|
@ -375,6 +412,31 @@ namespace gmtk
|
|||
mouse_ = event.position;
|
||||
}
|
||||
|
||||
void on_event(app::mouse_button_event const & event) override
|
||||
{
|
||||
if (event.down && event.button == app::mouse_button::left)
|
||||
{
|
||||
if (selected_ && !view_transition_)
|
||||
if (auto entity = map_.world.index<index>().find(*selected_))
|
||||
if (map_.world.get(*entity).contains<zoomer>())
|
||||
{
|
||||
view_transition_ = {view_stack_.back()};
|
||||
view_stack_.push_back(*selected_);
|
||||
selected_ = std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
if (event.down && event.button == app::mouse_button::right)
|
||||
{
|
||||
if (!view_transition_ && view_stack_.size() > 1)
|
||||
{
|
||||
view_transition_ = {view_stack_.back()};
|
||||
view_stack_.pop_back();
|
||||
selected_ = std::nullopt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void on_event(app::key_event const & event) override
|
||||
{
|
||||
if (event.down && event.key == app::keycode::S)
|
||||
|
|
@ -407,30 +469,64 @@ namespace gmtk
|
|||
{
|
||||
if (belt_start_)
|
||||
{
|
||||
auto d = selected_->coords - belt_start_->coords;
|
||||
if (std::abs(d[0]) + std::abs(d[1]) == 1)
|
||||
if (selected_->level == belt_start_->level)
|
||||
{
|
||||
auto & index = map_.world.index<path_index>();
|
||||
for (int i = 0; i < 3; ++i)
|
||||
auto d = selected_->coords - belt_start_->coords;
|
||||
if (std::abs(d[0]) + std::abs(d[1]) == 1)
|
||||
{
|
||||
auto p = belt_start_->down();
|
||||
p.coords += d * i;
|
||||
auto q = p;
|
||||
q.coords += d;
|
||||
bool from_zoom = false;
|
||||
bool to_zoom = false;
|
||||
|
||||
auto s = index.get(p);
|
||||
auto t = index.get(q);
|
||||
if (auto entity = map_.world.index<index>().find(*belt_start_))
|
||||
if (map_.world.get(*entity).contains<zoomer>())
|
||||
from_zoom = true;
|
||||
(void)from_zoom;
|
||||
|
||||
auto & sv = map_.world.get(s).get<path_vertex>();
|
||||
auto & tv = map_.world.get(t).get<path_vertex>();
|
||||
if (auto entity = map_.world.index<index>().find(*selected_))
|
||||
if (map_.world.get(*entity).contains<zoomer>())
|
||||
to_zoom = true;
|
||||
|
||||
if (sv.belts.contains(t))
|
||||
sv.belts.erase(t);
|
||||
else
|
||||
auto vx = [&](int i)
|
||||
{
|
||||
if (tv.belts.contains(s))
|
||||
tv.belts.erase(s);
|
||||
sv.belts.insert(t);
|
||||
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;
|
||||
};
|
||||
|
||||
auto & index = map_.world.index<path_index>();
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
auto p = vx(i);
|
||||
auto q = vx(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);
|
||||
else
|
||||
{
|
||||
if (tv.belts.contains(s))
|
||||
tv.belts.erase(s);
|
||||
sv.belts.insert(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -471,6 +567,17 @@ namespace gmtk
|
|||
}
|
||||
}
|
||||
|
||||
if (event.down && event.key == app::keycode::Z)
|
||||
{
|
||||
if (selected_ && !map_.world.index<index>().find(*selected_))
|
||||
{
|
||||
map_.world.create(
|
||||
vertex{*selected_},
|
||||
zoomer{}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (event.down && event.key == app::keycode::X)
|
||||
{
|
||||
if (selected_)
|
||||
|
|
@ -527,7 +634,6 @@ namespace gmtk
|
|||
);
|
||||
}
|
||||
|
||||
|
||||
map_.world.apply<task>([&](task & t)
|
||||
{
|
||||
auto threshold = map_.time;
|
||||
|
|
@ -540,6 +646,16 @@ namespace gmtk
|
|||
{
|
||||
if (i.target)
|
||||
{
|
||||
{
|
||||
auto & v = map_.world.get(map_.world.index<path_index>().get(i.start)).get<path_vertex const>();
|
||||
if (!v.belts.contains(i.target))
|
||||
{
|
||||
map_.world.detach<occupied>(i.target);
|
||||
map_.world.destroy(entity);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
i.state += 3.f * dt;
|
||||
if (i.state < 1.f)
|
||||
return;
|
||||
|
|
@ -552,7 +668,24 @@ namespace gmtk
|
|||
}
|
||||
else
|
||||
{
|
||||
map_.world.detach<occupied>(map_.world.index<path_index>().get(i.start));
|
||||
auto s = map_.world.index<path_index>().get(i.start);
|
||||
map_.world.detach<occupied>(s);
|
||||
|
||||
auto & v = map_.world.get(s).get<path_vertex const>();
|
||||
if (v.belts.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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (auto cell = map_.world.index<index>().find(i.start.up()))
|
||||
|
|
@ -589,22 +722,52 @@ namespace gmtk
|
|||
|
||||
float aspect_ratio = (screen_size_[0] * 1.f) / screen_size_[1];
|
||||
|
||||
view_box_[1] = {-1.f, 4.f};
|
||||
view_box_[0] = view_box_[1];
|
||||
if (view_transition_)
|
||||
{
|
||||
auto from = view_transition_->old.bbox(1.f / 3.f);
|
||||
auto to = view_stack_.back().bbox(1.f / 3.f);
|
||||
|
||||
float t = geom::smoothstep(view_transition_->timer * 2.f);
|
||||
|
||||
view_box_[0].min = geom::lerp(from[0].min, to[0].min, t);
|
||||
view_box_[0].max = geom::lerp(from[0].max, to[0].max, t);
|
||||
view_box_[1].min = geom::lerp(from[1].min, to[1].min, t);
|
||||
view_box_[1].max = geom::lerp(from[1].max, to[1].max, t);
|
||||
|
||||
view_transition_->timer += dt;
|
||||
if (view_transition_->timer >= 0.5f)
|
||||
view_transition_ = std::nullopt;
|
||||
}
|
||||
else
|
||||
{
|
||||
view_box_ = view_stack_.back().bbox(1.f / 3.f);
|
||||
}
|
||||
|
||||
view_box_[0] = geom::expand(view_box_[0], (view_box_[1].length() * aspect_ratio - view_box_[0].length()) / 2.f);
|
||||
|
||||
selected_ = std::nullopt;
|
||||
|
||||
if (!view_transition_)
|
||||
{
|
||||
auto m = screen_to_grid(geom::cast<float>(mouse_));
|
||||
auto m = view_box_.corner(
|
||||
mouse_[0] * 1.f / screen_size_[0],
|
||||
1.f - mouse_[1] * 1.f / screen_size_[1]
|
||||
);
|
||||
|
||||
int x = std::floor(m[0]);
|
||||
int y = std::floor(m[1]);
|
||||
float s = std::pow(3.f, 1 + view_stack_.back().level);
|
||||
|
||||
if (x >= 0 && x < 3 && y >= 0 && y < 3)
|
||||
selected_ = {0, geom::point{x, y}};
|
||||
else if (map_.world.index<index>().find({0, {x, y}}))
|
||||
selected_ = {0, geom::point{x, y}};
|
||||
m[0] *= s;
|
||||
m[1] *= s;
|
||||
|
||||
auto l = view_stack_.back();
|
||||
|
||||
location p{1 + l.level, {std::floor(m[0]), std::floor(m[1])}};
|
||||
|
||||
if (p.coords[0] >= 3 * l.coords[0] && p.coords[0] < 3 * l.coords[0] + 3 && p.coords[1] >= 3 * l.coords[1] && p.coords[1] < 3 * l.coords[1] + 3)
|
||||
selected_ = p;
|
||||
else if (auto entity = map_.world.index<index>().find(p))
|
||||
if (map_.world.get(*entity).contains<task>())
|
||||
selected_ = p;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -613,7 +776,15 @@ namespace gmtk
|
|||
gl::ClearColor(1.f, 1.f, 1.f, 1.f);
|
||||
gl::Clear(gl::COLOR_BUFFER_BIT);
|
||||
|
||||
draw(map_, painter_);
|
||||
float view_level = view_stack_.back().level;
|
||||
|
||||
if (view_transition_)
|
||||
{
|
||||
float t = geom::smoothstep(view_transition_->timer * 2.f);
|
||||
view_level = geom::lerp<float>(view_transition_->old.level, view_stack_.back().level, t);
|
||||
}
|
||||
|
||||
draw(map_, view_level, painter_);
|
||||
|
||||
if (selected_)
|
||||
draw_selection(*selected_, painter_);
|
||||
|
|
@ -634,6 +805,16 @@ namespace gmtk
|
|||
|
||||
gfx::painter painter_;
|
||||
|
||||
struct view_transition
|
||||
{
|
||||
location old;
|
||||
float timer = 0.f;
|
||||
};
|
||||
|
||||
std::optional<view_transition> view_transition_;
|
||||
|
||||
std::vector<location> view_stack_;
|
||||
|
||||
geom::box<float, 2> view_box_;
|
||||
|
||||
std::optional<location> selected_;
|
||||
|
|
@ -641,10 +822,17 @@ namespace gmtk
|
|||
|
||||
geom::point<float, 2> screen_to_grid(geom::point<float, 2> const & p)
|
||||
{
|
||||
return view_box_.corner(
|
||||
auto result = view_box_.corner(
|
||||
p[0] / screen_size_[0],
|
||||
1.f - p[1] / screen_size_[1]
|
||||
);
|
||||
|
||||
float s = std::pow(3.f, 1 + view_stack_.back().level);
|
||||
|
||||
result[0] *= s;
|
||||
result[1] *= s;
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue