Files are now in a src directory and I'm using a src/meson.build and tests/meson.build to specify what to build.
This commit is contained in:
parent
4778677647
commit
1d4ae911b9
108 changed files with 94 additions and 83 deletions
138
src/spatialmap.cpp
Normal file
138
src/spatialmap.cpp
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
#include "spatialmap.hpp"
|
||||
#include <fmt/core.h>
|
||||
|
||||
using namespace fmt;
|
||||
|
||||
using DinkyECS::Entity;
|
||||
|
||||
void SpatialMap::insert(Point pos, Entity ent, bool has_collision) {
|
||||
if(has_collision) {
|
||||
dbc::check(!occupied(pos), "attempt to insert an entity with collision in space with collision");
|
||||
}
|
||||
|
||||
$collision.emplace(pos, CollisionData{ent, has_collision});
|
||||
}
|
||||
|
||||
CollisionData SpatialMap::remove(Point pos, Entity ent) {
|
||||
auto [begin, end] = $collision.equal_range(pos);
|
||||
for(auto it = begin; it != end; ++it) {
|
||||
if(it->second.entity == ent) {
|
||||
// does the it->second go invalid after erase?
|
||||
auto copy = it->second;
|
||||
$collision.erase(it);
|
||||
return copy;
|
||||
}
|
||||
}
|
||||
|
||||
dbc::sentinel("failed to find entity to remove");
|
||||
}
|
||||
|
||||
void SpatialMap::move(Point from, Point to, Entity ent) {
|
||||
auto data = remove(from, ent);
|
||||
insert(to, ent, data.collision);
|
||||
}
|
||||
|
||||
Entity SpatialMap::occupied_by(Point at) const {
|
||||
auto [begin, end] = $collision.equal_range(at);
|
||||
for(auto it = begin; it != end; ++it) {
|
||||
if(it->second.collision) {
|
||||
return it->second.entity;
|
||||
}
|
||||
}
|
||||
|
||||
return DinkyECS::NONE;
|
||||
}
|
||||
|
||||
bool SpatialMap::occupied(Point at) const {
|
||||
return occupied_by(at) != DinkyECS::NONE;
|
||||
}
|
||||
|
||||
bool SpatialMap::something_there(Point at) const {
|
||||
return $collision.count(at) > 0;
|
||||
}
|
||||
|
||||
Entity SpatialMap::get(Point at) const {
|
||||
dbc::check($collision.contains(at), "attempt to get entity when none there");
|
||||
auto [begin, end] = $collision.equal_range(at);
|
||||
return begin->second.entity;
|
||||
}
|
||||
|
||||
void SpatialMap::find_neighbor(EntityList &result, Point at, int dy, int dx) const {
|
||||
// don't bother checking for cells out of bounds
|
||||
if((dx < 0 && at.x <= 0) || (dy < 0 && at.y <= 0)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Point cell = {at.x + dx, at.y + dy};
|
||||
|
||||
auto entity = find(cell, [&](auto data) {
|
||||
return data.collision;
|
||||
});
|
||||
|
||||
if(entity != DinkyECS::NONE) result.push_back(entity);
|
||||
}
|
||||
|
||||
FoundEntities SpatialMap::neighbors(Point cell, bool diag) const {
|
||||
EntityList result;
|
||||
|
||||
// just unroll the loop since we only check four directions
|
||||
// this also solves the problem that it was detecting that the cell was automatically included as a "neighbor" but it's not
|
||||
find_neighbor(result, cell, 0, 1); // north
|
||||
find_neighbor(result, cell, 0, -1); // south
|
||||
find_neighbor(result, cell, 1, 0); // east
|
||||
find_neighbor(result, cell, -1, 0); // west
|
||||
|
||||
if(diag) {
|
||||
find_neighbor(result, cell, 1, -1); // south east
|
||||
find_neighbor(result, cell, -1, -1); // south west
|
||||
find_neighbor(result, cell, 1, 1); // north east
|
||||
find_neighbor(result, cell, -1, 1); // north west
|
||||
}
|
||||
|
||||
return {!result.empty(), result};
|
||||
}
|
||||
|
||||
inline void update_sorted(SortedEntities& sprite_distance, PointEntityMap& table, Point from, int max_dist) {
|
||||
Point seen{0,0};
|
||||
float wiggle = 0.0f;
|
||||
|
||||
for(const auto &rec : table) {
|
||||
Point sprite = rec.first;
|
||||
|
||||
int inside = (from.x - sprite.x) * (from.x - sprite.x) +
|
||||
(from.y - sprite.y) * (from.y - sprite.y);
|
||||
|
||||
if(from == sprite || rec.second.collision) {
|
||||
wiggle = 0.0f;
|
||||
} else if(sprite == seen) {
|
||||
wiggle += 0.02f;
|
||||
} else {
|
||||
wiggle = 0.0f;
|
||||
seen = sprite;
|
||||
}
|
||||
|
||||
if(inside < max_dist) {
|
||||
sprite_distance.push_back({inside, rec.second.entity, wiggle});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Entity SpatialMap::find(Point at, std::function<bool(CollisionData)> cb) const {
|
||||
auto [begin, end] = $collision.equal_range(at);
|
||||
|
||||
for(auto it = begin; it != end; ++it) {
|
||||
if(cb(it->second)) return it->second.entity;
|
||||
}
|
||||
|
||||
return DinkyECS::NONE;
|
||||
}
|
||||
|
||||
void SpatialMap::distance_sorted(SortedEntities& sprite_distance, Point from, int max_dist) {
|
||||
sprite_distance.clear();
|
||||
|
||||
update_sorted(sprite_distance, $collision, from, max_dist);
|
||||
|
||||
std::sort(sprite_distance.begin(), sprite_distance.end(), [](auto &a, auto &b) {
|
||||
return a.dist_square > b.dist_square;
|
||||
});
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue