#include "GameObject.h" #include "Level.h" #include "Physics2D.h" #include "LightEffectSystem.h" #include "LevelLoader.h" #include "LevelData.h" #include #include 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(cps[0]).activated = true; respawn = level.get_active_checkpoint(); assert(respawn.x == 200); assert(respawn.y == 300); const_cast(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 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 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 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 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; }