565 lines
16 KiB
C++
565 lines
16 KiB
C++
// Copyright 2020 Mookie. All Rights Reserved.
|
|
|
|
#include "EBBullet.h"
|
|
#include "EBBarrel.h"
|
|
#include "EBUnitConversions.h"
|
|
#include "Engine/World.h"
|
|
#include "Engine/Engine.h"
|
|
#include "PhysicalMaterials/PhysicalMaterial.h"
|
|
#include "DrawDebugHelpers.h"
|
|
|
|
// Initialize static debug counter
|
|
int32 AEBBullet::DebugMessageCounter = 0;
|
|
|
|
void AEBBullet::CreateDebugImpactWidget(FVector Location, bool bRicochet, bool bPenetration, FVector ImpactVelocity, float PenetrationDepth, UPhysicalMaterial* Material)
|
|
{
|
|
if (!DebugEnabled || !DebugImpact)
|
|
{
|
|
return;
|
|
}
|
|
|
|
UEBBarrel* Barrel = GetFiringBarrel();
|
|
if (!Barrel || !Barrel->DebugImpactInfo)
|
|
{
|
|
return;
|
|
}
|
|
|
|
UWorld* World = GetWorld();
|
|
if (!World)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Add to debug tracking
|
|
DebugImpactLocations.Add(Location);
|
|
DebugImpactTimes.Add(World->GetTimeSeconds());
|
|
|
|
// Clean up old debug data
|
|
float CurrentTime = World->GetTimeSeconds();
|
|
for (int32 i = DebugImpactLocations.Num() - 1; i >= 0; i--)
|
|
{
|
|
if (CurrentTime - DebugImpactTimes[i] > ImpactDebugTime)
|
|
{
|
|
DebugImpactLocations.RemoveAt(i);
|
|
DebugImpactTimes.RemoveAt(i);
|
|
}
|
|
}
|
|
|
|
// Build comprehensive debug information
|
|
FString ImpactType;
|
|
FLinearColor ImpactColor;
|
|
if (bRicochet)
|
|
{
|
|
ImpactType = TEXT("RICOCHET");
|
|
ImpactColor = ImpactColorRicochet;
|
|
}
|
|
else if (bPenetration)
|
|
{
|
|
ImpactType = TEXT("PENETRATION");
|
|
ImpactColor = ImpactColorPenetration;
|
|
}
|
|
else
|
|
{
|
|
ImpactType = TEXT("STOPPED");
|
|
ImpactColor = ImpactColorStopped;
|
|
}
|
|
|
|
FString MaterialName = Material ? Material->GetName() : TEXT("Unknown");
|
|
float VelocityCMPS = ImpactVelocity.Size();
|
|
float VelocityMPS = FEBUnitConversions::CMPSToMPS(VelocityCMPS);
|
|
float VelocityKMH = FEBUnitConversions::CMPSToKMH(VelocityCMPS);
|
|
float KineticEnergy = FEBUnitConversions::CalculateKineticEnergyJoules(GetEffectiveMass(), VelocityMPS);
|
|
|
|
FString DebugInfo = FString::Printf(TEXT(
|
|
"Impact: %s | Material: %s | Velocity: %.1f m/s (%.1f km/h) | Mass: %.3f kg | Diameter: %.2f cm | Energy: %.1f J | Penetration: %.2f cm"
|
|
),
|
|
*ImpactType,
|
|
*MaterialName,
|
|
VelocityMPS,
|
|
VelocityKMH,
|
|
GetEffectiveMass(),
|
|
GetEffectiveDiameter(),
|
|
KineticEnergy,
|
|
PenetrationDepth
|
|
);
|
|
|
|
// Display debug information
|
|
if (UseOnScreenMessages && GEngine)
|
|
{
|
|
// Manage message count
|
|
if (DebugMessageCounter > MaxOnScreenMessages)
|
|
{
|
|
DebugMessageCounter = 0;
|
|
}
|
|
|
|
GEngine->AddOnScreenDebugMessage(DebugMessageCounter++, ImpactDebugTime,
|
|
FColor(ImpactColor.R * 255, ImpactColor.G * 255, ImpactColor.B * 255), DebugInfo);
|
|
}
|
|
|
|
if (UseWorldSpaceText)
|
|
{
|
|
DrawDebugString(World, Location + FVector(0, 0, 50), DebugInfo, nullptr,
|
|
FColor(ImpactColor.R * 255, ImpactColor.G * 255, ImpactColor.B * 255),
|
|
ImpactDebugTime, false, WorldTextScale);
|
|
}
|
|
}
|
|
|
|
void AEBBullet::DrawTrajectoryDebug(FVector StartLocation, FVector EndLocation, FVector CurrentVelocity, float DeltaTime)
|
|
{
|
|
if (!DebugEnabled || !DebugTrajectory)
|
|
{
|
|
return;
|
|
}
|
|
|
|
UWorld* World = GetWorld();
|
|
if (!World)
|
|
{
|
|
return;
|
|
}
|
|
|
|
float CurrentTime = World->GetTimeSeconds();
|
|
|
|
// Add trajectory point
|
|
if (ShowTrail)
|
|
{
|
|
DebugTrajectoryPoints.Add(StartLocation);
|
|
DebugTrajectoryTimes.Add(CurrentTime);
|
|
|
|
// Clean up old trajectory points
|
|
for (int32 i = DebugTrajectoryPoints.Num() - 1; i >= 0; i--)
|
|
{
|
|
if (CurrentTime - DebugTrajectoryTimes[i] > DebugTrailTime)
|
|
{
|
|
DebugTrajectoryPoints.RemoveAt(i);
|
|
DebugTrajectoryTimes.RemoveAt(i);
|
|
}
|
|
}
|
|
|
|
// Draw trajectory trail
|
|
if (DebugTrajectoryPoints.Num() > 1)
|
|
{
|
|
for (int32 i = 1; i < DebugTrajectoryPoints.Num(); i++)
|
|
{
|
|
float Alpha = FMath::Clamp((CurrentTime - DebugTrajectoryTimes[i]) / DebugTrailTime, 0.0f, 1.0f);
|
|
float VelocityNormalized = FMath::Clamp(CurrentVelocity.Size() / 100000.0f, 0.0f, 1.0f); // Normalize to ~1000m/s
|
|
|
|
FLinearColor TrailColor = FMath::Lerp(DebugTrailColorSlow, DebugTrailColorFast, VelocityNormalized);
|
|
TrailColor.A = 1.0f - Alpha;
|
|
|
|
float LineThickness = DebugTrailWidth > 0 ? DebugTrailWidth : 1.0f;
|
|
DrawDebugLine(World, DebugTrajectoryPoints[i-1], DebugTrajectoryPoints[i],
|
|
FColor(TrailColor.R * 255, TrailColor.G * 255, TrailColor.B * 255, TrailColor.A * 255),
|
|
false, -1, 0, LineThickness);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Show velocity vectors
|
|
if (ShowVelocityVectors)
|
|
{
|
|
FVector VelocityVector = CurrentVelocity * VelocityVectorScale;
|
|
DrawDebugDirectionalArrow(World, StartLocation, StartLocation + VelocityVector,
|
|
50.0f, FColor::Blue, false, DebugTrailTime, 0, 2.0f);
|
|
|
|
// Add velocity magnitude text
|
|
FString VelocityText = FString::Printf(TEXT("%.1f m/s"),
|
|
FEBUnitConversions::CMPSToMPS(CurrentVelocity.Size()));
|
|
DrawDebugString(World, StartLocation + FVector(0, 0, 30), VelocityText, nullptr,
|
|
FColor::Blue, DebugTrailTime, false, WorldTextScale);
|
|
}
|
|
|
|
// Show path prediction
|
|
if (ShowPathPrediction && PathPredictionSteps > 0)
|
|
{
|
|
FVector PredictLocation = StartLocation;
|
|
FVector PredictVelocity = CurrentVelocity;
|
|
float PredictDeltaTime = DeltaTime * 5.0f; // Predict further ahead
|
|
|
|
for (int32 i = 0; i < PathPredictionSteps; i++)
|
|
{
|
|
FVector NextLocation = PredictLocation + PredictVelocity * PredictDeltaTime;
|
|
|
|
// Apply gravity and drag prediction (simplified)
|
|
FVector GravityForce = OverrideGravity ? Gravity : FVector(0, 0, -980);
|
|
PredictVelocity += GravityForce * PredictDeltaTime;
|
|
|
|
DrawDebugLine(World, PredictLocation, NextLocation, FColor::Yellow, false,
|
|
DebugTrailTime, 0, 1.0f);
|
|
DrawDebugSphere(World, NextLocation, 2.0f, 8, FColor::Yellow, false, DebugTrailTime);
|
|
|
|
PredictLocation = NextLocation;
|
|
}
|
|
}
|
|
}
|
|
|
|
void AEBBullet::DrawImpactDebug(FVector ImpactLocation, FVector ImpactVelocity, FVector ImpactNormal, bool bRicochet, bool bPenetration, float PenetrationDepth, UPhysicalMaterial* Material)
|
|
{
|
|
if (!DebugEnabled || !DebugImpact)
|
|
{
|
|
return;
|
|
}
|
|
|
|
UWorld* World = GetWorld();
|
|
if (!World)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Choose color based on impact type
|
|
FLinearColor ImpactColor;
|
|
if (bRicochet)
|
|
{
|
|
ImpactColor = ImpactColorRicochet;
|
|
}
|
|
else if (bPenetration)
|
|
{
|
|
ImpactColor = ImpactColorPenetration;
|
|
}
|
|
else
|
|
{
|
|
ImpactColor = ImpactColorStopped;
|
|
}
|
|
|
|
FColor DebugColor(ImpactColor.R * 255, ImpactColor.G * 255, ImpactColor.B * 255);
|
|
|
|
// Show impact points
|
|
if (ShowImpactPoints)
|
|
{
|
|
DrawDebugSphere(World, ImpactLocation, ImpactPointSize, 12, DebugColor, false, ImpactDebugTime);
|
|
}
|
|
|
|
// Show impact normals
|
|
if (ShowImpactNormals)
|
|
{
|
|
DrawDebugDirectionalArrow(World, ImpactLocation, ImpactLocation + ImpactNormal * 50.0f,
|
|
20.0f, DebugColor, false, ImpactDebugTime, 0, 2.0f);
|
|
}
|
|
|
|
// Show penetration depth
|
|
if (ShowPenetrationDepth && bPenetration)
|
|
{
|
|
FVector PenetrationVector = -ImpactNormal * PenetrationDepth;
|
|
DrawDebugLine(World, ImpactLocation, ImpactLocation + PenetrationVector,
|
|
FColor::Green, false, ImpactDebugTime, 0, 3.0f);
|
|
|
|
FString PenetrationText = FString::Printf(TEXT("Pen: %.1f cm"), PenetrationDepth);
|
|
DrawDebugString(World, ImpactLocation + PenetrationVector + FVector(0, 0, 20),
|
|
PenetrationText, nullptr, FColor::Green, ImpactDebugTime, false, WorldTextScale);
|
|
}
|
|
|
|
// Show ricochet angles
|
|
if (ShowRicochetAngles && bRicochet)
|
|
{
|
|
FVector ReflectedVelocity = ImpactVelocity - 2 * FVector::DotProduct(ImpactVelocity, ImpactNormal) * ImpactNormal;
|
|
DrawDebugDirectionalArrow(World, ImpactLocation, ImpactLocation + ReflectedVelocity.GetSafeNormal() * 75.0f,
|
|
30.0f, FColor::Yellow, false, ImpactDebugTime, 0, 2.0f);
|
|
|
|
float RicochetAngle = FMath::Acos(FVector::DotProduct(-ImpactVelocity.GetSafeNormal(), ImpactNormal));
|
|
FString AngleText = FString::Printf(TEXT("Angle: %.1f°"), FMath::RadiansToDegrees(RicochetAngle));
|
|
DrawDebugString(World, ImpactLocation + FVector(0, 0, 40), AngleText, nullptr,
|
|
FColor::Yellow, ImpactDebugTime, false, WorldTextScale);
|
|
}
|
|
|
|
// Show material information
|
|
if (ShowMaterialInfo && Material)
|
|
{
|
|
FString MaterialInfo = FString::Printf(TEXT("Material: %s"), *Material->GetName());
|
|
DrawDebugString(World, ImpactLocation + FVector(0, 0, 60), MaterialInfo, nullptr,
|
|
DebugColor, ImpactDebugTime, false, WorldTextScale);
|
|
}
|
|
}
|
|
|
|
void AEBBullet::DrawPhysicsDebug(FVector Location, FVector DragForce, FVector GravityForce, FVector WindForce, float AirDensity, float SpeedOfSound)
|
|
{
|
|
if (!DebugEnabled || !DebugPhysics)
|
|
{
|
|
return;
|
|
}
|
|
|
|
UWorld* World = GetWorld();
|
|
if (!World)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Show drag forces
|
|
if (ShowDragForces && !DragForce.IsNearlyZero())
|
|
{
|
|
FVector DragVector = DragForce * ForceVectorScale;
|
|
DrawDebugDirectionalArrow(World, Location, Location + DragVector,
|
|
10.0f, FColor::Red, false, PhysicsDebugTime, 0, 1.5f);
|
|
|
|
FString DragText = FString::Printf(TEXT("Drag: %.1f N"), DragForce.Size());
|
|
DrawDebugString(World, Location + DragVector + FVector(0, 0, 10), DragText, nullptr,
|
|
FColor::Red, PhysicsDebugTime, false, WorldTextScale);
|
|
}
|
|
|
|
// Show gravity effect
|
|
if (ShowGravityEffect && !GravityForce.IsNearlyZero())
|
|
{
|
|
FVector GravityVector = GravityForce * ForceVectorScale;
|
|
DrawDebugDirectionalArrow(World, Location, Location + GravityVector,
|
|
10.0f, FColor::Purple, false, PhysicsDebugTime, 0, 1.5f);
|
|
|
|
FString GravityText = FString::Printf(TEXT("Gravity: %.1f N"), GravityForce.Size());
|
|
DrawDebugString(World, Location + GravityVector + FVector(0, 0, 10), GravityText, nullptr,
|
|
FColor::Purple, PhysicsDebugTime, false, WorldTextScale);
|
|
}
|
|
|
|
// Show wind effect
|
|
if (ShowWindEffect && !WindForce.IsNearlyZero())
|
|
{
|
|
FVector WindVector = WindForce * ForceVectorScale;
|
|
DrawDebugDirectionalArrow(World, Location, Location + WindVector,
|
|
10.0f, FColor::Cyan, false, PhysicsDebugTime, 0, 1.5f);
|
|
|
|
FString WindText = FString::Printf(TEXT("Wind: %.1f N"), WindForce.Size());
|
|
DrawDebugString(World, Location + WindVector + FVector(0, 0, 10), WindText, nullptr,
|
|
FColor::Cyan, PhysicsDebugTime, false, WorldTextScale);
|
|
}
|
|
|
|
// Show atmospheric data
|
|
if (ShowAtmosphericData)
|
|
{
|
|
FString AtmosphericInfo = FString::Printf(TEXT(
|
|
"Air Density: %.3f kg/m³\nSpeed of Sound: %.1f m/s\nAltitude: %.1f m"
|
|
),
|
|
AirDensity,
|
|
FEBUnitConversions::CMPSToMPS(SpeedOfSound),
|
|
FEBUnitConversions::CMToM(GetAltitude(World, Location))
|
|
);
|
|
|
|
DrawDebugString(World, Location + FVector(0, 0, 80), AtmosphericInfo, nullptr,
|
|
FColor::White, PhysicsDebugTime, false, WorldTextScale);
|
|
}
|
|
}
|
|
|
|
void AEBBullet::DrawBallisticsDebug(FVector Location, FVector BulletVelocity, float KineticEnergy, float DragCoefficient, float MachNumber)
|
|
{
|
|
if (!DebugEnabled || !DebugBallistics)
|
|
{
|
|
return;
|
|
}
|
|
|
|
UWorld* World = GetWorld();
|
|
if (!World)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Show energy calculations
|
|
if (ShowEnergyCalculations)
|
|
{
|
|
FString EnergyInfo = FString::Printf(TEXT(
|
|
"Kinetic Energy: %.1f J\nMomentum: %.3f kg⋅m/s\nPower: %.1f W"
|
|
),
|
|
KineticEnergy,
|
|
GetEffectiveMass() * FEBUnitConversions::CMPSToMPS(BulletVelocity.Size()),
|
|
KineticEnergy * BulletVelocity.Size() / 100.0f // Simplified power calculation
|
|
);
|
|
|
|
DrawDebugString(World, Location + FVector(0, 0, 100), EnergyInfo, nullptr,
|
|
FColor::Orange, BallisticsDebugTime, false, WorldTextScale);
|
|
}
|
|
|
|
// Show mathematical comparison
|
|
if (ShowMathematicalComparison && UseMathematicalPhysics)
|
|
{
|
|
FString MathInfo = FString::Printf(TEXT(
|
|
"Mathematical Mode: ON\nDrag Coefficient: %.3f\nMach Number: %.2f"
|
|
),
|
|
DragCoefficient,
|
|
MachNumber
|
|
);
|
|
|
|
DrawDebugString(World, Location + FVector(0, 0, 120), MathInfo, nullptr,
|
|
FColor::Green, BallisticsDebugTime, false, WorldTextScale);
|
|
}
|
|
|
|
// Show ballistic coefficient
|
|
if (ShowBallisticCoefficient)
|
|
{
|
|
float BallisticCoefficient = GetEffectiveMass() / (DragCoefficient * GetEffectiveDiameter() * GetEffectiveDiameter());
|
|
FString BCInfo = FString::Printf(TEXT("Ballistic Coefficient: %.3f"), BallisticCoefficient);
|
|
|
|
DrawDebugString(World, Location + FVector(0, 0, 140), BCInfo, nullptr,
|
|
FColor::Magenta, BallisticsDebugTime, false, WorldTextScale);
|
|
}
|
|
}
|
|
|
|
void AEBBullet::DrawSpallDebug(FVector ImpactLocation, FVector ImpactVelocity, FVector ImpactNormal, TArray<FVector> FragmentVelocities)
|
|
{
|
|
if (!DebugEnabled || !DebugSpalling)
|
|
{
|
|
return;
|
|
}
|
|
|
|
UWorld* World = GetWorld();
|
|
if (!World)
|
|
{
|
|
return;
|
|
}
|
|
|
|
FColor PrimaryColor(SpallColorPrimary.R * 255, SpallColorPrimary.G * 255, SpallColorPrimary.B * 255);
|
|
FColor FragmentColor(SpallColorFragment.R * 255, SpallColorFragment.G * 255, SpallColorFragment.B * 255);
|
|
|
|
// Show spall generation
|
|
if (ShowSpallGeneration)
|
|
{
|
|
DrawDebugSphere(World, ImpactLocation, 8.0f, 16, PrimaryColor, false, SpallDebugTime);
|
|
|
|
FString SpallInfo = FString::Printf(TEXT("Spall Generated: %d fragments"), FragmentVelocities.Num());
|
|
DrawDebugString(World, ImpactLocation + FVector(0, 0, 70), SpallInfo, nullptr,
|
|
PrimaryColor, SpallDebugTime, false, WorldTextScale);
|
|
}
|
|
|
|
// Show fragment trajectories
|
|
if (ShowFragmentTrajectories)
|
|
{
|
|
for (int32 i = 0; i < FragmentVelocities.Num(); i++)
|
|
{
|
|
FVector FragmentDirection = FragmentVelocities[i].GetSafeNormal();
|
|
FVector FragmentEndpoint = ImpactLocation + FragmentDirection * 100.0f;
|
|
|
|
DrawDebugDirectionalArrow(World, ImpactLocation, FragmentEndpoint,
|
|
15.0f, FragmentColor, false, SpallDebugTime, 0, 1.0f);
|
|
}
|
|
}
|
|
|
|
// Show spall cones
|
|
if (ShowSpallCones && FragmentVelocities.Num() > 0)
|
|
{
|
|
// Calculate cone parameters
|
|
FVector ConeDirection = ImpactNormal;
|
|
float ConeAngle = FMath::DegreesToRadians(45.0f); // 45 degree cone
|
|
float ConeLength = 80.0f;
|
|
|
|
// Draw cone outline
|
|
int32 ConeSides = 8;
|
|
TArray<FVector> ConePoints;
|
|
|
|
for (int32 i = 0; i < ConeSides; i++)
|
|
{
|
|
float Angle = (2.0f * PI * i) / ConeSides;
|
|
FVector RadialDirection = FVector(FMath::Cos(Angle), FMath::Sin(Angle), 0);
|
|
FVector ConePoint = ImpactLocation + ConeDirection * ConeLength + RadialDirection * FMath::Tan(ConeAngle) * ConeLength;
|
|
ConePoints.Add(ConePoint);
|
|
|
|
// Draw lines from impact point to cone edge
|
|
DrawDebugLine(World, ImpactLocation, ConePoint, PrimaryColor, false, SpallDebugTime, 0, 0.5f);
|
|
}
|
|
|
|
// Draw cone base
|
|
for (int32 i = 0; i < ConeSides; i++)
|
|
{
|
|
int32 NextIndex = (i + 1) % ConeSides;
|
|
DrawDebugLine(World, ConePoints[i], ConePoints[NextIndex], PrimaryColor, false, SpallDebugTime, 0, 0.5f);
|
|
}
|
|
}
|
|
}
|
|
|
|
void AEBBullet::DrawPerformanceDebug(FVector Location, int32 TraceCount, float FrameTime, int32 PooledBullets)
|
|
{
|
|
if (!DebugEnabled || !DebugPerformance)
|
|
{
|
|
return;
|
|
}
|
|
|
|
UWorld* World = GetWorld();
|
|
if (!World)
|
|
{
|
|
return;
|
|
}
|
|
|
|
FString PerformanceInfo;
|
|
|
|
// Show trace count
|
|
if (ShowTraceCount)
|
|
{
|
|
PerformanceInfo += FString::Printf(TEXT("Traces: %d\n"), TraceCount);
|
|
}
|
|
|
|
// Show frame timing
|
|
if (ShowFrameTiming)
|
|
{
|
|
float FPS = FrameTime > 0 ? 1.0f / FrameTime : 0.0f;
|
|
PerformanceInfo += FString::Printf(TEXT("Frame Time: %.2f ms (%.1f FPS)\n"), FrameTime * 1000.0f, FPS);
|
|
}
|
|
|
|
// Show pooling stats
|
|
if (ShowPoolingStats && EnablePooling)
|
|
{
|
|
PerformanceInfo += FString::Printf(TEXT("Pooled Bullets: %d/%d\n"), PooledBullets, MaxPoolSize);
|
|
}
|
|
|
|
if (!PerformanceInfo.IsEmpty())
|
|
{
|
|
DrawDebugString(World, Location + FVector(0, 0, 160), PerformanceInfo, nullptr,
|
|
FColor::Cyan, PerformanceDebugTime, false, WorldTextScale);
|
|
}
|
|
}
|
|
|
|
void AEBBullet::ClearDebugDisplay()
|
|
{
|
|
DebugTrajectoryPoints.Empty();
|
|
DebugTrajectoryTimes.Empty();
|
|
DebugImpactLocations.Empty();
|
|
DebugImpactTimes.Empty();
|
|
DebugTraceCounter = 0;
|
|
DebugMessageCounter = 0;
|
|
}
|
|
|
|
void AEBBullet::ToggleDebugCategory(const FString& CategoryName, bool bEnabled)
|
|
{
|
|
if (CategoryName == TEXT("Trajectory"))
|
|
{
|
|
DebugTrajectory = bEnabled;
|
|
}
|
|
else if (CategoryName == TEXT("Impact"))
|
|
{
|
|
DebugImpact = bEnabled;
|
|
}
|
|
else if (CategoryName == TEXT("Physics"))
|
|
{
|
|
DebugPhysics = bEnabled;
|
|
}
|
|
else if (CategoryName == TEXT("Performance"))
|
|
{
|
|
DebugPerformance = bEnabled;
|
|
}
|
|
else if (CategoryName == TEXT("Ballistics"))
|
|
{
|
|
DebugBallistics = bEnabled;
|
|
}
|
|
else if (CategoryName == TEXT("Spalling"))
|
|
{
|
|
DebugSpalling = bEnabled;
|
|
}
|
|
else if (CategoryName == TEXT("Pooling"))
|
|
{
|
|
DebugPooling = bEnabled;
|
|
}
|
|
}
|
|
|
|
FString AEBBullet::GetDebugInfoString() const
|
|
{
|
|
return FString::Printf(TEXT(
|
|
"Bullet Debug Info:\n"
|
|
"Enabled: %s\n"
|
|
"Trajectory: %s | Impact: %s | Physics: %s\n"
|
|
"Performance: %s | Ballistics: %s | Spalling: %s\n"
|
|
"Trace Count: %d | Active Trajectory Points: %d\n"
|
|
"Active Impact Points: %d"
|
|
),
|
|
DebugEnabled ? TEXT("Yes") : TEXT("No"),
|
|
DebugTrajectory ? TEXT("On") : TEXT("Off"),
|
|
DebugImpact ? TEXT("On") : TEXT("Off"),
|
|
DebugPhysics ? TEXT("On") : TEXT("Off"),
|
|
DebugPerformance ? TEXT("On") : TEXT("Off"),
|
|
DebugBallistics ? TEXT("On") : TEXT("Off"),
|
|
DebugSpalling ? TEXT("On") : TEXT("Off"),
|
|
DebugTraceCounter,
|
|
DebugTrajectoryPoints.Num(),
|
|
DebugImpactLocations.Num()
|
|
);
|
|
} |