Exploring raycasters and possibly make a little "doom like" game based on it.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
raycaster/tests/spatialmap.cpp

168 lines
4.4 KiB

#include <catch2/catch_test_macros.hpp>
#include <fmt/core.h>
#include <string>
#include "spatialmap.hpp"
#include "dinkyecs.hpp"
#include "rand.hpp"
using DinkyECS::Entity;
using namespace fmt;
EntityList require_found(const SpatialMap& collider, Point at, bool diag, size_t expect_size) {
println("TEST require_found at={},{}", at.x, at.y);
auto [found, nearby] = collider.neighbors(at, diag);
REQUIRE(found == true);
REQUIRE(nearby.size() == expect_size);
return nearby;
}
TEST_CASE("confirm basic collision operations", "[collision]") {
DinkyECS::World world;
Entity player = world.entity();
Entity enemy = world.entity();
SpatialMap collider;
collider.insert({11,11}, player);
collider.insert({21,21}, enemy);
{ // not found
auto [found, nearby] = collider.neighbors({1,1});
REQUIRE(!found);
REQUIRE(nearby.empty());
}
// found
EntityList nearby = require_found(collider, {10,10}, true, 1);
REQUIRE(nearby[0] == player);
{ // removed
collider.remove({11,11});
auto [found, nearby] = collider.neighbors({10,10}, true);
REQUIRE(!found);
REQUIRE(nearby.empty());
}
collider.insert({11,11}, player); // setup for the move test
{ // moving, not found
collider.move({11,11}, {12, 12}, player);
auto [found, nearby] = collider.neighbors({10,10}, true);
REQUIRE(!found);
REQUIRE(nearby.empty());
}
nearby = require_found(collider, {11,11}, true, 1);
REQUIRE(nearby[0] == player);
// confirm occupied works
REQUIRE(collider.occupied({12,12}));
REQUIRE(collider.occupied({21,21}));
REQUIRE(!collider.occupied({1,10}));
REQUIRE(collider.get({12,12}) == player);
}
TEST_CASE("confirm multiple entities moving", "[collision]") {
DinkyECS::World world;
Entity player = world.entity();
Entity e1 = world.entity();
Entity e2 = world.entity();
Entity e3 = world.entity();
SpatialMap collider;
collider.insert({11,11}, player);
collider.insert({10,10}, e2);
collider.insert({11,10}, e3);
collider.insert({21,21}, e1);
EntityList nearby = require_found(collider, {11,11}, false, 1);
REQUIRE(nearby[0] == e3);
nearby = require_found(collider, {11,11}, true, 2);
REQUIRE(nearby[0] == e3);
REQUIRE(nearby[1] == e2);
collider.move({11,11}, {20,20}, player);
nearby = require_found(collider, {20,20}, true, 1);
REQUIRE(nearby[0] == e1);
}
TEST_CASE("test edge cases that might crash", "[collision]") {
DinkyECS::World world;
Entity player = world.entity();
Entity enemy = world.entity();
SpatialMap collider;
collider.insert({0,0}, player);
Point enemy_at = {1, 0};
collider.insert(enemy_at, enemy);
EntityList nearby = require_found(collider, {0,0}, true, 1);
collider.move({1,0}, {1,1}, enemy);
nearby = require_found(collider, {0,0}, true, 1);
REQUIRE(nearby[0] == enemy);
collider.move({1,1}, {0,1}, enemy);
nearby = require_found(collider, {0,0}, true, 1);
REQUIRE(nearby[0] == enemy);
}
TEST_CASE("check all diagonal works", "[collision]") {
DinkyECS::World world;
Entity player = world.entity();
Entity enemy = world.entity();
SpatialMap collider;
Point player_at = {1,1};
collider.insert(player_at, player);
Point enemy_at = {1, 0};
collider.insert(enemy_at, enemy);
for(size_t x = 0; x <= 2; x++) {
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
EntityList nearby = require_found(collider, player_at, true, 1);
REQUIRE(nearby[0] == enemy);
// move the enemy to a new spot around the player
Point move_to = {enemy_at.x + x, enemy_at.y + y};
collider.move(enemy_at, move_to, enemy);
enemy_at = move_to;
}
}
}
TEST_CASE("confirm can iterate through all", "[spatialmap-sort]") {
DinkyECS::World world;
SpatialMap collider;
Point player{10,10};
for(int i = 0; i < 10; i++) {
size_t max = Random::uniform<size_t>(2,30);
for(size_t i = 0; i < max; i++) {
size_t x = Random::uniform<size_t>(0, 213);
size_t y = Random::uniform<size_t>(0, 251);
Entity ent = world.entity();
collider.insert({x,y}, ent);
}
auto sprite_distance = collider.distance_sorted(player, 1000);
// sometimes there's nothing near us
if(sprite_distance.size() == 0) continue;
int prev_dist = sprite_distance[0].first;
for(auto dist : sprite_distance) {
REQUIRE(prev_dist >= dist.first);
prev_dist = dist.first;
}
}
}