Refactor some code to have better naming and move Point and related point things into their own .hpp.

main
Zed A. Shaw 11 months ago
parent c19cd707d1
commit 5a123ae74c
  1. 14
      collider.cpp
  2. 14
      collider.hpp
  3. 4
      gui.cpp
  4. 11
      map.hpp
  5. 18
      point.hpp
  6. 6
      systems.cpp
  7. 18
      tests/collider.cpp

@ -5,20 +5,20 @@ using namespace fmt;
using DinkyECS::Entity; using DinkyECS::Entity;
void SpatialHashTable::insert(Point pos, Entity ent) { void spatial_map::insert(Point pos, Entity ent) {
table[pos] = ent; table[pos] = ent;
} }
void SpatialHashTable::remove(Point pos) { void spatial_map::remove(Point pos) {
table.erase(pos); table.erase(pos);
} }
void SpatialHashTable::move(Point from, Point to, Entity ent) { void spatial_map::move(Point from, Point to, Entity ent) {
remove(from); remove(from);
insert(to, ent); insert(to, ent);
} }
bool SpatialHashTable::occupied(Point at) const { bool spatial_map::occupied(Point at) const {
return table.contains(at); return table.contains(at);
} }
@ -27,7 +27,7 @@ bool SpatialHashTable::occupied(Point at) const {
* at.x or at.y is > 0. If either is 0 then there can't be * at.x or at.y is > 0. If either is 0 then there can't be
* a neighbor since that's out of bounds. * a neighbor since that's out of bounds.
*/ */
inline void find_neighbor(const PointEntityMap &table, FoundList &result, Point at, int dy, int dx) { inline void find_neighbor(const PointEntityMap &table, EntityList &result, Point at, int dy, int dx) {
// don't bother checking for cells out of bounds // don't bother checking for cells out of bounds
if((dx < 0 && at.x <= 0) || (dy < 0 && at.y <= 0)) { if((dx < 0 && at.x <= 0) || (dy < 0 && at.y <= 0)) {
return; return;
@ -41,8 +41,8 @@ inline void find_neighbor(const PointEntityMap &table, FoundList &result, Point
} }
} }
std::tuple<bool, FoundList> SpatialHashTable::neighbors(Point cell, bool diag) const { std::tuple<bool, EntityList> spatial_map::neighbors(Point cell, bool diag) const {
FoundList result; EntityList result;
// just unroll the loop since we only check four directions // 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 // this also solves the problem that it was detecting that the cell was automatically included as a "neighbor" but it's not

@ -3,26 +3,22 @@
#include <unordered_map> #include <unordered_map>
#include "map.hpp" #include "map.hpp"
#include "dinkyecs.hpp" #include "dinkyecs.hpp"
#include "point.hpp"
#include <tuple> #include <tuple>
struct PointHash { typedef std::vector<DinkyECS::Entity> EntityList;
size_t operator()(const Point& p) const {
return std::hash<int>()(p.x) ^ std::hash<int>()(p.y);
}
};
typedef std::vector<DinkyECS::Entity> FoundList;
typedef std::unordered_map<Point, DinkyECS::Entity, PointHash> PointEntityMap; typedef std::unordered_map<Point, DinkyECS::Entity, PointHash> PointEntityMap;
class SpatialHashTable { class spatial_map {
public: public:
SpatialHashTable() {} spatial_map() {}
void insert(Point pos, DinkyECS::Entity obj); void insert(Point pos, DinkyECS::Entity obj);
void move(Point from, Point to, DinkyECS::Entity ent); void move(Point from, Point to, DinkyECS::Entity ent);
void remove(Point pos); void remove(Point pos);
bool occupied(Point pos) const; bool occupied(Point pos) const;
std::tuple<bool, FoundList> neighbors(Point position, bool diag=false) const; std::tuple<bool, EntityList> neighbors(Point position, bool diag=false) const;
private: private:
PointEntityMap table; PointEntityMap table;

@ -278,8 +278,8 @@ void GUI::configure_world() {
ActionLog log{{"Welcome to the game!"}}; ActionLog log{{"Welcome to the game!"}};
$world.set<ActionLog>(log); $world.set<ActionLog>(log);
SpatialHashTable collider; spatial_map collider;
$world.set<SpatialHashTable>(collider); $world.set<spatial_map>(collider);
$world.assign<Position>(player.entity, {$game_map.place_entity(0)}); $world.assign<Position>(player.entity, {$game_map.place_entity(0)});
$world.assign<Motion>(player.entity, {0, 0}); $world.assign<Motion>(player.entity, {0, 0});

@ -5,6 +5,7 @@
#include <random> #include <random>
#include <algorithm> #include <algorithm>
#include <fmt/core.h> #include <fmt/core.h>
#include "point.hpp"
#define INV_WALL 0 #define INV_WALL 0
#define INV_SPACE 1 #define INV_SPACE 1
@ -15,15 +16,6 @@
#define PLAYER_TILE "☺" #define PLAYER_TILE "☺"
#define ENEMY_TILE "Ω" #define ENEMY_TILE "Ω"
struct Point {
size_t x = 0;
size_t y = 0;
bool operator==(const Point& other) const {
return other.x == x && other.y == y;
}
};
struct Room { struct Room {
size_t x = 0; size_t x = 0;
size_t y = 0; size_t y = 0;
@ -33,7 +25,6 @@ struct Room {
Point exit; Point exit;
}; };
typedef std::vector<Point> PointList;
typedef std::vector<int> MatrixRow; typedef std::vector<int> MatrixRow;
typedef std::vector<MatrixRow> Matrix; typedef std::vector<MatrixRow> Matrix;

@ -0,0 +1,18 @@
#pragma once
struct Point {
size_t x = 0;
size_t y = 0;
bool operator==(const Point& other) const {
return other.x == x && other.y == y;
}
};
typedef std::vector<Point> PointList;
struct PointHash {
size_t operator()(const Point& p) const {
return std::hash<int>()(p.x) ^ std::hash<int>()(p.y);
}
};

@ -26,7 +26,7 @@ void System::enemy_pathing(DinkyECS::World &world, Map &game_map, Player &player
} }
void System::init_positions(DinkyECS::World &world) { void System::init_positions(DinkyECS::World &world) {
auto &collider = world.get<SpatialHashTable>(); auto &collider = world.get<spatial_map>();
world.system<Position>([&](const auto &ent, auto &pos) { world.system<Position>([&](const auto &ent, auto &pos) {
collider.insert(pos.location, ent); collider.insert(pos.location, ent);
@ -34,7 +34,7 @@ void System::init_positions(DinkyECS::World &world) {
} }
void System::motion(DinkyECS::World &world, Map &game_map) { void System::motion(DinkyECS::World &world, Map &game_map) {
auto &collider = world.get<SpatialHashTable>(); auto &collider = world.get<spatial_map>();
world.system<Position, Motion>([&](const auto &ent, auto &position, auto &motion) { world.system<Position, Motion>([&](const auto &ent, auto &position, auto &motion) {
// don't process entities that don't move // don't process entities that don't move
@ -58,7 +58,7 @@ void System::motion(DinkyECS::World &world, Map &game_map) {
void System::combat(DinkyECS::World &world, Player &player) { void System::combat(DinkyECS::World &world, Player &player) {
const auto& collider = world.get<SpatialHashTable>(); const auto& collider = world.get<spatial_map>();
const auto& player_position = world.component<Position>(player.entity); const auto& player_position = world.component<Position>(player.entity);
auto& player_combat = world.component<Combat>(player.entity); auto& player_combat = world.component<Combat>(player.entity);
auto& log = world.get<ActionLog>(); auto& log = world.get<ActionLog>();

@ -7,7 +7,7 @@
using DinkyECS::Entity; using DinkyECS::Entity;
using namespace fmt; using namespace fmt;
FoundList require_found(const SpatialHashTable& collider, Point at, bool diag, size_t expect_size) { EntityList require_found(const spatial_map& collider, Point at, bool diag, size_t expect_size) {
println("TEST require_found at={},{}", at.x, at.y); println("TEST require_found at={},{}", at.x, at.y);
auto [found, nearby] = collider.neighbors(at, diag); auto [found, nearby] = collider.neighbors(at, diag);
REQUIRE(found == true); REQUIRE(found == true);
@ -21,7 +21,7 @@ TEST_CASE("confirm basic collision operations", "[collision]") {
Entity player = world.entity(); Entity player = world.entity();
Entity enemy = world.entity(); Entity enemy = world.entity();
SpatialHashTable collider; spatial_map collider;
collider.insert({11,11}, player); collider.insert({11,11}, player);
collider.insert({21,21}, enemy); collider.insert({21,21}, enemy);
@ -32,7 +32,7 @@ TEST_CASE("confirm basic collision operations", "[collision]") {
} }
// found // found
FoundList nearby = require_found(collider, {10,10}, true, 1); EntityList nearby = require_found(collider, {10,10}, true, 1);
REQUIRE(nearby[0] == player); REQUIRE(nearby[0] == player);
{ // removed { // removed
@ -68,13 +68,13 @@ TEST_CASE("confirm multiple entities moving", "[collision]") {
Entity e2 = world.entity(); Entity e2 = world.entity();
Entity e3 = world.entity(); Entity e3 = world.entity();
SpatialHashTable collider; spatial_map collider;
collider.insert({11,11}, player); collider.insert({11,11}, player);
collider.insert({10,10}, e2); collider.insert({10,10}, e2);
collider.insert({11,10}, e3); collider.insert({11,10}, e3);
collider.insert({21,21}, e1); collider.insert({21,21}, e1);
FoundList nearby = require_found(collider, {11,11}, false, 1); EntityList nearby = require_found(collider, {11,11}, false, 1);
REQUIRE(nearby[0] == e3); REQUIRE(nearby[0] == e3);
nearby = require_found(collider, {11,11}, true, 2); nearby = require_found(collider, {11,11}, true, 2);
@ -91,13 +91,13 @@ TEST_CASE("test edge cases that might crash", "[collision]") {
Entity player = world.entity(); Entity player = world.entity();
Entity enemy = world.entity(); Entity enemy = world.entity();
SpatialHashTable collider; spatial_map collider;
collider.insert({0,0}, player); collider.insert({0,0}, player);
Point enemy_at = {1, 0}; Point enemy_at = {1, 0};
collider.insert(enemy_at, enemy); collider.insert(enemy_at, enemy);
FoundList nearby = require_found(collider, {0,0}, true, 1); EntityList nearby = require_found(collider, {0,0}, true, 1);
collider.move({1,0}, {1,1}, enemy); collider.move({1,0}, {1,1}, enemy);
nearby = require_found(collider, {0,0}, true, 1); nearby = require_found(collider, {0,0}, true, 1);
@ -113,7 +113,7 @@ TEST_CASE("check all diagonal works", "[collision]") {
Entity player = world.entity(); Entity player = world.entity();
Entity enemy = world.entity(); Entity enemy = world.entity();
SpatialHashTable collider; spatial_map collider;
Point player_at = {1,1}; Point player_at = {1,1};
collider.insert(player_at, player); collider.insert(player_at, player);
@ -123,7 +123,7 @@ TEST_CASE("check all diagonal works", "[collision]") {
for(size_t x = 0; x <= 2; x++) { for(size_t x = 0; x <= 2; x++) {
for(size_t y = 0; y <= 2; y++) { for(size_t y = 0; y <= 2; y++) {
if(enemy_at.x == player_at.x && enemy_at.y == player_at.y) continue; // skip player spot if(enemy_at.x == player_at.x && enemy_at.y == player_at.y) continue; // skip player spot
FoundList nearby = require_found(collider, player_at, true, 1); EntityList nearby = require_found(collider, player_at, true, 1);
REQUIRE(nearby[0] == enemy); REQUIRE(nearby[0] == enemy);
// move the enemy to a new spot around the player // move the enemy to a new spot around the player