#include #include #include #include "spatialmap.hpp" #include "dinkyecs.hpp" #include "rand.hpp" #include using DinkyECS::Entity; using namespace fmt; TEST_CASE("SpatialMap::insert", "[spatialmap]") { DinkyECS::World world; SpatialMap map; auto player = world.entity(); auto item = world.entity(); auto potion = world.entity(); auto enemy = world.entity(); Point at{10,10}; Point enemy_at{11,11}; map.insert(at, item, false); map.insert(at, potion, false); REQUIRE(!map.occupied(at)); map.insert(at, player, true); REQUIRE(map.occupied(at)); REQUIRE_THROWS(map.insert(at, enemy, true)); map.insert(enemy_at, enemy, true); REQUIRE(map.occupied(enemy_at)); } TEST_CASE("SpatialMap::remove", "[spatialmap]") { DinkyECS::World world; SpatialMap map; auto player = world.entity(); auto item = world.entity(); Point at{120, 120}; // confirm that things can be in any order map.insert(at, player, true); map.insert(at, item, false); REQUIRE(map.occupied(at)); auto data = map.remove(at, player); REQUIRE(!map.occupied(at)); REQUIRE(data.entity == player); REQUIRE(data.collision == true); REQUIRE_THROWS(map.remove(at, player)); } TEST_CASE("SpatialMap::move", "[spatialmap]") { DinkyECS::World world; SpatialMap map; auto player = world.entity(); auto item = world.entity(); Point at{10, 320}; map.insert(at, player, true); map.insert(at, item, false); REQUIRE(map.occupied(at)); auto enemy = world.entity(); auto potion = world.entity(); Point enemy_at{11, 320}; map.insert(enemy_at, enemy, true); map.insert(enemy_at, potion, false); REQUIRE(map.occupied(enemy_at)); Point target{at.x + 1, at.y}; // try bad move with a slot that's empty REQUIRE_THROWS(map.move({0,0}, target, player)); // try move into an occupied spot also fails REQUIRE_THROWS(map.move(at, target, player)); // now move to a new spot, need to add them back map.insert(at, player, true); target.x++; // just move farther map.move(at, target, player); REQUIRE(map.occupied(target)); auto data = map.remove(target, player); REQUIRE(data.entity == player); REQUIRE(data.collision == true); } TEST_CASE("SpatialMap::occupied/something_there", "[spatialmap]") { DinkyECS::World world; SpatialMap map; auto player = world.entity(); auto item = world.entity(); Point at{1000, 20}; // first test empty locations REQUIRE(!map.something_there(at)); REQUIRE(!map.occupied(at)); // then when there's something without collision map.insert(at, item, false); REQUIRE(map.something_there(at)); REQUIRE(!map.occupied(at)); // finally with collision and an item there map.insert(at, player, true); REQUIRE(map.something_there(at)); REQUIRE(map.occupied(at)); // then remove the item and still have collision map.remove(at, item); REQUIRE(map.something_there(at)); REQUIRE(map.occupied(at)); // remove player and back to no collision map.remove(at, player); REQUIRE(!map.something_there(at)); REQUIRE(!map.occupied(at)); // last thing, put just the player in at a new spot Point target{at.x+1, at.y+10}; map.insert(target, player, true); REQUIRE(map.something_there(target)); REQUIRE(map.occupied(target)); } TEST_CASE("SpatialMap::get", "[spatialmap]") { DinkyECS::World world; SpatialMap map; auto player = world.entity(); auto item = world.entity(); Point at{101, 31}; // finally with collision and an item there map.insert(at, player, true); REQUIRE(map.occupied(at)); auto entity = map.get(at); REQUIRE(player == entity); // This probably doesn't work so need to // rethink how get works. map.insert(at, item, false); entity = map.get(at); REQUIRE(entity == item); } TEST_CASE("SpatialMap::neighbors", "[spatialmap]") { DinkyECS::World world; SpatialMap map; auto player = world.entity(); auto enemy1 = world.entity(); auto enemy2 = world.entity(); //auto item1 = world.entity(); //auto item2 = world.entity(); Point at{101, 31}; map.insert(at, player, true); map.insert({at.x+1, at.y}, enemy1, true); map.insert({at.x-1, at.y+1}, enemy2, true); auto result = map.neighbors(at, true); REQUIRE(result.found); REQUIRE(result.nearby.size() > 0); bool maybe = result.nearby[0] == enemy1 || result.nearby[1] == enemy1; REQUIRE(maybe); maybe = result.nearby[0] == enemy2 || result.nearby[1] == enemy2; REQUIRE(maybe); result = map.neighbors(at, false); REQUIRE(result.found); REQUIRE(result.nearby.size() == 1); REQUIRE(result.nearby[0] == enemy1); } TEST_CASE("SpatialMap::distance_sorted", "[spatialmap]") { DinkyECS::World world; SpatialMap map; auto player = world.entity(); auto enemy1 = world.entity(); auto item = world.entity(); map.insert({1,1}, player, true); map.insert({4,4}, enemy1, true); map.insert({3, 3}, item, false); auto result = map.distance_sorted({1, 1}, 100); REQUIRE(result.size() == 3); REQUIRE(result[0].entity == enemy1); REQUIRE(result[1].entity == item); REQUIRE(result[2].entity == player); int prev_dist = std::numeric_limits::max(); for(auto rec : result) { REQUIRE(rec.dist_square < prev_dist); prev_dist = rec.dist_square; } }