IMX6U-Game/tests/game_engine_tests.cpp

440 lines
11 KiB
C++

#include "GameObject.h"
#include "Level.h"
#include "Physics2D.h"
#include "LightEffectSystem.h"
#include "LevelLoader.h"
#include "LevelData.h"
#include <cassert>
#include <iostream>
using namespace LightGame;
namespace
{
void TestGameObjectDefaults()
{
GameObject obj;
assert(obj.id == 0);
assert(obj.type == GameObjectType::StaticPlatform);
assert(obj.position.x == 0);
assert(obj.position.y == 0);
assert(obj.velocity.x == 0);
assert(obj.velocity.y == 0);
assert(obj.sprite == nullptr);
assert(obj.active == true);
assert(obj.solid == true);
assert(obj.flip_h == false);
}
void TestGameObjectWorldCollider()
{
GameObject obj;
obj.position = Math::Vector2Int(100, 200);
obj.collider = RenderData::BoundingBox2D(
Math::Vector2Int(0, 0),
Math::Vector2Int(32, 32));
RenderData::BoundingBox2D world = obj.get_world_collider();
assert(world.min.x == 100);
assert(world.min.y == 200);
assert(world.max.x == 132);
assert(world.max.y == 232);
}
void TestLevelAddAndGet()
{
Level level;
assert(level.object_count() == 0);
GameObject platform;
platform.type = GameObjectType::StaticPlatform;
platform.position = Math::Vector2Int(0, 400);
uint32_t id1 = level.add_object(platform);
assert(id1 == 1);
assert(level.object_count() == 1);
GameObject player;
player.type = GameObjectType::Player;
player.position = Math::Vector2Int(50, 350);
uint32_t id2 = level.add_object(player);
assert(id2 == 2);
assert(level.object_count() == 2);
const GameObject* found = level.get_object(id1);
assert(found != nullptr);
assert(found->type == GameObjectType::StaticPlatform);
assert(found->id == 1);
const GameObject* not_found = level.get_object(999);
assert(not_found == nullptr);
}
void TestLevelRemove()
{
Level level;
GameObject obj;
obj.type = GameObjectType::Collectible;
uint32_t id = level.add_object(obj);
assert(level.object_count() == 1);
level.remove_object(id);
assert(level.object_count() == 0);
assert(level.get_object(id) == nullptr);
}
void TestLevelQueryByType()
{
Level level;
GameObject platform;
platform.type = GameObjectType::StaticPlatform;
level.add_object(platform);
GameObject light_plat;
light_plat.type = GameObjectType::LightPlatform;
level.add_object(light_plat);
GameObject player;
player.type = GameObjectType::Player;
level.add_object(player);
auto platforms = level.get_objects_by_type(GameObjectType::StaticPlatform);
assert(platforms.size() == 1);
assert(platforms[0]->type == GameObjectType::StaticPlatform);
auto players = level.get_objects_by_type(GameObjectType::Player);
assert(players.size() == 1);
auto hazards = level.get_objects_by_type(GameObjectType::Hazard);
assert(hazards.size() == 0);
}
void TestLevelQueryRegion()
{
Level level;
GameObject obj1;
obj1.type = GameObjectType::StaticPlatform;
obj1.position = Math::Vector2Int(100, 100);
obj1.collider = RenderData::BoundingBox2D(
Math::Vector2Int(0, 0), Math::Vector2Int(32, 32));
level.add_object(obj1);
GameObject obj2;
obj2.type = GameObjectType::StaticPlatform;
obj2.position = Math::Vector2Int(500, 500);
obj2.collider = RenderData::BoundingBox2D(
Math::Vector2Int(0, 0), Math::Vector2Int(32, 32));
level.add_object(obj2);
RenderData::BoundingBox2D query(
Math::Vector2Int(80, 80), Math::Vector2Int(200, 200));
auto results = level.query_region(query);
assert(results.size() == 1);
assert(results[0]->position.x == 100);
}
void TestLevelInactiveObjectsExcluded()
{
Level level;
GameObject obj;
obj.type = GameObjectType::Collectible;
obj.active = true;
uint32_t id = level.add_object(obj);
auto active = level.get_objects_by_type(GameObjectType::Collectible);
assert(active.size() == 1);
GameObject* found = level.get_object(id);
found->active = false;
auto active2 = level.get_objects_by_type(GameObjectType::Collectible);
assert(active2.size() == 0);
}
void TestLevelCheckpoints()
{
Level level;
level.set_spawn_point(Math::Vector2Int(50, 300));
Checkpoint cp1(200, 300);
Checkpoint cp2(400, 200);
level.add_checkpoint(cp1);
level.add_checkpoint(cp2);
Math::Vector2Int respawn = level.get_active_checkpoint();
assert(respawn.x == 50);
assert(respawn.y == 300);
level.get_all_objects();
auto& cps = level.get_checkpoints();
const_cast<Checkpoint&>(cps[0]).activated = true;
respawn = level.get_active_checkpoint();
assert(respawn.x == 200);
assert(respawn.y == 300);
const_cast<Checkpoint&>(cps[1]).activated = true;
respawn = level.get_active_checkpoint();
assert(respawn.x == 400);
assert(respawn.y == 200);
}
void TestAabbOverlap()
{
RenderData::BoundingBox2D a(Math::Vector2Int(0, 0), Math::Vector2Int(10, 10));
RenderData::BoundingBox2D b(Math::Vector2Int(5, 5), Math::Vector2Int(15, 15));
assert(aabb_overlap(a, b) == true);
RenderData::BoundingBox2D c(Math::Vector2Int(20, 20), Math::Vector2Int(30, 30));
assert(aabb_overlap(a, c) == false);
RenderData::BoundingBox2D d(Math::Vector2Int(10, 0), Math::Vector2Int(20, 10));
assert(aabb_overlap(a, d) == false);
RenderData::BoundingBox2D e(Math::Vector2Int(9, 0), Math::Vector2Int(19, 10));
assert(aabb_overlap(a, e) == true);
}
void TestGravityAccumulation()
{
Physics2D physics;
PhysicsConfig config;
config.gravity = 1000;
config.max_fall_speed = 500;
physics.set_config(config);
GameObject obj;
obj.velocity = Math::Vector2Int(0, 0);
physics.apply_gravity(obj, 16);
assert(obj.velocity.y > 0);
assert(obj.velocity.y <= config.max_fall_speed);
for (int i = 0; i < 100; ++i)
{
physics.apply_gravity(obj, 16);
}
assert(obj.velocity.y == config.max_fall_speed);
}
void TestGroundDetection()
{
Level level;
level.set_bounds(LevelBounds(0, 0, 800, 600));
GameObject ground;
ground.type = GameObjectType::StaticPlatform;
ground.position = Math::Vector2Int(0, 400);
ground.collider = RenderData::BoundingBox2D(
Math::Vector2Int(0, 0), Math::Vector2Int(800, 32));
ground.solid = true;
level.add_object(ground);
GameObject player;
player.type = GameObjectType::Player;
player.position = Math::Vector2Int(100, 368);
player.collider = RenderData::BoundingBox2D(
Math::Vector2Int(0, 0), Math::Vector2Int(16, 32));
Physics2D physics;
assert(physics.is_grounded(player, level) == true);
player.position = Math::Vector2Int(100, 300);
assert(physics.is_grounded(player, level) == false);
}
void TestOneWayPlatform()
{
Level level;
level.set_bounds(LevelBounds(0, 0, 800, 600));
GameObject platform;
platform.type = GameObjectType::LightPlatform;
platform.position = Math::Vector2Int(100, 300);
platform.collider = RenderData::BoundingBox2D(
Math::Vector2Int(0, 0), Math::Vector2Int(64, 16));
platform.solid = true;
level.add_object(platform);
GameObject player;
player.type = GameObjectType::Player;
player.position = Math::Vector2Int(110, 320);
player.collider = RenderData::BoundingBox2D(
Math::Vector2Int(0, 0), Math::Vector2Int(16, 32));
player.velocity = Math::Vector2Int(0, -100);
Physics2D physics;
physics.move_and_collide(player, level, 16);
assert(player.position.y < 320);
}
void TestLightPlatformActivation()
{
LightEffectSystem system;
GameObject light_plat;
light_plat.type = GameObjectType::LightPlatform;
light_plat.light_threshold.min_level = 2000;
light_plat.solid = false;
std::vector<GameObject> objects;
objects.push_back(light_plat);
system.update(objects, 1000);
assert(objects[0].solid == false);
system.update(objects, 2500);
assert(objects[0].solid == true);
system.update(objects, 2000);
assert(objects[0].solid == true);
}
void TestShadowPlatformActivation()
{
LightEffectSystem system;
GameObject shadow_plat;
shadow_plat.type = GameObjectType::ShadowPlatform;
shadow_plat.light_threshold.max_level = 1000;
shadow_plat.solid = true;
std::vector<GameObject> objects;
objects.push_back(shadow_plat);
system.update(objects, 2000);
assert(objects[0].solid == false);
system.update(objects, 500);
assert(objects[0].solid == true);
system.update(objects, 1000);
assert(objects[0].solid == true);
}
void TestLightDoorOpen()
{
LightEffectSystem system;
GameObject door;
door.type = GameObjectType::Door;
door.light_threshold.min_level = 1500;
door.light_threshold.max_level = 2500;
door.solid = true;
std::vector<GameObject> objects;
objects.push_back(door);
system.update(objects, 1000);
assert(objects[0].solid == true);
system.update(objects, 2000);
assert(objects[0].solid == false);
system.update(objects, 3000);
assert(objects[0].solid == true);
system.update(objects, 1500);
assert(objects[0].solid == false);
system.update(objects, 2500);
assert(objects[0].solid == false);
}
void TestLightEffectIgnoresOtherTypes()
{
LightEffectSystem system;
GameObject platform;
platform.type = GameObjectType::StaticPlatform;
platform.solid = true;
GameObject hazard;
hazard.type = GameObjectType::Hazard;
hazard.solid = true;
std::vector<GameObject> objects;
objects.push_back(platform);
objects.push_back(hazard);
system.update(objects, 0);
assert(objects[0].solid == true);
assert(objects[1].solid == true);
system.update(objects, 4095);
assert(objects[0].solid == true);
assert(objects[1].solid == true);
}
void TestLevelLoaderBasic()
{
const uint16_t tiles[] = {
0, 0, 0,
0, 0, 0,
1, 1, 1,
};
const ObjectSpawn spawns[] = {
{ GameObjectType::Player, 1, 1, 0, 0, TriggerAction::None, 0 },
{ GameObjectType::StaticPlatform, 0, 2, 0, 0, TriggerAction::None, 0 },
};
const LevelData data = {
tiles,
3,
3,
16,
nullptr,
0,
spawns,
2,
Math::Vector2Int(16, 16),
0,
0,
48,
48
};
Level level;
LevelLoader::load(level, data);
assert(level.object_count() == 2);
assert(level.get_bounds().max_x == 48);
assert(level.get_bounds().max_y == 48);
assert(level.get_spawn_point().x == 16);
assert(level.get_spawn_point().y == 16);
const RenderData::Tilemap& tm = level.get_tilemap();
assert(tm.width == 3);
assert(tm.height == 3);
assert(tm.tiles == tiles);
}
}
int main()
{
TestGameObjectDefaults();
TestGameObjectWorldCollider();
TestLevelAddAndGet();
TestLevelRemove();
TestLevelQueryByType();
TestLevelQueryRegion();
TestLevelInactiveObjectsExcluded();
TestLevelCheckpoints();
TestAabbOverlap();
TestGravityAccumulation();
TestGroundDetection();
TestOneWayPlatform();
TestLightPlatformActivation();
TestShadowPlatformActivation();
TestLightDoorOpen();
TestLightEffectIgnoresOtherTypes();
TestLevelLoaderBasic();
std::cout << "game_engine_tests: PASS\n";
return 0;
}