feat: add debug rendering for other types of colliders / split game into more logical functions / files

This commit is contained in:
2026-10-16 15:08:10 +02:00
parent 4c9b77c948
commit 469bb287b7
32 changed files with 42809 additions and 882 deletions
+84
View File
@@ -30,6 +30,8 @@
#include <destrum/Components/Physics/Collider.h>
#include <destrum/Components/Animator.h>
#include <destrum/Components/CameraComponent.h>
#include <destrum/Graphics/Resources/PrimitiveMeshes.h>
#include <destrum/Graphics/Managers/LineRenderingManager.h>
#include <destrum/Components/LightComponent.h>
#include <destrum/Components/Physics/Rigidbody.h>
#include <destrum/Graphics/Material.h>
@@ -429,6 +431,85 @@ namespace {
SceneManager::GetInstance().Destroy();
}
void testCapsuleColliderDebugLines()
{
GameObject object{"capsule"};
object.GetTransform().SetWorldPosition({1.0f, 2.0f, 3.0f});
object.GetTransform().SetWorldScale(glm::vec3{5.0f});
auto* capsule = object.AddComponent<CapsuleCollider>(0.4f, 1.8f);
capsule->SetCenterOffset({0.0f, 0.5f, 0.0f});
auto& lines = LineRenderingManager::GetInstance();
lines.ClearLines();
capsule->DrawDebugLines(glm::vec4{1.0f});
const glm::vec3 center{1.0f, 2.5f, 3.0f};
float top = -1000.0f;
float bottom = 1000.0f;
bool inside = true;
for (const Line& line : lines.GetLines()) {
for (const glm::vec3& point : {line.start, line.end}) {
const glm::vec3 local = point - center;
top = std::max(top, local.y);
bottom = std::min(bottom, local.y);
inside = inside && glm::length(glm::vec2{local.x, local.z}) <= 0.4f + 0.001f;
}
}
lines.ClearLines();
check(inside && close(top, 0.9f) && close(bottom, -0.9f),
"capsule debug lines must match the collider shape in world units, ignoring the object scale");
}
void testColliderCenterOffset()
{
Scene& scene = SceneManager::GetInstance().CreateScene("collider-offset");
GameObject* box = scene.CreateGameObject("offset box");
box->AddComponent<BoxCollider>(glm::vec3{0.5f})->SetCenterOffset({0.0f, 5.0f, 0.0f});
box->AddComponent<Rigidbody>()->SetType(RigidbodyType::Static);
scene.CommitPendingAdditions();
scene.GetPhysics().RefreshGameObject(*box);
PhysicsRaycastHit hit{};
const bool found = box->GetComponent<Rigidbody>()->GetPhysicsWorld()->Raycast(
{0.0f, 10.0f, 0.0f}, {0.0f, -1.0f, 0.0f}, 20.0f, hit);
check(found && std::abs(hit.distance - 4.5f) < 0.01f,
"a collider center offset must move the shape, not just the center of mass");
SceneManager::GetInstance().Destroy();
}
void testPrimitiveBoxMesh()
{
const glm::vec3 size{4.0f, 1.0f, 2.0f};
const CPUMesh box = PrimitiveMeshes::MakeBox(size);
check(box.vertices.size() == 24 && box.indices.size() == 36, "a box must have 6 faces of 2 triangles");
check(box.minPos == -size * 0.5f && box.maxPos == size * 0.5f, "a box must be centered on the origin");
float maxU = 0.0f;
bool outward = true;
for (const auto& vertex : box.vertices) {
if (vertex.normal == glm::vec3{0.0f, 0.0f, 1.0f}) {
maxU = std::max(maxU, vertex.uv_x);
}
outward = outward && glm::dot(vertex.position, vertex.normal) > 0.0f;
}
check(close(maxU, size.x), "box uvs must be in meters so textures tile at the same size");
check(outward, "box normals must point away from the center");
bool counterClockwise = true;
for (std::size_t i = 0; i < box.indices.size(); i += 3) {
const auto& a = box.vertices[box.indices[i]];
const auto& b = box.vertices[box.indices[i + 1]];
const auto& c = box.vertices[box.indices[i + 2]];
const glm::vec3 faceNormal = glm::cross(b.position - a.position, c.position - a.position);
counterClockwise = counterClockwise && glm::dot(faceNormal, a.normal) > 0.0f;
}
check(counterClockwise, "box triangles must be counter clockwise seen from outside");
}
void testFrozenRotationCapsule()
{
Scene& scene = SceneManager::GetInstance().CreateScene("frozen-capsule");
@@ -1047,6 +1128,9 @@ int main()
testTriggerZone();
testSceneCurrentCamera();
testFrozenRotationCapsule();
testPrimitiveBoxMesh();
testColliderCenterOffset();
testCapsuleColliderDebugLines();
std::cout << "destrum tests passed\n";
return EXIT_SUCCESS;
}