Reimplement core mechanics in a more generic graph using ecs
This commit is contained in:
parent
eaf27df1a0
commit
2468495fc6
2 changed files with 298 additions and 259 deletions
2
psemek
2
psemek
|
|
@ -1 +1 @@
|
|||
Subproject commit 6368ca5e680bbcae3d13df4e87ed25ef80728cd3
|
||||
Subproject commit 82f7d5d429f7f04a82235dd0b7023b23feb39eae
|
||||
|
|
@ -10,9 +10,13 @@
|
|||
#include <psemek/util/clock.hpp>
|
||||
#include <psemek/geom/box.hpp>
|
||||
#include <psemek/geom/camera.hpp>
|
||||
#include <psemek/ecs/container.hpp>
|
||||
#include <psemek/ecs/declare_uuid.hpp>
|
||||
|
||||
#include <psemek/log/log.hpp>
|
||||
|
||||
#include <boost/container/flat_set.hpp>
|
||||
|
||||
#include <variant>
|
||||
#include <deque>
|
||||
#include <format>
|
||||
|
|
@ -39,123 +43,97 @@ namespace gmtk
|
|||
throw util::unknown_enum_value_exception{c};
|
||||
}
|
||||
|
||||
struct tile;
|
||||
|
||||
struct grid
|
||||
struct location
|
||||
{
|
||||
util::array<tile, 2> tiles;
|
||||
util::array<bool, 2> item_target;
|
||||
int level;
|
||||
geom::point<int, 2> coords;
|
||||
|
||||
util::array<util::hash_set<geom::point<int, 2>>, 2> belts;
|
||||
geom::point<float, 2> center() const
|
||||
{
|
||||
float s = std::pow(3.f, -level);
|
||||
return {(coords[0] + 0.5f) * s, (coords[1] + 0.5f) * s};
|
||||
}
|
||||
|
||||
static grid create();
|
||||
geom::box<float, 2> bbox() 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}}};
|
||||
}
|
||||
|
||||
static geom::point<int, 2> const indices[9];
|
||||
location down() const
|
||||
{
|
||||
return {level + 1, {coords[0] * 3 + 1, coords[1] * 3 + 1}};
|
||||
}
|
||||
|
||||
static geom::vector<int, 2> const neighbours[4];
|
||||
location up() const
|
||||
{
|
||||
return {level - 1, {geom::idiv(coords[0], 3), geom::idiv(coords[1], 3)}};
|
||||
}
|
||||
|
||||
friend bool operator == (location const & x, location const & y) = default;
|
||||
friend auto operator <=> (location const & x, location const & y) = default;
|
||||
};
|
||||
|
||||
geom::point<int, 2> const grid::indices[9] =
|
||||
struct location_hash
|
||||
{
|
||||
{0, 0},
|
||||
{1, 0},
|
||||
{2, 0},
|
||||
{0, 1},
|
||||
{1, 1},
|
||||
{2, 1},
|
||||
{0, 2},
|
||||
{1, 2},
|
||||
{2, 2},
|
||||
std::size_t operator()(location const & x) const noexcept
|
||||
{
|
||||
return util::hash_all(x.level, x.coords[0], x.coords[1]);
|
||||
}
|
||||
};
|
||||
|
||||
geom::vector<int, 2> const grid::neighbours[4] =
|
||||
struct vertex
|
||||
{
|
||||
{1, 0},
|
||||
{0, 1},
|
||||
{-1, 0},
|
||||
{0, -1},
|
||||
};
|
||||
psemek_ecs_declare_uuid("vertex")
|
||||
|
||||
struct empty{};
|
||||
struct location location;
|
||||
};
|
||||
|
||||
struct source
|
||||
{
|
||||
psemek_ecs_declare_uuid("source")
|
||||
|
||||
color type;
|
||||
};
|
||||
|
||||
struct factory
|
||||
struct transformer
|
||||
{
|
||||
psemek_ecs_declare_uuid("transformer")
|
||||
|
||||
color input;
|
||||
color output;
|
||||
};
|
||||
|
||||
struct zoomer
|
||||
struct path_vertex
|
||||
{
|
||||
struct grid grid;
|
||||
psemek_ecs_declare_uuid("path_vertex")
|
||||
|
||||
struct location location;
|
||||
|
||||
boost::container::flat_set<ecs::handle> belts = {};
|
||||
};
|
||||
|
||||
using tile_variant = std::variant<empty, source, factory, zoomer>;
|
||||
|
||||
struct tile
|
||||
: tile_variant
|
||||
struct occupied
|
||||
{
|
||||
using tile_variant::variant;
|
||||
psemek_ecs_declare_uuid("occupied")
|
||||
|
||||
ecs::handle entity;
|
||||
};
|
||||
|
||||
grid grid::create()
|
||||
{
|
||||
grid result;
|
||||
|
||||
result.tiles.resize({3, 3});
|
||||
result.belts.resize({3, 3});
|
||||
result.item_target.resize({9, 9}, false);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
struct item
|
||||
{
|
||||
psemek_ecs_declare_uuid("item")
|
||||
|
||||
color type;
|
||||
geom::point<int, 2> start;
|
||||
geom::point<int, 2> target;
|
||||
float pos;
|
||||
location start;
|
||||
ecs::handle target = ecs::handle::null();
|
||||
float state = 0.f;
|
||||
};
|
||||
|
||||
geom::point<int, 2> item_to_cell(geom::point<int, 2> const & p)
|
||||
bool within_grid(location const & l)
|
||||
{
|
||||
return {geom::idiv(p[0], 3), geom::idiv(p[1], 3)};
|
||||
}
|
||||
|
||||
geom::point<int, 2> cell_center_to_item(geom::point<int, 2> const & p)
|
||||
{
|
||||
return {p[0] * 3 + 1, p[1] * 3 + 1};
|
||||
}
|
||||
|
||||
geom::point<int, 2> task_sink_to_item(geom::point<int, 2> p)
|
||||
{
|
||||
p[0] *= 3;
|
||||
p[1] *= 3;
|
||||
|
||||
if (p[0] == -3)
|
||||
p += geom::vector{2, 1};
|
||||
else if (p[1] == -3)
|
||||
p += geom::vector{1, 2};
|
||||
else if (p[0] == 9)
|
||||
p += geom::vector{0, 1};
|
||||
else if (p[1] == 9)
|
||||
p += geom::vector{1, 0};
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
bool within_grid(geom::point<int, 2> const & p)
|
||||
{
|
||||
return p[0] >= 0 && p[0] < 3 && p[1] >= 0 && p[1] < 3;
|
||||
}
|
||||
|
||||
bool item_within_grid(geom::point<int, 2> const & p)
|
||||
{
|
||||
return p[0] >= 0 && p[0] < 9 && p[1] >= 0 && p[1] < 9;
|
||||
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;
|
||||
}
|
||||
|
||||
struct timestamp
|
||||
|
|
@ -177,6 +155,8 @@ namespace gmtk
|
|||
|
||||
struct task
|
||||
{
|
||||
psemek_ecs_declare_uuid("task")
|
||||
|
||||
color type;
|
||||
|
||||
// In last 15 seconds
|
||||
|
|
@ -187,33 +167,82 @@ namespace gmtk
|
|||
|
||||
struct map
|
||||
{
|
||||
struct grid grid;
|
||||
ecs::container world;
|
||||
|
||||
util::hash_map<geom::point<int, 2>, task> tasks;
|
||||
|
||||
std::vector<item> items;
|
||||
int current_level = 0;
|
||||
geom::point<int, 2> current_origin = {0, 0};
|
||||
|
||||
timestamp time = {};
|
||||
|
||||
float spawn_timer = 0.f;
|
||||
};
|
||||
|
||||
template <typename Component, util::uuid UUID>
|
||||
struct index_base
|
||||
{
|
||||
static constexpr util::uuid uuid()
|
||||
{
|
||||
return UUID;
|
||||
}
|
||||
|
||||
index_base(ecs::container & world)
|
||||
: world_(world)
|
||||
{
|
||||
world.apply<Component>([this](ecs::handle entity, Component const & v){
|
||||
index_[v.location] = entity;
|
||||
});
|
||||
|
||||
world.constructor<Component>([this](ecs::handle entity, Component const & v){
|
||||
index_[v.location] = entity;
|
||||
});
|
||||
|
||||
world.destructor<Component>([this](Component const & v){
|
||||
index_.erase(v.location);
|
||||
});
|
||||
}
|
||||
|
||||
std::optional<ecs::handle> find(location const & l) const
|
||||
{
|
||||
if (auto it = index_.find(l); it != index_.end())
|
||||
return it->second;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
ecs::handle get(location const & l) const
|
||||
{
|
||||
if (auto entity = find(l))
|
||||
return *entity;
|
||||
|
||||
return world_.create(Component{l});
|
||||
}
|
||||
|
||||
private:
|
||||
ecs::container & world_;
|
||||
util::hash_map<location, ecs::handle, location_hash> index_;
|
||||
};
|
||||
|
||||
using index = index_base<vertex, util::make_uuid("vertex_index")>;
|
||||
using path_index = index_base<path_vertex, util::make_uuid("path_vertex_index")>;
|
||||
|
||||
void generate_next_task(random::generator & rng, map & map)
|
||||
{
|
||||
color type;
|
||||
|
||||
util::hash_set<color> existing_tasks;
|
||||
int task_count = 0;
|
||||
map.world.apply<task const>([&](task const & task)
|
||||
{
|
||||
existing_tasks.insert(task.type);
|
||||
task_count += 1;
|
||||
});
|
||||
|
||||
while (true)
|
||||
{
|
||||
type = random::uniform_from(rng, color_values());
|
||||
if (map.tasks.size() >= 3)
|
||||
if (task_count >= 3)
|
||||
break;
|
||||
|
||||
bool good = true;
|
||||
for (auto const & t : map.tasks)
|
||||
if (t.second.type == type)
|
||||
good = false;
|
||||
|
||||
if (good)
|
||||
if (!existing_tasks.contains(type))
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -223,10 +252,15 @@ namespace gmtk
|
|||
int y = random::uniform<bool>(rng) ? -1 : 3;
|
||||
if (random::uniform<bool>(rng))
|
||||
std::swap(x, y);
|
||||
if (map.tasks.contains({x, y}))
|
||||
|
||||
if (map.world.index<index>().find({0, {x, y}}))
|
||||
continue;
|
||||
|
||||
map.tasks[{x, y}] = {type};
|
||||
map.world.create(
|
||||
vertex{{0, {x, y}}},
|
||||
task{type}
|
||||
);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -235,17 +269,17 @@ namespace gmtk
|
|||
{
|
||||
map result;
|
||||
|
||||
result.grid = grid::create();
|
||||
result.world.index<index>();
|
||||
result.world.index<path_index>();
|
||||
|
||||
generate_next_task(rng, result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void draw(map const & map, gfx::painter & painter)
|
||||
void draw(map & map, gfx::painter & painter)
|
||||
{
|
||||
float const grid_width = 0.1f;
|
||||
geom::box<float, 2> source_box{{{0.2f, 0.8f}, {0.2f, 0.8f}}};
|
||||
|
||||
for (int x = 0; x <= 3; ++x)
|
||||
{
|
||||
|
|
@ -253,71 +287,70 @@ namespace gmtk
|
|||
painter.line({0.f, x}, {3.f, x}, grid_width, gfx::black, true);
|
||||
}
|
||||
|
||||
auto & grid = map.grid;
|
||||
|
||||
for (auto p : grid::indices)
|
||||
for (auto q : grid.belts(p))
|
||||
painter.line(geom::cast<float>(p) + geom::vector{0.5f, 0.5f}, geom::cast<float>(q) + geom::vector{0.5f, 0.5f}, 0.3f, {191, 191, 191, 255}, true);
|
||||
|
||||
for (auto p : grid::indices)
|
||||
map.world.apply<path_vertex const>([&](path_vertex const & vertex)
|
||||
{
|
||||
for (auto q : grid.belts(p))
|
||||
for (auto b : vertex.belts)
|
||||
{
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
geom::vector d = geom::cast<float>(q - p);
|
||||
|
||||
auto c = geom::cast<float>(p) + geom::vector{0.5f, 0.5f} + d * (i / 3.f);
|
||||
|
||||
auto n = geom::ort(d);
|
||||
|
||||
c += d / 6.f;
|
||||
|
||||
float s = 1.f / 24.f;
|
||||
|
||||
d *= s;
|
||||
n *= s;
|
||||
|
||||
painter.triangle(c - d + n, c - d - n, c + d, {255, 127, 0, 255});
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
for (auto p : grid::indices)
|
||||
map.world.apply<path_vertex const>([&](path_vertex const & vertex)
|
||||
{
|
||||
auto const & cell = grid.tiles(p);
|
||||
|
||||
if (auto source = std::get_if<struct source>(&cell))
|
||||
for (auto b : vertex.belts)
|
||||
{
|
||||
painter.rect(source_box + geom::vector{p[0] * 1.f, p[1] * 1.f}, to_color(source->type));
|
||||
painter.text({p[0] + 0.5f, p[1] + 0.5f}, "180/m", {.scale = {0.01f, -0.01f}, .c = {0, 0, 0, 255}});
|
||||
}
|
||||
else if (auto factory = std::get_if<struct factory>(&cell))
|
||||
{
|
||||
auto box = source_box + geom::vector{p[0] * 1.f, p[1] * 1.f};
|
||||
painter.triangle(box.corner(0, 0), box.corner(1, 1), box.corner(0, 1), to_color(factory->input));
|
||||
painter.triangle(box.corner(0, 0), box.corner(1, 0), box.corner(1, 1), to_color(factory->output));
|
||||
}
|
||||
}
|
||||
auto q = map.world.get(b).get<path_vertex const>().location;
|
||||
|
||||
for (auto const & task : map.tasks)
|
||||
{
|
||||
painter.rect(source_box + geom::vector{task.first[0] * 1.f, task.first[1] * 1.f}, to_color(task.second.type));
|
||||
painter.text(geom::point{task.first[0] + 0.5f, task.first[1] + 0.5f}, std::format("{}/m", task.second.received.size() * task::freq), {.scale = {0.01f, -0.01f}, .c = {0, 0, 0, 255}});
|
||||
}
|
||||
geom::vector d = q.center() - vertex.location.center();
|
||||
|
||||
for (auto const & item : map.items)
|
||||
auto c = vertex.location.center() + d / 2.f;
|
||||
|
||||
auto n = geom::ort(d);
|
||||
|
||||
float s = 1.f / 6.f;
|
||||
|
||||
d *= s * 0.5f;
|
||||
n *= s;
|
||||
|
||||
painter.triangle(c - d + n, c - d - n, c + d, {255, 127, 0, 255});
|
||||
}
|
||||
});
|
||||
|
||||
map.world.apply<vertex const, source const>([&](vertex const & v, source const & s)
|
||||
{
|
||||
auto pos = geom::lerp(geom::cast<float>(item.start), geom::cast<float>(item.target), item.pos) + geom::vector{0.5f, 0.5f};
|
||||
pos[0] /= 3.f;
|
||||
pos[1] /= 3.f;
|
||||
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}});
|
||||
});
|
||||
|
||||
map.world.apply<vertex const, transformer const>([&](vertex const & v, transformer const & t)
|
||||
{
|
||||
auto box = geom::shrink(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}});
|
||||
});
|
||||
|
||||
map.world.apply<item const>([&](item const & i)
|
||||
{
|
||||
geom::point<float, 2> pos;
|
||||
if (i.target)
|
||||
pos = geom::lerp(i.start.center(), map.world.get(i.target).get<path_vertex const>().location.center(), i.state);
|
||||
else
|
||||
pos = i.start.center();
|
||||
painter.circle(pos, 0.075f, {0, 0, 0, 255});
|
||||
painter.circle(pos, 0.05f, to_color(item.type));
|
||||
}
|
||||
painter.circle(pos, 0.05f, to_color(i.type));
|
||||
});
|
||||
}
|
||||
|
||||
void draw_selection(geom::point<int, 2> const & p, gfx::painter & painter)
|
||||
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);
|
||||
|
|
@ -346,15 +379,25 @@ namespace gmtk
|
|||
{
|
||||
if (event.down && event.key == app::keycode::S)
|
||||
{
|
||||
if (selected_ && std::holds_alternative<empty>(map_.grid.tiles(*selected_)))
|
||||
if (selected_ && !map_.world.index<index>().find(*selected_))
|
||||
{
|
||||
util::hash_set<color> types;
|
||||
if (map_.tasks.size() == 1)
|
||||
types.insert(map_.tasks.begin()->second.type);
|
||||
else
|
||||
int task_count = 0;
|
||||
|
||||
map_.world.apply<task const>([&](task const & t)
|
||||
{
|
||||
types.insert(t.type);
|
||||
task_count += 1;
|
||||
});
|
||||
|
||||
if (task_count > 1)
|
||||
for (auto t : color_values())
|
||||
types.insert(t);
|
||||
map_.grid.tiles(*selected_) = source{random::uniform_from(rng_, types)};
|
||||
|
||||
map_.world.create(
|
||||
vertex{*selected_},
|
||||
source{random::uniform_from(rng_, types)}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -364,16 +407,32 @@ namespace gmtk
|
|||
{
|
||||
if (belt_start_)
|
||||
{
|
||||
auto d = *selected_ - *belt_start_;
|
||||
auto d = selected_->coords - belt_start_->coords;
|
||||
if (std::abs(d[0]) + std::abs(d[1]) == 1)
|
||||
{
|
||||
if (within_grid(*selected_))
|
||||
map_.grid.belts(*selected_).erase(*belt_start_);
|
||||
auto & index = map_.world.index<path_index>();
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
auto p = belt_start_->down();
|
||||
p.coords += d * i;
|
||||
auto q = p;
|
||||
q.coords += d;
|
||||
|
||||
if (map_.grid.belts(*belt_start_).contains(*selected_))
|
||||
map_.grid.belts(*belt_start_).erase(*selected_);
|
||||
else
|
||||
map_.grid.belts(*belt_start_).insert(*selected_);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
belt_start_ = std::nullopt;
|
||||
}
|
||||
|
|
@ -384,13 +443,18 @@ namespace gmtk
|
|||
|
||||
if (event.down && event.key == app::keycode::F)
|
||||
{
|
||||
if (selected_ && std::holds_alternative<empty>(map_.grid.tiles(*selected_)))
|
||||
if (selected_ && !map_.world.index<index>().find(*selected_))
|
||||
{
|
||||
util::hash_set<color> types;
|
||||
for (auto const & task : map_.tasks)
|
||||
types.insert(task.second.type);
|
||||
int task_count = 0;
|
||||
|
||||
if (types.size() == 1)
|
||||
map_.world.apply<task const>([&](task const & t)
|
||||
{
|
||||
types.insert(t.type);
|
||||
task_count += 1;
|
||||
});
|
||||
|
||||
if (task_count == 1)
|
||||
{
|
||||
for (auto c : color_values())
|
||||
types.insert(c);
|
||||
|
|
@ -400,7 +464,10 @@ namespace gmtk
|
|||
types.erase(input);
|
||||
color output = random::uniform_from(rng_, types);
|
||||
|
||||
map_.grid.tiles(*selected_) = gmtk::factory{input, output};
|
||||
map_.world.create(
|
||||
vertex{*selected_},
|
||||
transformer{input, output}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -408,7 +475,9 @@ namespace gmtk
|
|||
{
|
||||
if (selected_)
|
||||
{
|
||||
map_.grid.tiles(*selected_) = empty{};
|
||||
if (auto entity = map_.world.index<index>().find(*selected_))
|
||||
if (!map_.world.get(*entity).contains<task>())
|
||||
map_.world.destroy(*entity);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -439,114 +508,84 @@ namespace gmtk
|
|||
{
|
||||
map_.spawn_timer -= 1.f;
|
||||
|
||||
for (auto p : grid::indices)
|
||||
{
|
||||
if (auto source = std::get_if<struct source>(&map_.grid.tiles(p)))
|
||||
map_.world.apply<vertex const, source const>(
|
||||
[&](vertex const & v, source const & s)
|
||||
{
|
||||
auto pos = cell_center_to_item(p);
|
||||
auto p = v.location.down();
|
||||
|
||||
if (!map_.grid.item_target(pos))
|
||||
auto t = map_.world.index<path_index>().get(p);
|
||||
|
||||
if (!map_.world.get(t).contains<occupied>())
|
||||
{
|
||||
auto & item = map_.items.emplace_back();
|
||||
item.type = source->type;
|
||||
item.start = pos;
|
||||
item.target = pos;
|
||||
map_.grid.item_target(pos) = true;
|
||||
auto i = map_.world.create(
|
||||
item{s.type, p}
|
||||
);
|
||||
|
||||
map_.world.attach(t, occupied{i});
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
for (auto & task : map_.tasks)
|
||||
|
||||
map_.world.apply<task>([&](task & t)
|
||||
{
|
||||
auto & received = task.second.received;
|
||||
auto threshold = map_.time;
|
||||
threshold.trunc -= 60 / task::freq;
|
||||
while (!received.empty() && received.front() < threshold)
|
||||
received.pop_front();
|
||||
}
|
||||
while (!t.received.empty() && t.received.front() < threshold)
|
||||
t.received.pop_front();
|
||||
});
|
||||
|
||||
std::vector<item> alive_items;
|
||||
for (auto item : map_.items)
|
||||
map_.world.apply<item>([&](ecs::handle entity, item & i)
|
||||
{
|
||||
if (item.start != item.target)
|
||||
if (i.target)
|
||||
{
|
||||
item.pos += 3.f * dt;
|
||||
i.state += 3.f * dt;
|
||||
if (i.state < 1.f)
|
||||
return;
|
||||
|
||||
if (item.pos < 1.f)
|
||||
{
|
||||
alive_items.push_back(item);
|
||||
continue;
|
||||
}
|
||||
i.state -= 1.f;
|
||||
|
||||
item.pos -= 1.f;
|
||||
}
|
||||
|
||||
if (item_within_grid(item.target))
|
||||
map_.grid.item_target(item.target) = false;
|
||||
|
||||
auto cell = item_to_cell(item.target);
|
||||
|
||||
if (map_.tasks.contains(cell))
|
||||
{
|
||||
if (map_.tasks.at(cell).type == item.type)
|
||||
map_.tasks.at(cell).received.push_back(map_.time);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (item_within_grid(item.target) && item.target == cell_center_to_item(cell))
|
||||
{
|
||||
if (auto factory = std::get_if<gmtk::factory>(&map_.grid.tiles(cell)))
|
||||
{
|
||||
if (factory->input == item.type)
|
||||
item.type = factory->output;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<geom::point<int, 2>> targets;
|
||||
|
||||
if (geom::imod(item.target[0], 3) == 1 && geom::imod(item.target[1], 3) == 1)
|
||||
{
|
||||
for (auto q : map_.grid.belts(cell))
|
||||
{
|
||||
auto t = item.target + (q - cell);
|
||||
if (!item_within_grid(t) || !map_.grid.item_target(t))
|
||||
targets.push_back(t);
|
||||
}
|
||||
i.start = map_.world.get(i.target).get<path_vertex const>().location;
|
||||
map_.world.detach<occupied>(i.target);
|
||||
i.target = ecs::handle::null();
|
||||
}
|
||||
else
|
||||
{
|
||||
auto s = item.target;
|
||||
if (geom::imod(s[0], 3) == 0)
|
||||
s[0] -= 1;
|
||||
else if (geom::imod(s[0], 3) == 2)
|
||||
s[0] += 1;
|
||||
else if (geom::imod(s[1], 3) == 0)
|
||||
s[1] -= 1;
|
||||
else if (geom::imod(s[1], 3) == 2)
|
||||
s[1] += 1;
|
||||
|
||||
if (!item_within_grid(s) || !map_.grid.item_target(s))
|
||||
if (within_grid(item_to_cell(item.target)) && map_.grid.belts(item_to_cell(item.target)).contains(item_to_cell(s)))
|
||||
targets.push_back(s);
|
||||
|
||||
auto t = item.target - (s - item.target);
|
||||
|
||||
if (!item_within_grid(t) || !map_.grid.item_target(t))
|
||||
if (within_grid(item_to_cell(s)) && map_.grid.belts(item_to_cell(s)).contains(item_to_cell(item.target)))
|
||||
targets.push_back(t);
|
||||
map_.world.detach<occupied>(map_.world.index<path_index>().get(i.start));
|
||||
}
|
||||
|
||||
item.start = item.target;
|
||||
if (auto cell = map_.world.index<index>().find(i.start.up()))
|
||||
{
|
||||
if (auto t = map_.world.get(*cell).get_if<task>())
|
||||
{
|
||||
if (t->type == i.type)
|
||||
t->received.push_back(map_.time);
|
||||
map_.world.destroy(entity);
|
||||
return;
|
||||
}
|
||||
|
||||
if (auto t = map_.world.get(*cell).get_if<transformer>())
|
||||
{
|
||||
if (t->input == i.type)
|
||||
i.type = t->output;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<ecs::handle> targets;
|
||||
|
||||
for (auto b : map_.world.get(map_.world.index<path_index>().get(i.start)).get<path_vertex>().belts)
|
||||
if (!map_.world.get(b).contains<occupied>())
|
||||
targets.push_back(b);
|
||||
|
||||
if (!targets.empty())
|
||||
item.target = random::uniform_from(rng_, targets);
|
||||
i.target = random::uniform_from(rng_, targets);
|
||||
|
||||
if (item_within_grid(item.target))
|
||||
map_.grid.item_target(item.target) = true;
|
||||
alive_items.push_back(item);
|
||||
}
|
||||
map_.items = std::move(alive_items);
|
||||
if (i.target)
|
||||
map_.world.attach(i.target, occupied{entity});
|
||||
else
|
||||
map_.world.attach(map_.world.index<path_index>().get(i.start), occupied{entity});
|
||||
});
|
||||
|
||||
float aspect_ratio = (screen_size_[0] * 1.f) / screen_size_[1];
|
||||
|
||||
|
|
@ -563,9 +602,9 @@ namespace gmtk
|
|||
int y = std::floor(m[1]);
|
||||
|
||||
if (x >= 0 && x < 3 && y >= 0 && y < 3)
|
||||
selected_ = geom::point{x, y};
|
||||
else if (map_.tasks.contains({x, y}))
|
||||
selected_ = geom::point{x, y};
|
||||
selected_ = {0, geom::point{x, y}};
|
||||
else if (map_.world.index<index>().find({0, {x, y}}))
|
||||
selected_ = {0, geom::point{x, y}};
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -597,8 +636,8 @@ namespace gmtk
|
|||
|
||||
geom::box<float, 2> view_box_;
|
||||
|
||||
std::optional<geom::point<int, 2>> selected_;
|
||||
std::optional<geom::point<int, 2>> belt_start_;
|
||||
std::optional<location> selected_;
|
||||
std::optional<location> belt_start_;
|
||||
|
||||
geom::point<float, 2> screen_to_grid(geom::point<float, 2> const & p)
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue