Debugging Profiling
ΠΡΡΠ΅ΠΊΡΠΈΠ²Π½Π°Ρ ΠΎΡΠ»Π°Π΄ΠΊΠ° ΠΈ ΠΏΡΠΎΡΠΈΠ»ΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅ β ΠΊΠ»ΡΡΠ΅Π²ΡΠ΅ Π½Π°Π²ΡΠΊΠΈ Π΄Π»Ρ ΠΎΠΏΡΠΈΠΌΠΈΠ·Π°ΡΠΈΠΈ ΠΏΡΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡΠ΅Π»ΡΠ½ΠΎΡΡΠΈ ΠΈΠ³Ρ Π½Π° Wudgine. Π ΡΡΠΎΠΌ ΡΠ°Π·Π΄Π΅Π»Π΅ ΡΠ°ΡΡΠΌΠ°ΡΡΠΈΠ²Π°ΡΡΡΡ ΠΈΠ½ΡΡΡΡΠΌΠ΅Π½ΡΡ ΠΈ ΠΌΠ΅ΡΠΎΠ΄ΠΈΠΊΠΈ Π΄Π»Ρ Π²ΡΡΠ²Π»Π΅Π½ΠΈΡ ΠΈ ΡΡΡΡΠ°Π½Π΅Π½ΠΈΡ ΠΏΡΠΎΠ±Π»Π΅ΠΌ.
ΠΠ²Π΅Π΄Π΅Π½ΠΈΠ΅
ΠΡΠ»Π°Π΄ΠΊΠ° ΠΈ ΠΏΡΠΎΡΠΈΠ»ΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅ ΡΠ²Π»ΡΡΡΡΡ Π½Π΅ΠΎΡΡΠ΅ΠΌΠ»Π΅ΠΌΠΎΠΉ ΡΠ°ΡΡΡΡ ΡΠ°Π·ΡΠ°Π±ΠΎΡΠΊΠΈ ΠΈΠ³Ρ. Wudgine ΠΏΡΠ΅Π΄ΠΎΡΡΠ°Π²Π»ΡΠ΅Ρ Π½Π°Π±ΠΎΡ ΠΈΠ½ΡΡΡΡΠΌΠ΅Π½ΡΠΎΠ², ΠΊΠΎΡΠΎΡΡΠ΅ ΠΏΠΎΠΌΠΎΠ³Π°ΡΡ Π²ΡΡΠ²Π»ΡΡΡ ΠΈ ΡΡΡΡΠ°Π½ΡΡΡ ΠΏΡΠΎΠ±Π»Π΅ΠΌΡ ΠΏΡΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡΠ΅Π»ΡΠ½ΠΎΡΡΠΈ, ΡΡΠ΅ΡΠΊΠΈ ΠΏΠ°ΠΌΡΡΠΈ ΠΈ Π΄ΡΡΠ³ΠΈΠ΅ ΠΎΡΠΈΠ±ΠΊΠΈ.
ΠΡΡΡΠΎΠ΅Π½Π½ΡΠ΅ ΠΈΠ½ΡΡΡΡΠΌΠ΅Π½ΡΡ ΠΎΡΠ»Π°Π΄ΠΊΠΈ
ΠΠΎΠ½ΡΠΎΠ»Ρ ΠΎΡΠ»Π°Π΄ΠΊΠΈ
Wudgine Π²ΠΊΠ»ΡΡΠ°Π΅Ρ Π²ΡΡΡΠΎΠ΅Π½Π½ΡΡ ΠΊΠΎΠ½ΡΠΎΠ»Ρ ΠΎΡΠ»Π°Π΄ΠΊΠΈ, ΠΊΠΎΡΠΎΡΠ°Ρ ΠΏΠΎΠ·Π²ΠΎΠ»ΡΠ΅Ρ ΠΏΡΠΎΡΠΌΠ°ΡΡΠΈΠ²Π°ΡΡ Π»ΠΎΠ³ΠΈ ΠΈ Π²ΡΠΏΠΎΠ»Π½ΡΡΡ ΠΊΠΎΠΌΠ°Π½Π΄Ρ Π²ΠΎ Π²ΡΠ΅ΠΌΡ ΡΠ°Π±ΠΎΡΡ ΠΈΠ³ΡΡ.
// ΠΠΊΠ»ΡΡΠ΅Π½ΠΈΠ΅ ΠΊΠΎΠ½ΡΠΎΠ»ΠΈ ΠΎΡΠ»Π°Π΄ΠΊΠΈ
Wudgine::Debug::Console::Initialize();
// Π Π΅Π³ΠΈΡΡΡΠ°ΡΠΈΡ ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»ΡΡΠΊΠΎΠΉ ΠΊΠΎΠΌΠ°Π½Π΄Ρ
Wudgine::Debug::Console::RegisterCommand("spawn_enemy", [](const std::vector<std::string>& args) {
if (args.size() < 2) {
return "ΠΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΠ΅: spawn_enemy <ΡΠΈΠΏ> <ΠΊΠΎΠ»ΠΈΡΠ΅ΡΡΠ²ΠΎ>";
}
std::string enemyType = args[0];
int count = std::stoi(args[1]);
for (int i = 0; i < count; i++) {
// Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ Π²ΡΠ°Π³Π° ΡΠΊΠ°Π·Π°Π½Π½ΠΎΠ³ΠΎ ΡΠΈΠΏΠ°
SpawnEnemy(enemyType);
}
return "Π‘ΠΎΠ·Π΄Π°Π½ΠΎ " + std::to_string(count) + " Π²ΡΠ°Π³ΠΎΠ² ΡΠΈΠΏΠ° " + enemyType;
});
// ΠΡΠ²ΠΎΠ΄ ΡΠΎΠΎΠ±ΡΠ΅Π½ΠΈΡ Π² ΠΊΠΎΠ½ΡΠΎΠ»Ρ
Wudgine::Debug::Console::Log("ΠΠ½ΠΈΡΠΈΠ°Π»ΠΈΠ·Π°ΡΠΈΡ ΠΈΠ³ΡΡ Π·Π°Π²Π΅ΡΡΠ΅Π½Π°");
Wudgine::Debug::Console::LogWarning("Π Π΅ΡΡΡΡ Π½Π΅ Π½Π°ΠΉΠ΄Π΅Π½: textures/missing.png");
Wudgine::Debug::Console::LogError("ΠΡΠΈΡΠΈΡΠ΅ΡΠΊΠ°Ρ ΠΎΡΠΈΠ±ΠΊΠ° ΠΏΡΠΈ Π·Π°Π³ΡΡΠ·ΠΊΠ΅ ΡΡΠΎΠ²Π½Ρ");
ΠΠΈΠ·ΡΠ°Π»ΠΈΠ·Π°ΡΠΈΡ ΠΎΡΠ»Π°Π΄ΠΎΡΠ½ΠΎΠΉ ΠΈΠ½ΡΠΎΡΠΌΠ°ΡΠΈΠΈ
// Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ ΠΎΡΠ»Π°Π΄ΠΎΡΠ½ΠΎΠ³ΠΎ ΡΠ΅Π½Π΄Π΅ΡΠ΅ΡΠ°
Wudgine::Debug::DebugRenderer debugRenderer;
// ΠΡΡΠΈΡΠΎΠ²ΠΊΠ° ΠΎΡΠ»Π°Π΄ΠΎΡΠ½ΡΡ
ΠΏΡΠΈΠΌΠΈΡΠΈΠ²ΠΎΠ²
void Update(float deltaTime) {
// ΠΡΡΠΈΡΠΎΠ²ΠΊΠ° ΠΊΠΎΠ»Π»Π°ΠΉΠ΄Π΅ΡΠΎΠ²
for (auto entity : physicsSystem.GetEntities()) {
auto& collider = world.GetComponent<Wudgine::Physics::ColliderComponent>(entity);
auto& transform = world.GetComponent<Wudgine::ECS::TransformComponent>(entity);
// ΠΡΡΠΈΡΠΎΠ²ΠΊΠ° ΠΊΠΎΠ»Π»Π°ΠΉΠ΄Π΅ΡΠ° Π² Π·Π°Π²ΠΈΡΠΈΠΌΠΎΡΡΠΈ ΠΎΡ Π΅Π³ΠΎ ΡΠΈΠΏΠ°
switch (collider.type) {
case Wudgine::Physics::ColliderType::Box:
debugRenderer.DrawBox(transform.position, collider.size, transform.rotation,
Wudgine::Math::Color(0, 1, 0, 0.5f));
break;
case Wudgine::Physics::ColliderType::Sphere:
debugRenderer.DrawSphere(transform.position, collider.radius,
Wudgine::Math::Color(0, 1, 0, 0.5f));
break;
}
}
// ΠΡΡΠΈΡΠΎΠ²ΠΊΠ° ΠΏΡΡΠ΅ΠΉ Π½Π°Π²ΠΈΠ³Π°ΡΠΈΠΈ
for (auto& path : navigationSystem.GetActivePaths()) {
debugRenderer.DrawPath(path.points, Wudgine::Math::Color(0, 0, 1, 1.0f));
}
// ΠΡΡΠΈΡΠΎΠ²ΠΊΠ° Π½Π°ΠΏΡΠ°Π²Π»Π΅Π½ΠΈΠΉ ΠΈ Π²Π΅ΠΊΡΠΎΡΠΎΠ²
debugRenderer.DrawArrow(player.position, player.position + player.velocity * 2.0f,
Wudgine::Math::Color(1, 0, 0, 1.0f));
}
ΠΡΠΎΡΠΈΠ»ΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅ ΠΏΡΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡΠ΅Π»ΡΠ½ΠΎΡΡΠΈ
ΠΡΡΡΠΎΠ΅Π½Π½ΡΠΉ ΠΏΡΠΎΡΠΈΠ»ΠΈΡΠΎΠ²ΡΠΈΠΊ
Wudgine Π²ΠΊΠ»ΡΡΠ°Π΅Ρ Π²ΡΡΡΠΎΠ΅Π½Π½ΡΠΉ ΠΏΡΠΎΡΠΈΠ»ΠΈΡΠΎΠ²ΡΠΈΠΊ Π΄Π»Ρ ΠΈΠ·ΠΌΠ΅ΡΠ΅Π½ΠΈΡ ΠΏΡΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡΠ΅Π»ΡΠ½ΠΎΡΡΠΈ ΡΠ°Π·Π»ΠΈΡΠ½ΡΡ ΡΠ°ΡΡΠ΅ΠΉ ΠΈΠ³ΡΡ.
// ΠΠ½ΠΈΡΠΈΠ°Π»ΠΈΠ·Π°ΡΠΈΡ ΠΏΡΠΎΡΠΈΠ»ΠΈΡΠΎΠ²ΡΠΈΠΊΠ°
Wudgine::Profiling::Profiler::Initialize();
// ΠΡΠΎΡΠΈΠ»ΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅ ΡΡΠ½ΠΊΡΠΈΠΈ ΠΈΠ»ΠΈ Π±Π»ΠΎΠΊΠ° ΠΊΠΎΠ΄Π°
void Update(float deltaTime) {
WUDGINE_PROFILE_FUNCTION(); // ΠΠ²ΡΠΎΠΌΠ°ΡΠΈΡΠ΅ΡΠΊΠΈ ΠΏΡΠΎΡΠΈΠ»ΠΈΡΡΠ΅Ρ Π²ΡΡ ΡΡΠ½ΠΊΡΠΈΡ
{
WUDGINE_PROFILE_SCOPE("Physics Update"); // ΠΡΠΎΡΠΈΠ»ΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅ ΠΊΠΎΠ½ΠΊΡΠ΅ΡΠ½ΠΎΠ³ΠΎ Π±Π»ΠΎΠΊΠ° ΠΊΠΎΠ΄Π°
physicsSystem.Update(deltaTime);
}
{
WUDGINE_PROFILE_SCOPE("AI Update");
aiSystem.Update(deltaTime);
}
{
WUDGINE_PROFILE_SCOPE("Rendering");
renderSystem.Render();
}
}
// Π‘ΠΎΡ
ΡΠ°Π½Π΅Π½ΠΈΠ΅ ΡΠ΅Π·ΡΠ»ΡΡΠ°ΡΠΎΠ² ΠΏΡΠΎΡΠΈΠ»ΠΈΡΠΎΠ²Π°Π½ΠΈΡ
void OnGameExit() {
Wudgine::Profiling::Profiler::SaveResults("profile_results.json");
}
ΠΠ½ΡΠ΅Π³ΡΠ°ΡΠΈΡ Ρ Π²Π½Π΅ΡΠ½ΠΈΠΌΠΈ ΠΏΡΠΎΡΠΈΠ»ΠΈΡΠΎΠ²ΡΠΈΠΊΠ°ΠΌΠΈ
// ΠΠ½ΡΠ΅Π³ΡΠ°ΡΠΈΡ Ρ Tracy Profiler
#include "TracyWudgine.h"
void GameLoop() {
while (running) {
ZoneScoped; // Tracy: ΠΏΡΠΎΡΠΈΠ»ΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅ Π²ΡΠ΅Π³ΠΎ ΠΊΠ°Π΄ΡΠ°
{
ZoneScopedN("Input Processing"); // Tracy: ΠΈΠΌΠ΅Π½ΠΎΠ²Π°Π½Π½Π°Ρ Π·ΠΎΠ½Π° ΠΏΡΠΎΡΠΈΠ»ΠΈΡΠΎΠ²Π°Π½ΠΈΡ
ProcessInput();
}
{
ZoneScopedN("Update");
Update(deltaTime);
}
{
ZoneScopedN("Render");
Render();
}
FrameMark; // Tracy: ΠΎΡΠΌΠ΅ΡΠΊΠ° ΠΊΠΎΠ½ΡΠ° ΠΊΠ°Π΄ΡΠ°
}
}
ΠΡΠ»Π°Π΄ΠΊΠ° ΠΏΠ°ΠΌΡΡΠΈ
ΠΡΡΠ»Π΅ΠΆΠΈΠ²Π°Π½ΠΈΠ΅ ΡΡΠ΅ΡΠ΅ΠΊ ΠΏΠ°ΠΌΡΡΠΈ
// ΠΠΊΠ»ΡΡΠ΅Π½ΠΈΠ΅ ΠΎΡΡΠ»Π΅ΠΆΠΈΠ²Π°Π½ΠΈΡ ΠΏΠ°ΠΌΡΡΠΈ
Wudgine::Debug::MemoryTracker::Initialize();
// ΠΠΎΠ»ΡΡΠ΅Π½ΠΈΠ΅ ΡΡΠ°ΡΠΈΡΡΠΈΠΊΠΈ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΡ ΠΏΠ°ΠΌΡΡΠΈ
void DisplayMemoryStats() {
auto stats = Wudgine::Debug::MemoryTracker::GetStats();
std::cout << "Π‘ΡΠ°ΡΠΈΡΡΠΈΠΊΠ° ΠΏΠ°ΠΌΡΡΠΈ:" << std::endl;
std::cout << "- ΠΡΠ΅Π³ΠΎ Π²ΡΠ΄Π΅Π»Π΅Π½ΠΎ: " << stats.totalAllocated / (1024 * 1024) << " ΠΠ" << std::endl;
std::cout << "- ΠΡΠ΅Π³ΠΎ ΠΎΡΠ²ΠΎΠ±ΠΎΠΆΠ΄Π΅Π½ΠΎ: " << stats.totalFreed / (1024 * 1024) << " ΠΠ" << std::endl;
std::cout << "- Π’Π΅ΠΊΡΡΠ΅Π΅ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΠ΅: " << stats.currentUsage / (1024 * 1024) << " ΠΠ" << std::endl;
std::cout << "- ΠΠΈΠΊΠΎΠ²ΠΎΠ΅ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΠ΅: " << stats.peakUsage / (1024 * 1024) << " ΠΠ" << std::endl;
std::cout << "- ΠΠΎΠ»ΠΈΡΠ΅ΡΡΠ²ΠΎ Π°ΠΊΡΠΈΠ²Π½ΡΡ
Π²ΡΠ΄Π΅Π»Π΅Π½ΠΈΠΉ: " << stats.activeAllocations << std::endl;
}
Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ ΡΠ½ΠΈΠΌΠΊΠΎΠ² ΠΏΠ°ΠΌΡΡΠΈ Π΄Π»Ρ ΡΡΠ°Π²Π½Π΅Π½ΠΈΡ
// Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ ΡΠ½ΠΈΠΌΠΊΠ° ΠΏΠ°ΠΌΡΡΠΈ Π΄Π»Ρ ΡΡΠ°Π²Π½Π΅Π½ΠΈΡ
void CheckForLeaks() {
// Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ ΡΠ½ΠΈΠΌΠΊΠ° ΡΠ΅ΠΊΡΡΠ΅Π³ΠΎ ΡΠΎΡΡΠΎΡΠ½ΠΈΡ ΠΏΠ°ΠΌΡΡΠΈ
auto snapshot1 = Wudgine::Debug::MemoryTracker::CreateSnapshot();
// ΠΡΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅ ΠΎΠΏΠ΅ΡΠ°ΡΠΈΠΉ, ΠΊΠΎΡΠΎΡΡΠ΅ ΠΌΠΎΠ³ΡΡ Π²ΡΠ·ΡΠ²Π°ΡΡ ΡΡΠ΅ΡΠΊΠΈ
LoadLevel("test_level");
UnloadLevel("test_level");
// Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ Π²ΡΠΎΡΠΎΠ³ΠΎ ΡΠ½ΠΈΠΌΠΊΠ°
auto snapshot2 = Wudgine::Debug::MemoryTracker::CreateSnapshot();
// Π‘ΡΠ°Π²Π½Π΅Π½ΠΈΠ΅ ΡΠ½ΠΈΠΌΠΊΠΎΠ² Π΄Π»Ρ Π²ΡΡΠ²Π»Π΅Π½ΠΈΡ ΡΡΠ΅ΡΠ΅ΠΊ
auto diff = Wudgine::Debug::MemoryTracker::CompareSnapshots(snapshot1, snapshot2);
if (diff.newAllocations.empty()) {
std::cout << "Π£ΡΠ΅ΡΠ΅ΠΊ ΠΏΠ°ΠΌΡΡΠΈ Π½Π΅ ΠΎΠ±Π½Π°ΡΡΠΆΠ΅Π½ΠΎ!" << std::endl;
} else {
std::cout << "ΠΠ±Π½Π°ΡΡΠΆΠ΅Π½Ρ ΠΏΠΎΡΠ΅Π½ΡΠΈΠ°Π»ΡΠ½ΡΠ΅ ΡΡΠ΅ΡΠΊΠΈ ΠΏΠ°ΠΌΡΡΠΈ:" << std::endl;
for (const auto& alloc : diff.newAllocations) {
std::cout << "- " << alloc.size << " Π±Π°ΠΉΡ Π² " << alloc.file << ":" << alloc.line << std::endl;
}
}
}
ΠΡΠ»Π°Π΄ΠΊΠ° ΡΠ΅Π½Π΄Π΅ΡΠΈΠ½Π³Π°
ΠΠΈΠ·ΡΠ°Π»ΠΈΠ·Π°ΡΠΈΡ Π±ΡΡΠ΅ΡΠΎΠ² ΡΠ΅Π½Π΄Π΅ΡΠΈΠ½Π³Π°
// ΠΡΠΎΠ±ΡΠ°ΠΆΠ΅Π½ΠΈΠ΅ ΡΠ°Π·Π»ΠΈΡΠ½ΡΡ
Π±ΡΡΠ΅ΡΠΎΠ² ΡΠ΅Π½Π΄Π΅ΡΠΈΠ½Π³Π°
void RenderDebugBuffers() {
if (Wudgine::Debug::ImGui::Begin("Debug Buffers")) {
// ΠΠΎΠ»ΡΡΠ΅Π½ΠΈΠ΅ ΡΠ΅ΠΊΡΡΡΡ Π±ΡΡΠ΅ΡΠΎΠ²
auto colorBuffer = renderer.GetColorBufferTexture();
auto depthBuffer = renderer.GetDepthBufferTexture();
auto normalBuffer = renderer.GetGBufferTexture(Wudgine::Rendering::GBufferType::Normal);
auto velocityBuffer = renderer.GetGBufferTexture(Wudgine::Rendering::GBufferType::Velocity);
// ΠΡΠΎΠ±ΡΠ°ΠΆΠ΅Π½ΠΈΠ΅ Π±ΡΡΠ΅ΡΠΎΠ²
Wudgine::Debug::ImGui::Text("Color Buffer");
Wudgine::Debug::ImGui::Image(colorBuffer, ImVec2(200, 200));
Wudgine::Debug::ImGui::Text("Depth Buffer");
Wudgine::Debug::ImGui::Image(depthBuffer, ImVec2(200, 200));
Wudgine::Debug::ImGui::Text("Normal Buffer");
Wudgine::Debug::ImGui::Image(normalBuffer, ImVec2(200, 200));
Wudgine::Debug::ImGui::Text("Velocity Buffer");
Wudgine::Debug::ImGui::Image(velocityBuffer, ImVec2(200, 200));
Wudgine::Debug::ImGui::End();
}
}
ΠΡΠ»Π°Π΄ΠΊΠ° ΡΠ΅ΠΉΠ΄Π΅ΡΠΎΠ²
// ΠΠΊΠ»ΡΡΠ΅Π½ΠΈΠ΅ ΠΎΡΠ»Π°Π΄ΠΊΠΈ ΡΠ΅ΠΉΠ΄Π΅ΡΠΎΠ²
Wudgine::Rendering::ShaderDebugger::Initialize();
// ΠΡΠ»Π°Π΄ΠΊΠ° ΠΊΠΎΠ½ΠΊΡΠ΅ΡΠ½ΠΎΠ³ΠΎ ΡΠ΅ΠΉΠ΄Π΅ΡΠ°
void DebugShader(const std::string& shaderName) {
auto debugInfo = Wudgine::Rendering::ShaderDebugger::DebugShader(shaderName);
std::cout << "ΠΡΠ»Π°Π΄ΠΊΠ° ΡΠ΅ΠΉΠ΄Π΅ΡΠ°: " << shaderName << std::endl;
std::cout << "- ΠΡΠ΅ΠΌΡ ΠΊΠΎΠΌΠΏΠΈΠ»ΡΡΠΈΠΈ: " << debugInfo.compilationTimeMs << " ΠΌΡ" << std::endl;
std::cout << "- ΠΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΠ΅ ΡΠ΅Π³ΠΈΡΡΡΠΎΠ²: " << debugInfo.registerUsage << "%" << std::endl;
if (!debugInfo.warnings.empty()) {
std::cout << "ΠΡΠ΅Π΄ΡΠΏΡΠ΅ΠΆΠ΄Π΅Π½ΠΈΡ:" << std::endl;
for (const auto& warning : debugInfo.warnings) {
std::cout << "- " << warning << std::endl;
}
}
}
ΠΡΠ»Π°Π΄ΠΊΠ° ΡΠΈΠ·ΠΈΠΊΠΈ
ΠΠΈΠ·ΡΠ°Π»ΠΈΠ·Π°ΡΠΈΡ ΡΠΈΠ·ΠΈΡΠ΅ΡΠΊΠΈΡ ΠΎΠ±ΡΠ΅ΠΊΡΠΎΠ²
// ΠΠΊΠ»ΡΡΠ΅Π½ΠΈΠ΅ Π²ΠΈΠ·ΡΠ°Π»ΠΈΠ·Π°ΡΠΈΠΈ ΡΠΈΠ·ΠΈΠΊΠΈ
Wudgine::Physics::Debug::EnableVisualization();
// ΠΠ°ΡΡΡΠΎΠΉΠΊΠ° ΠΏΠ°ΡΠ°ΠΌΠ΅ΡΡΠΎΠ² Π²ΠΈΠ·ΡΠ°Π»ΠΈΠ·Π°ΡΠΈΠΈ
Wudgine::Physics::Debug::SetVisualizationOptions({
.showColliders = true,
.showContacts = true,
.showJoints = true,
.showAABBs = false,
.showVelocities = true,
.colliderColor = Wudgine::Math::Color(0, 1, 0, 0.5f),
.contactColor = Wudgine::Math::Color(1, 0, 0, 1.0f),
.jointColor = Wudgine::Math::Color(0, 0, 1, 1.0f),
.velocityColor = Wudgine::Math::Color(1, 1, 0, 1.0f)
});
ΠΡΠ»Π°Π΄ΠΊΠ° ΡΡΠΎΠ»ΠΊΠ½ΠΎΠ²Π΅Π½ΠΈΠΉ
// Π Π΅Π³ΠΈΡΡΡΠ°ΡΠΈΡ ΠΎΠ±ΡΠ°ΡΠ½ΠΎΠ³ΠΎ Π²ΡΠ·ΠΎΠ²Π° Π΄Π»Ρ ΠΎΡΠ»Π°Π΄ΠΊΠΈ ΡΡΠΎΠ»ΠΊΠ½ΠΎΠ²Π΅Π½ΠΈΠΉ
Wudgine::Physics::Debug::RegisterCollisionCallback([](const Wudgine::Physics::CollisionInfo& info) {
std::cout << "Π‘ΡΠΎΠ»ΠΊΠ½ΠΎΠ²Π΅Π½ΠΈΠ΅ ΠΌΠ΅ΠΆΠ΄Ρ ΠΎΠ±ΡΠ΅ΠΊΡΠ°ΠΌΠΈ " << info.entityA << " ΠΈ " << info.entityB << std::endl;
std::cout << "- Π’ΠΎΡΠΊΠ° ΠΊΠΎΠ½ΡΠ°ΠΊΡΠ°: " << info.contactPoint.x << ", "
<< info.contactPoint.y << ", " << info.contactPoint.z << std::endl;
std::cout << "- ΠΠΎΡΠΌΠ°Π»Ρ: " << info.normal.x << ", "
<< info.normal.y << ", " << info.normal.z << std::endl;
std::cout << "- ΠΠ»ΡΠ±ΠΈΠ½Π° ΠΏΡΠΎΠ½ΠΈΠΊΠ½ΠΎΠ²Π΅Π½ΠΈΡ: " << info.penetrationDepth << std::endl;
// ΠΠΎΠΆΠ½ΠΎ ΡΠ°ΠΊΠΆΠ΅ Π²ΠΈΠ·ΡΠ°Π»ΠΈΠ·ΠΈΡΠΎΠ²Π°ΡΡ ΡΠΎΡΠΊΡ ΠΊΠΎΠ½ΡΠ°ΠΊΡΠ°
Wudgine::Debug::DebugRenderer::DrawSphere(info.contactPoint, 0.1f,
Wudgine::Math::Color(1, 0, 0, 1.0f), 2.0f);
});
ΠΡΠ»Π°Π΄ΠΊΠ° ΠΈΡΠΊΡΡΡΡΠ²Π΅Π½Π½ΠΎΠ³ΠΎ ΠΈΠ½ΡΠ΅Π»Π»Π΅ΠΊΡΠ°
ΠΠΈΠ·ΡΠ°Π»ΠΈΠ·Π°ΡΠΈΡ ΠΏΠΎΠ²Π΅Π΄Π΅Π½ΠΈΡ ΠΠ
// ΠΠΈΠ·ΡΠ°Π»ΠΈΠ·Π°ΡΠΈΡ Π·ΠΎΠ½ Π²ΠΎΡΠΏΡΠΈΡΡΠΈΡ ΠΠ
void DebugAIPerception() {
for (auto entity : aiSystem.GetEntities()) {
auto& perception = world.GetComponent<Wudgine::AI::PerceptionComponent>(entity);
auto& transform = world.GetComponent<Wudgine::ECS::TransformComponent>(entity);
// ΠΠΈΠ·ΡΠ°Π»ΠΈΠ·Π°ΡΠΈΡ Π·ΠΎΠ½Ρ Π²ΠΈΠ΄ΠΈΠΌΠΎΡΡΠΈ
if (perception.hasVision) {
debugRenderer.DrawCone(transform.position, transform.forward,
perception.visionRange, perception.visionAngle,
Wudgine::Math::Color(1, 1, 0, 0.3f));
}
// ΠΠΈΠ·ΡΠ°Π»ΠΈΠ·Π°ΡΠΈΡ Π·ΠΎΠ½Ρ ΡΠ»ΡΡΠΈΠΌΠΎΡΡΠΈ
if (perception.hasHearing) {
debugRenderer.DrawSphere(transform.position, perception.hearingRange,
Wudgine::Math::Color(0, 1, 1, 0.3f));
}
// ΠΠΈΠ·ΡΠ°Π»ΠΈΠ·Π°ΡΠΈΡ ΠΎΠ±Π½Π°ΡΡΠΆΠ΅Π½Π½ΡΡ
ΡΠ΅Π»Π΅ΠΉ
for (const auto& target : perception.detectedTargets) {
debugRenderer.DrawLine(transform.position, target.position,
Wudgine::Math::Color(1, 0, 0, 1.0f));
}
}
}
ΠΡΠ»Π°Π΄ΠΊΠ° Π΄Π΅ΡΠ΅Π²ΡΠ΅Π² ΠΏΠΎΠ²Π΅Π΄Π΅Π½ΠΈΡ
// ΠΠΊΠ»ΡΡΠ΅Π½ΠΈΠ΅ ΠΎΡΠ»Π°Π΄ΠΊΠΈ Π΄Π΅ΡΠ΅Π²ΡΠ΅Π² ΠΏΠΎΠ²Π΅Π΄Π΅Π½ΠΈΡ
Wudgine::AI::BehaviorTreeDebugger::Initialize();
// Π Π΅Π³ΠΈΡΡΡΠ°ΡΠΈΡ Π΄Π΅ΡΠ΅Π²Π° ΠΏΠΎΠ²Π΅Π΄Π΅Π½ΠΈΡ Π΄Π»Ρ ΠΎΡΠ»Π°Π΄ΠΊΠΈ
void RegisterBehaviorTreeForDebugging(Wudgine::AI::BehaviorTree* tree, const std::string& name) {
Wudgine::AI::BehaviorTreeDebugger::RegisterTree(tree, name);
}
// ΠΡΠΎΠ±ΡΠ°ΠΆΠ΅Π½ΠΈΠ΅ ΡΠΎΡΡΠΎΡΠ½ΠΈΡ Π΄Π΅ΡΠ΅Π²Π° ΠΏΠΎΠ²Π΅Π΄Π΅Π½ΠΈΡ
void RenderBehaviorTreeDebugger() {
if (Wudgine::Debug::ImGui::Begin("Behavior Tree Debugger")) {
// ΠΡΠ±ΠΎΡ Π΄Π΅ΡΠ΅Π²Π° ΠΏΠΎΠ²Π΅Π΄Π΅Π½ΠΈΡ Π΄Π»Ρ ΠΎΡΠΎΠ±ΡΠ°ΠΆΠ΅Π½ΠΈΡ
static int selectedTree = 0;
auto treeNames = Wudgine::AI::BehaviorTreeDebugger::GetRegisteredTreeNames();
if (Wudgine::Debug::ImGui::Combo("Tree", &selectedTree, treeNames)) {
Wudgine::AI::BehaviorTreeDebugger::SetActiveTree(treeNames[selectedTree]);
}
// ΠΡΠΎΠ±ΡΠ°ΠΆΠ΅Π½ΠΈΠ΅ ΡΡΡΡΠΊΡΡΡΡ Π΄Π΅ΡΠ΅Π²Π°
Wudgine::AI::BehaviorTreeDebugger::RenderActiveTree();
Wudgine::Debug::ImGui::End();
}
}
ΠΡΠ»Π°Π΄ΠΊΠ° ΡΠ΅ΡΠΈ
ΠΠΎΠ½ΠΈΡΠΎΡΠΈΠ½Π³ ΡΠ΅ΡΠ΅Π²ΠΎΠ³ΠΎ ΡΡΠ°ΡΠΈΠΊΠ°
// ΠΠΊΠ»ΡΡΠ΅Π½ΠΈΠ΅ ΠΌΠΎΠ½ΠΈΡΠΎΡΠΈΠ½Π³Π° ΡΠ΅ΡΠ΅Π²ΠΎΠ³ΠΎ ΡΡΠ°ΡΠΈΠΊΠ°
Wudgine::Networking::Debug::EnableTrafficMonitoring();
// ΠΡΠΎΠ±ΡΠ°ΠΆΠ΅Π½ΠΈΠ΅ ΡΡΠ°ΡΠΈΡΡΠΈΠΊΠΈ ΡΠ΅ΡΠ΅Π²ΠΎΠ³ΠΎ ΡΡΠ°ΡΠΈΠΊΠ°
void DisplayNetworkStats() {
auto stats = Wudgine::Networking::Debug::GetTrafficStats();
std::cout << "Π‘ΡΠ°ΡΠΈΡΡΠΈΠΊΠ° ΡΠ΅ΡΠΈ:" << std::endl;
std::cout << "- ΠΡΠΏΡΠ°Π²Π»Π΅Π½ΠΎ ΠΏΠ°ΠΊΠ΅ΡΠΎΠ²: " << stats.packetsSent << std::endl;
std::cout << "- ΠΠΎΠ»ΡΡΠ΅Π½ΠΎ ΠΏΠ°ΠΊΠ΅ΡΠΎΠ²: " << stats.packetsReceived << std::endl;
std::cout << "- ΠΡΠΏΡΠ°Π²Π»Π΅Π½ΠΎ Π±Π°ΠΉΡ: " << stats.bytesSent / 1024.0f << " ΠΠ" << std::endl;
std::cout << "- ΠΠΎΠ»ΡΡΠ΅Π½ΠΎ Π±Π°ΠΉΡ: " << stats.bytesReceived / 1024.0f << " ΠΠ" << std::endl;
std::cout << "- Π‘ΡΠ΅Π΄Π½ΡΡ Π·Π°Π΄Π΅ΡΠΆΠΊΠ°: " << stats.averagePing << " ΠΌΡ" << std::endl;
std::cout << "- ΠΠΎΡΠ΅ΡΡΠ½ΠΎ ΠΏΠ°ΠΊΠ΅ΡΠΎΠ²: " << stats.packetsLost << " ("
<< (stats.packetsSent > 0 ? (stats.packetsLost * 100.0f / stats.packetsSent) : 0.0f)
<< "%)" << std::endl;
}
// ΠΠΎΠ³ΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅ ΡΠ΅ΡΠ΅Π²ΡΡ
ΡΠΎΠΎΠ±ΡΠ΅Π½ΠΈΠΉ
Wudgine::Networking::Debug::SetMessageLoggingLevel(Wudgine::Networking::Debug::LogLevel::Verbose);
Π‘ΠΈΠΌΡΠ»ΡΡΠΈΡ ΡΠ΅ΡΠ΅Π²ΡΡ ΡΡΠ»ΠΎΠ²ΠΈΠΉ
// ΠΠ°ΡΡΡΠΎΠΉΠΊΠ° ΡΠΈΠΌΡΠ»ΡΡΠΈΠΈ ΡΠ΅ΡΠ΅Π²ΡΡ
ΡΡΠ»ΠΎΠ²ΠΈΠΉ
void SimulateNetworkConditions() {
Wudgine::Networking::Debug::NetworkConditions conditions;
// Π‘ΠΈΠΌΡΠ»ΡΡΠΈΡ ΠΏΠ»ΠΎΡ
ΠΎΠ³ΠΎ ΡΠΎΠ΅Π΄ΠΈΠ½Π΅Π½ΠΈΡ
conditions.packetLossPercentage = 5.0f; // 5% ΠΏΠΎΡΠ΅ΡΠΈ ΠΏΠ°ΠΊΠ΅ΡΠΎΠ²
conditions.minimumLatencyMs = 50; // ΠΠΈΠ½ΠΈΠΌΠ°Π»ΡΠ½Π°Ρ Π·Π°Π΄Π΅ΡΠΆΠΊΠ° 50 ΠΌΡ
conditions.additionalRandomLatencyMs = 100; // Π‘Π»ΡΡΠ°ΠΉΠ½Π°Ρ Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡΠ΅Π»ΡΠ½Π°Ρ Π·Π°Π΄Π΅ΡΠΆΠΊΠ° Π΄ΠΎ 100 ΠΌΡ
conditions.jitterMs = 20; // ΠΠΆΠΈΡΡΠ΅Ρ 20 ΠΌΡ
Wudgine::Networking::Debug::SetNetworkConditions(conditions);
// ΠΠ°ΠΏΡΡΠΊ ΡΠΈΠΌΡΠ»ΡΡΠΈΠΈ Π½Π° 60 ΡΠ΅ΠΊΡΠ½Π΄
Wudgine::Networking::Debug::EnableNetworkSimulation(true, 60.0f);
}
ΠΠ²ΡΠΎΠΌΠ°ΡΠΈΠ·ΠΈΡΠΎΠ²Π°Π½Π½ΠΎΠ΅ ΡΠ΅ΡΡΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅
ΠΠΎΠ΄ΡΠ»ΡΠ½ΠΎΠ΅ ΡΠ΅ΡΡΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅
// ΠΡΠΈΠΌΠ΅Ρ ΠΌΠΎΠ΄ΡΠ»ΡΠ½ΠΎΠ³ΠΎ ΡΠ΅ΡΡΠ° Ρ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΠ΅ΠΌ Π²ΡΡΡΠΎΠ΅Π½Π½ΠΎΠ³ΠΎ ΡΡΠ΅ΠΉΠΌΠ²ΠΎΡΠΊΠ° ΡΠ΅ΡΡΠΈΡΠΎΠ²Π°Π½ΠΈΡ
WUDGINE_TEST_CASE("Physics - Collision Detection") {
// ΠΠ°ΡΡΡΠΎΠΉΠΊΠ° ΡΠ΅ΡΡΠΎΠ²ΠΎΠ³ΠΎ ΠΎΠΊΡΡΠΆΠ΅Π½ΠΈΡ
Wudgine::Physics::World physicsWorld;
// Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ ΡΠ΅ΡΡΠΎΠ²ΡΡ
ΠΎΠ±ΡΠ΅ΠΊΡΠΎΠ²
auto boxA = physicsWorld.CreateBox({0, 0, 0}, {1, 1, 1}, 1.0f);
auto boxB = physicsWorld.CreateBox({0.5f, 0, 0}, {1, 1, 1}, 1.0f);
// ΠΡΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅ ΡΠ΅ΡΡΠ°
physicsWorld.Step(1.0f / 60.0f);
// ΠΡΠΎΠ²Π΅ΡΠΊΠ° ΡΠ΅Π·ΡΠ»ΡΡΠ°ΡΠΎΠ²
auto contacts = physicsWorld.GetContacts();
WUDGINE_CHECK(!contacts.empty());
WUDGINE_CHECK(contacts[0].entityA == boxA || contacts[0].entityA == boxB);
WUDGINE_CHECK(contacts[0].entityB == boxA || contacts[0].entityB == boxB);
WUDGINE_CHECK(contacts[0].entityA != contacts[0].entityB);
}
ΠΠ½ΡΠ΅Π³ΡΠ°ΡΠΈΠΎΠ½Π½ΠΎΠ΅ ΡΠ΅ΡΡΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅
// ΠΡΠΈΠΌΠ΅Ρ ΠΈΠ½ΡΠ΅Π³ΡΠ°ΡΠΈΠΎΠ½Π½ΠΎΠ³ΠΎ ΡΠ΅ΡΡΠ°
WUDGINE_TEST_CASE("Game Systems Integration") {
// ΠΠ½ΠΈΡΠΈΠ°Π»ΠΈΠ·Π°ΡΠΈΡ ΠΈΠ³ΡΠΎΠ²ΡΡ
ΡΠΈΡΡΠ΅ΠΌ
Wudgine::ECS::World world;
Wudgine::Physics::PhysicsSystem physicsSystem(&world);
Wudgine::AI::AISystem aiSystem(&world);
// ΠΠ°ΡΡΡΠΎΠΉΠΊΠ° ΡΠ΅ΡΡΠΎΠ²ΠΎΠ³ΠΎ ΡΡΠ΅Π½Π°ΡΠΈΡ
auto player = world.CreateEntity();
world.AddComponent<Wudgine::ECS::TransformComponent>(player, {{0, 0, 0}, {0, 0, 0, 1}, {1, 1, 1}});
world.AddComponent<Wudgine::Physics::RigidbodyComponent>(player, {1.0f, false});
auto enemy = world.CreateEntity();
world.AddComponent<Wudgine::ECS::TransformComponent>(enemy, {{5, 0, 0}, {0, 0, 0, 1}, {1, 1, 1}});
world.AddComponent<Wudgine::AI::BehaviorComponent>(enemy, {"chase_player"});
// ΠΡΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅ ΡΠ΅ΡΡΠΎΠ²ΠΎΠ³ΠΎ ΡΡΠ΅Π½Π°ΡΠΈΡ
for (int i = 0; i < 60; i++) {
physicsSystem.Update(1.0f / 60.0f);
aiSystem.Update(1.0f / 60.0f);
}
// ΠΡΠΎΠ²Π΅ΡΠΊΠ° ΡΠ΅Π·ΡΠ»ΡΡΠ°ΡΠΎΠ²
auto& enemyTransform = world.GetComponent<Wudgine::ECS::TransformComponent>(enemy);
auto& playerTransform = world.GetComponent<Wudgine::ECS::TransformComponent>(player);
// ΠΡΠΎΠ²Π΅ΡΡΠ΅ΠΌ, ΡΡΠΎ Π²ΡΠ°Π³ ΠΏΡΠΈΠ±Π»ΠΈΠ·ΠΈΠ»ΡΡ ΠΊ ΠΈΠ³ΡΠΎΠΊΡ
float distance = Wudgine::Math::Vector3::Distance(enemyTransform.position, playerTransform.position);
WUDGINE_CHECK(distance < 5.0f);
}
Π‘ΡΡΠ΅ΡΡ-ΡΠ΅ΡΡΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅
// ΠΡΠΈΠΌΠ΅Ρ ΡΡΡΠ΅ΡΡ-ΡΠ΅ΡΡΠ°
WUDGINE_TEST_CASE("Rendering System Stress Test") {
// ΠΠ½ΠΈΡΠΈΠ°Π»ΠΈΠ·Π°ΡΠΈΡ ΡΠΈΡΡΠ΅ΠΌΡ ΡΠ΅Π½Π΄Π΅ΡΠΈΠ½Π³Π°
Wudgine::Rendering::Renderer renderer;
// Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ Π±ΠΎΠ»ΡΡΠΎΠ³ΠΎ ΠΊΠΎΠ»ΠΈΡΠ΅ΡΡΠ²Π° ΠΎΠ±ΡΠ΅ΠΊΡΠΎΠ² Π΄Π»Ρ ΡΠ΅Π½Π΄Π΅ΡΠΈΠ½Π³Π°
const int objectCount = 10000;
std::vector<Wudgine::Rendering::MeshInstance> instances;
auto mesh = Wudgine::Resources::ResourceManager::LoadMesh("models/cube.obj");
auto material = Wudgine::Resources::ResourceManager::LoadMaterial("materials/standard.mat");
for (int i = 0; i < objectCount; i++) {
Wudgine::Rendering::MeshInstance instance;
instance.mesh = mesh;
instance.material = material;
instance.transform = Wudgine::Math::Matrix4x4::Translation(
Wudgine::Math::Vector3(
Wudgine::Math::Random::Range(-100.0f, 100.0f),
Wudgine::Math::Random::Range(-100.0f, 100.0f),
Wudgine::Math::Random::Range(-100.0f, 100.0f)
)
);
instances.push_back(instance);
}
// ΠΠ·ΠΌΠ΅ΡΠ΅Π½ΠΈΠ΅ ΠΏΡΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡΠ΅Π»ΡΠ½ΠΎΡΡΠΈ ΡΠ΅Π½Π΄Π΅ΡΠΈΠ½Π³Π°
Wudgine::Profiling::ScopedTimer timer("Rendering Stress Test");
for (int frame = 0; frame < 100; frame++) {
renderer.BeginFrame();
renderer.RenderInstances(instances);
renderer.EndFrame();
}
auto elapsedTime = timer.GetElapsedMilliseconds();
auto averageFrameTime = elapsedTime / 100.0f;
std::cout << "Π‘ΡΡΠ΅ΡΡ-ΡΠ΅ΡΡ ΡΠ΅Π½Π΄Π΅ΡΠΈΠ½Π³Π°:" << std::endl;
std::cout << "- ΠΠΎΠ»ΠΈΡΠ΅ΡΡΠ²ΠΎ ΠΎΠ±ΡΠ΅ΠΊΡΠΎΠ²: " << objectCount << std::endl;
std::cout << "- ΠΠ±ΡΠ΅Π΅ Π²ΡΠ΅ΠΌΡ: " << elapsedTime << " ΠΌΡ" << std::endl;
std::cout << "- Π‘ΡΠ΅Π΄Π½Π΅Π΅ Π²ΡΠ΅ΠΌΡ ΠΊΠ°Π΄ΡΠ°: " << averageFrameTime << " ΠΌΡ" << std::endl;
std::cout << "- Π‘ΡΠ΅Π΄Π½ΠΈΠΉ FPS: " << 1000.0f / averageFrameTime << std::endl;
// ΠΡΠΎΠ²Π΅ΡΠΊΠ° ΡΠ΅Π·ΡΠ»ΡΡΠ°ΡΠΎΠ²
WUDGINE_CHECK(averageFrameTime < 33.3f); // ΠΠΈΠ½ΠΈΠΌΡΠΌ 30 FPS
}
ΠΠ½Π°Π»ΠΈΠ· ΠΏΡΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡΠ΅Π»ΡΠ½ΠΎΡΡΠΈ CPU ΠΈ GPU
ΠΠ½Π°Π»ΠΈΠ· ΠΏΡΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡΠ΅Π»ΡΠ½ΠΎΡΡΠΈ CPU
// ΠΠΊΠ»ΡΡΠ΅Π½ΠΈΠ΅ Π°Π½Π°Π»ΠΈΠ·Π° ΠΏΡΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡΠ΅Π»ΡΠ½ΠΎΡΡΠΈ CPU
Wudgine::Profiling::CPUProfiler::Initialize();
// ΠΠ°ΠΏΡΡΠΊ Π°Π½Π°Π»ΠΈΠ·Π°
void AnalyzeCPUPerformance() {
Wudgine::Profiling::CPUProfiler::BeginSession("GameLoop");
// ΠΡΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅ ΠΈΠ³ΡΠΎΠ²ΠΎΠ³ΠΎ ΡΠΈΠΊΠ»Π°
for (int i = 0; i < 1000; i++) {
{
WUDGINE_CPU_PROFILE_SCOPE("Input");
ProcessInput();
}
{
WUDGINE_CPU_PROFILE_SCOPE("Update");
Update(1.0f / 60.0f);
}
{
WUDGINE_CPU_PROFILE_SCOPE("Render");
Render();
}
}
// ΠΠ°Π²Π΅ΡΡΠ΅Π½ΠΈΠ΅ Π°Π½Π°Π»ΠΈΠ·Π° ΠΈ ΡΠΎΡ
ΡΠ°Π½Π΅Π½ΠΈΠ΅ ΡΠ΅Π·ΡΠ»ΡΡΠ°ΡΠΎΠ²
Wudgine::Profiling::CPUProfiler::EndSession();
Wudgine::Profiling::CPUProfiler::SaveResults("cpu_profile.json");
}
ΠΠ½Π°Π»ΠΈΠ· ΠΏΡΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡΠ΅Π»ΡΠ½ΠΎΡΡΠΈ GPU
// ΠΠΊΠ»ΡΡΠ΅Π½ΠΈΠ΅ Π°Π½Π°Π»ΠΈΠ·Π° ΠΏΡΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡΠ΅Π»ΡΠ½ΠΎΡΡΠΈ GPU
Wudgine::Profiling::GPUProfiler::Initialize();
// ΠΠ°ΠΏΡΡΠΊ Π°Π½Π°Π»ΠΈΠ·Π°
void AnalyzeGPUPerformance() {
Wudgine::Profiling::GPUProfiler::BeginSession("RenderingPipeline");
// ΠΡΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅ ΡΠ΅Π½Π΄Π΅ΡΠΈΠ½Π³Π°
for (int i = 0; i < 100; i++) {
renderer.BeginFrame();
{
WUDGINE_GPU_PROFILE_SCOPE("Shadow Maps");
renderer.RenderShadowMaps();
}
{
WUDGINE_GPU_PROFILE_SCOPE("GBuffer");
renderer.RenderGBuffer();
}
{
WUDGINE_GPU_PROFILE_SCOPE("Lighting");
renderer.RenderLighting();
}
{
WUDGINE_GPU_PROFILE_SCOPE("Post-Processing");
renderer.RenderPostProcessing();
}
renderer.EndFrame();
}
// ΠΠ°Π²Π΅ΡΡΠ΅Π½ΠΈΠ΅ Π°Π½Π°Π»ΠΈΠ·Π° ΠΈ ΡΠΎΡ
ΡΠ°Π½Π΅Π½ΠΈΠ΅ ΡΠ΅Π·ΡΠ»ΡΡΠ°ΡΠΎΠ²
Wudgine::Profiling::GPUProfiler::EndSession();
Wudgine::Profiling::GPUProfiler::SaveResults("gpu_profile.json");
}
ΠΡΠΈΠΌΠ΅ΡΡ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΡ
ΠΡΠ»Π°Π΄ΠΊΠ° ΡΡΠ΅ΡΠ΅ΠΊ ΠΏΠ°ΠΌΡΡΠΈ
// ΠΡΠΈΠΌΠ΅Ρ ΠΎΡΠ»Π°Π΄ΠΊΠΈ ΡΡΠ΅ΡΠ΅ΠΊ ΠΏΠ°ΠΌΡΡΠΈ
void DebugMemoryLeaks() {
// ΠΠΊΠ»ΡΡΠ΅Π½ΠΈΠ΅ ΠΎΡΡΠ»Π΅ΠΆΠΈΠ²Π°Π½ΠΈΡ ΠΏΠ°ΠΌΡΡΠΈ
Wudgine::Debug::MemoryTracker::Initialize();
// Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ ΡΠ½ΠΈΠΌΠΊΠ° ΠΏΠ°ΠΌΡΡΠΈ ΠΏΠ΅ΡΠ΅Π΄ Π²ΡΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅ΠΌ ΠΎΠΏΠ΅ΡΠ°ΡΠΈΠΉ
auto beforeSnapshot = Wudgine::Debug::MemoryTracker::CreateSnapshot();
// ΠΡΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅ ΠΎΠΏΠ΅ΡΠ°ΡΠΈΠΉ, ΠΊΠΎΡΠΎΡΡΠ΅ ΠΌΠΎΠ³ΡΡ Π²ΡΠ·ΡΠ²Π°ΡΡ ΡΡΠ΅ΡΠΊΠΈ
{
// ΠΠ°ΠΌΠ΅ΡΠ΅Π½Π½Π°Ρ ΡΡΠ΅ΡΠΊΠ° ΠΏΠ°ΠΌΡΡΠΈ Π΄Π»Ρ Π΄Π΅ΠΌΠΎΠ½ΡΡΡΠ°ΡΠΈΠΈ
auto* leakedData = new char[1024 * 1024]; // 1 ΠΠ
std::cout << "ΠΡΠ΄Π΅Π»Π΅Π½ΠΎ " << leakedData << std::endl;
// ΠΡΡΡΡΡΡΠ²ΡΠ΅Ρ delete[]
}
// ΠΡΠΈΠ½ΡΠ΄ΠΈΡΠ΅Π»ΡΠ½ΡΠΉ ΡΠ±ΠΎΡ ΠΌΡΡΠΎΡΠ° (Π΅ΡΠ»ΠΈ ΠΏΡΠΈΠΌΠ΅Π½ΠΈΠΌΠΎ)
Wudgine::Memory::GarbageCollector::Collect();
// Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ ΡΠ½ΠΈΠΌΠΊΠ° ΠΏΠ°ΠΌΡΡΠΈ ΠΏΠΎΡΠ»Π΅ Π²ΡΠΏΠΎΠ»Π½Π΅Π½ΠΈΡ ΠΎΠΏΠ΅ΡΠ°ΡΠΈΠΉ
auto afterSnapshot = Wudgine::Debug::MemoryTracker::CreateSnapshot();
// Π‘ΡΠ°Π²Π½Π΅Π½ΠΈΠ΅ ΡΠ½ΠΈΠΌΠΊΠΎΠ² Π΄Π»Ρ Π²ΡΡΠ²Π»Π΅Π½ΠΈΡ ΡΡΠ΅ΡΠ΅ΠΊ
auto diff = Wudgine::Debug::MemoryTracker::CompareSnapshots(beforeSnapshot, afterSnapshot);
// ΠΡΠ²ΠΎΠ΄ ΡΠ΅Π·ΡΠ»ΡΡΠ°ΡΠΎΠ²
if (diff.newAllocations.empty()) {
std::cout << "Π£ΡΠ΅ΡΠ΅ΠΊ ΠΏΠ°ΠΌΡΡΠΈ Π½Π΅ ΠΎΠ±Π½Π°ΡΡΠΆΠ΅Π½ΠΎ!" << std::endl;
} else {
std::cout << "ΠΠ±Π½Π°ΡΡΠΆΠ΅Π½Ρ ΠΏΠΎΡΠ΅Π½ΡΠΈΠ°Π»ΡΠ½ΡΠ΅ ΡΡΠ΅ΡΠΊΠΈ ΠΏΠ°ΠΌΡΡΠΈ:" << std::endl;
for (const auto& alloc : diff.newAllocations) {
std::cout << "- " << alloc.size << " Π±Π°ΠΉΡ Π² " << alloc.file << ":" << alloc.line << std::endl;
}
}
}
ΠΡΠΎΡΠΈΠ»ΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅ ΠΏΡΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡΠ΅Π»ΡΠ½ΠΎΡΡΠΈ ΠΈΠ³ΡΡ
// ΠΡΠΈΠΌΠ΅Ρ ΠΏΡΠΎΡΠΈΠ»ΠΈΡΠΎΠ²Π°Π½ΠΈΡ ΠΏΡΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡΠ΅Π»ΡΠ½ΠΎΡΡΠΈ ΠΈΠ³ΡΡ
void ProfileGamePerformance() {
// ΠΠ½ΠΈΡΠΈΠ°Π»ΠΈΠ·Π°ΡΠΈΡ ΠΏΡΠΎΡΠΈΠ»ΠΈΡΠΎΠ²ΡΠΈΠΊΠ°
Wudgine::Profiling::Profiler::Initialize();
// ΠΠ°ΡΡΡΠΎΠΉΠΊΠ° ΠΏΠ°ΡΠ°ΠΌΠ΅ΡΡΠΎΠ² ΠΏΡΠΎΡΠΈΠ»ΠΈΡΠΎΠ²Π°Π½ΠΈΡ
Wudgine::Profiling::ProfilerSettings settings;
settings.captureFrameCount = 100; // ΠΠΎΠ»ΠΈΡΠ΅ΡΡΠ²ΠΎ ΠΊΠ°Π΄ΡΠΎΠ² Π΄Π»Ρ ΠΏΡΠΎΡΠΈΠ»ΠΈΡΠΎΠ²Π°Π½ΠΈΡ
settings.samplingFrequency = 1000; // Π§Π°ΡΡΠΎΡΠ° ΡΡΠΌΠΏΠ»ΠΈΡΠΎΠ²Π°Π½ΠΈΡ (ΠΡ)
settings.outputFile = "game_profile.json";
Wudgine::Profiling::Profiler::Configure(settings);
// ΠΠ°ΠΏΡΡΠΊ ΠΏΡΠΎΡΠΈΠ»ΠΈΡΠΎΠ²Π°Π½ΠΈΡ
Wudgine::Profiling::Profiler::StartCapture();
// ΠΡΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅ ΠΈΠ³ΡΠΎΠ²ΠΎΠ³ΠΎ ΡΠΈΠΊΠ»Π°
for (int i = 0; i < settings.captureFrameCount; i++) {
WUDGINE_PROFILE_FRAME("Frame " + std::to_string(i));
{
WUDGINE_PROFILE_SCOPE("Input");
ProcessInput();
}
{
WUDGINE_PROFILE_SCOPE("Physics");
physicsSystem.Update(1.0f / 60.0f);
}
{
WUDGINE_PROFILE_SCOPE("AI");
aiSystem.Update(1.0f / 60.0f);
}
{
WUDGINE_PROFILE_SCOPE("Game Logic");
gameLogicSystem.Update(1.0f / 60.0f);
}
{
WUDGINE_PROFILE_SCOPE("Rendering");
renderSystem.Render();
}
}
// ΠΡΡΠ°Π½ΠΎΠ²ΠΊΠ° ΠΏΡΠΎΡΠΈΠ»ΠΈΡΠΎΠ²Π°Π½ΠΈΡ ΠΈ ΡΠΎΡ
ΡΠ°Π½Π΅Π½ΠΈΠ΅ ΡΠ΅Π·ΡΠ»ΡΡΠ°ΡΠΎΠ²
Wudgine::Profiling::Profiler::StopCapture();
// ΠΠ½Π°Π»ΠΈΠ· ΡΠ΅Π·ΡΠ»ΡΡΠ°ΡΠΎΠ²
auto results = Wudgine::Profiling::Profiler::GetResults();
std::cout << "Π Π΅Π·ΡΠ»ΡΡΠ°ΡΡ ΠΏΡΠΎΡΠΈΠ»ΠΈΡΠΎΠ²Π°Π½ΠΈΡ:" << std::endl;
std::cout << "- Π‘ΡΠ΅Π΄Π½Π΅Π΅ Π²ΡΠ΅ΠΌΡ ΠΊΠ°Π΄ΡΠ°: " << results.averageFrameTime << " ΠΌΡ" << std::endl;
std::cout << "- ΠΠΈΠ½ΠΈΠΌΠ°Π»ΡΠ½ΠΎΠ΅ Π²ΡΠ΅ΠΌΡ ΠΊΠ°Π΄ΡΠ°: " << results.minFrameTime << " ΠΌΡ" << std::endl;
std::cout << "- ΠΠ°ΠΊΡΠΈΠΌΠ°Π»ΡΠ½ΠΎΠ΅ Π²ΡΠ΅ΠΌΡ ΠΊΠ°Π΄ΡΠ°: " << results.maxFrameTime << " ΠΌΡ" << std::endl;
std::cout << "- 99-ΠΉ ΠΏΡΠΎΡΠ΅Π½ΡΠΈΠ»Ρ: " << results.percentile99 << " ΠΌΡ" << std::endl;
// ΠΡΠ²ΠΎΠ΄ Π²ΡΠ΅ΠΌΠ΅Π½ΠΈ Π²ΡΠΏΠΎΠ»Π½Π΅Π½ΠΈΡ ΠΏΠΎ ΠΊΠ°ΡΠ΅Π³ΠΎΡΠΈΡΠΌ
for (const auto& category : results.categories) {
std::cout << "- " << category.name << ": "
<< category.averageTime << " ΠΌΡ ("
<< (category.averageTime / results.averageFrameTime * 100.0f) << "%)" << std::endl;
}
}
Π‘Π²ΡΠ·Π°Π½Π½ΡΠ΅ ΡΠ°Π·Π΄Π΅Π»Ρ
- ΠΠ½ΠΎΠ³ΠΎΠΏΠΎΡΠΎΡΠ½ΠΎΡΡΡ - Π£Π·Π½Π°ΠΉΡΠ΅, ΠΊΠ°ΠΊ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΡ ΠΌΠ½ΠΎΠ³ΠΎΠΏΠΎΡΠΎΡΠ½ΠΎΡΡΡ Π΄Π»Ρ ΠΏΠΎΠ²ΡΡΠ΅Π½ΠΈΡ ΠΏΡΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡΠ΅Π»ΡΠ½ΠΎΡΡΠΈ.
- ΠΠΏΡΠΈΠΌΠΈΠ·Π°ΡΠΈΡ ΠΏΡΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡΠ΅Π»ΡΠ½ΠΎΡΡΠΈ - ΠΠ·ΡΡΠΈΡΠ΅ ΠΌΠ΅ΡΠΎΠ΄Ρ ΠΎΠΏΡΠΈΠΌΠΈΠ·Π°ΡΠΈΠΈ ΠΏΡΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡΠ΅Π»ΡΠ½ΠΎΡΡΠΈ ΠΈΠ³ΡΡ.
- ΠΡΠΎΠ΄Π²ΠΈΠ½ΡΡΠΎΠ΅ ΡΠΏΡΠ°Π²Π»Π΅Π½ΠΈΠ΅ ΡΠ΅ΡΡΡΡΠ°ΠΌΠΈ - Π£Π·Π½Π°ΠΉΡΠ΅ ΠΎ ΠΏΡΠΎΠ΄Π²ΠΈΠ½ΡΡΡΡ ΠΌΠ΅ΡΠΎΠ΄Π°Ρ ΡΠΏΡΠ°Π²Π»Π΅Π½ΠΈΡ ΡΠ΅ΡΡΡΡΠ°ΠΌΠΈ.