Files
BallisticsDocs/Source/EasyBallistics/Public/EBBullet.h
T
2025-07-10 01:02:24 -07:00

455 lines
33 KiB
C++

// Copyright 2016 Mookie. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Engine/Engine.h"
#include "Engine/World.h"
#include "Curves/CurveFloat.h"
#include "Kismet/KismetMathLibrary.h"
#include "Kismet/GameplayStatics.h"
#include "DrawDebugHelpers.h"
#include "Components/PrimitiveComponent.h"
#include "Components/SphereComponent.h"
#include "EBMaterialResponseMap.h"
#include "EBBulletProperties.h"
#include "EBMathematicalBallistics.h"
#include "EBBallisticImpactComponent.h"
#include "EBBullet.generated.h"
class UEBBarrel;
UENUM(BlueprintType)
enum class EEBAtmosphereType : uint8
{
AT_Constant UMETA(DisplayName = "Constant"),
AT_Curve UMETA(DisplayName = "Density Curve"),
AT_Earth UMETA(DisplayName = "Earth/IGL")
};
UCLASS(Blueprintable, BlueprintType)
class EASYBALLISTICS_API AEBBullet : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
AEBBullet();
// Collision Component
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Collision")
class USphereComponent* Collision;
UPROPERTY(Replicated, BlueprintReadWrite, Category = "State") FVector Velocity;
UPROPERTY(Replicated, BlueprintReadWrite, Category = "State") FRandomStream RandomStream;
UPROPERTY(BlueprintReadWrite, Category = "State") bool OwnerSafe=false;
// Enhanced Debug System
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Debug") bool DebugEnabled;
// Debug Categories
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Debug|Categories") bool DebugTrajectory = true;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Debug|Categories") bool DebugImpact = true;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Debug|Categories") bool DebugPhysics = false;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Debug|Categories") bool DebugPerformance = false;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Debug|Categories") bool DebugBallistics = false;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Debug|Categories") bool DebugSpalling = false;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Debug|Categories") bool DebugPooling = false;
// Trajectory Debug Options
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Debug|Trajectory", meta = (EditCondition = "DebugEnabled && DebugTrajectory")) bool ShowTrail = true;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Debug|Trajectory", meta = (EditCondition = "DebugEnabled && DebugTrajectory")) bool ShowVelocityVectors = false;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Debug|Trajectory", meta = (EditCondition = "DebugEnabled && DebugTrajectory")) bool ShowPathPrediction = false;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Debug|Trajectory", meta = (EditCondition = "DebugEnabled && DebugTrajectory")) bool ShowXRayTrajectory = false;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Debug|Trajectory", meta = (EditCondition = "DebugEnabled && DebugTrajectory")) float DebugTrailTime = 1.0f;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Debug|Trajectory", meta = (EditCondition = "DebugEnabled && DebugTrajectory")) float DebugTrailWidth = 0.0f;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Debug|Trajectory", meta = (EditCondition = "DebugEnabled && DebugTrajectory")) FLinearColor DebugTrailColorFast = FLinearColor(0, 1, 0, 1);
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Debug|Trajectory", meta = (EditCondition = "DebugEnabled && DebugTrajectory")) FLinearColor DebugTrailColorSlow = FLinearColor(1, 0, 0, 1);
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Debug|Trajectory", meta = (EditCondition = "DebugEnabled && DebugTrajectory")) FLinearColor XRayTrajectoryColor = FLinearColor(0, 1, 1, 0.7f);
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Debug|Trajectory", meta = (EditCondition = "DebugEnabled && DebugTrajectory")) FLinearColor PenetrationTrajectoryColor = FLinearColor(1, 0.5f, 0, 0.8f);
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Debug|Trajectory", meta = (EditCondition = "DebugEnabled && DebugTrajectory")) float VelocityVectorScale = 0.01f;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Debug|Trajectory", meta = (EditCondition = "DebugEnabled && DebugTrajectory")) int32 PathPredictionSteps = 10;
// Impact Debug Options
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Debug|Impact", meta = (EditCondition = "DebugEnabled && DebugImpact")) bool ShowImpactPoints = true;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Debug|Impact", meta = (EditCondition = "DebugEnabled && DebugImpact")) bool ShowPenetrationDepth = true;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Debug|Impact", meta = (EditCondition = "DebugEnabled && DebugImpact")) bool ShowRicochetAngles = true;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Debug|Impact", meta = (EditCondition = "DebugEnabled && DebugImpact")) bool ShowMaterialInfo = true;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Debug|Impact", meta = (EditCondition = "DebugEnabled && DebugImpact")) bool ShowImpactNormals = true;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Debug|Impact", meta = (EditCondition = "DebugEnabled && DebugImpact")) float ImpactDebugTime = 10.0f;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Debug|Impact", meta = (EditCondition = "DebugEnabled && DebugImpact")) float ImpactPointSize = 5.0f;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Debug|Impact", meta = (EditCondition = "DebugEnabled && DebugImpact")) FLinearColor ImpactColorPenetration = FLinearColor(0, 1, 0, 1);
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Debug|Impact", meta = (EditCondition = "DebugEnabled && DebugImpact")) FLinearColor ImpactColorRicochet = FLinearColor(1, 1, 0, 1);
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Debug|Impact", meta = (EditCondition = "DebugEnabled && DebugImpact")) FLinearColor ImpactColorStopped = FLinearColor(1, 0, 0, 1);
// Physics Debug Options
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Debug|Physics", meta = (EditCondition = "DebugEnabled && DebugPhysics")) bool ShowDragForces = true;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Debug|Physics", meta = (EditCondition = "DebugEnabled && DebugPhysics")) bool ShowGravityEffect = true;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Debug|Physics", meta = (EditCondition = "DebugEnabled && DebugPhysics")) bool ShowWindEffect = true;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Debug|Physics", meta = (EditCondition = "DebugEnabled && DebugPhysics")) bool ShowAtmosphericData = true;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Debug|Physics", meta = (EditCondition = "DebugEnabled && DebugPhysics")) float PhysicsDebugTime = 5.0f;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Debug|Physics", meta = (EditCondition = "DebugEnabled && DebugPhysics")) float ForceVectorScale = 0.001f;
// Performance Debug Options
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Debug|Performance", meta = (EditCondition = "DebugEnabled && DebugPerformance")) bool ShowTraceCount = true;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Debug|Performance", meta = (EditCondition = "DebugEnabled && DebugPerformance")) bool ShowFrameTiming = true;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Debug|Performance", meta = (EditCondition = "DebugEnabled && DebugPerformance")) bool ShowPoolingStats = true;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Debug|Performance", meta = (EditCondition = "DebugEnabled && DebugPerformance")) float PerformanceDebugTime = 3.0f;
// Ballistics Debug Options
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Debug|Ballistics", meta = (EditCondition = "DebugEnabled && DebugBallistics")) bool ShowEnergyCalculations = true;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Debug|Ballistics", meta = (EditCondition = "DebugEnabled && DebugBallistics")) bool ShowMathematicalComparison = true;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Debug|Ballistics", meta = (EditCondition = "DebugEnabled && DebugBallistics")) bool ShowBallisticCoefficient = true;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Debug|Ballistics", meta = (EditCondition = "DebugEnabled && DebugBallistics")) float BallisticsDebugTime = 8.0f;
// Spalling Debug Options
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Debug|Spalling", meta = (EditCondition = "DebugEnabled && DebugSpalling")) bool ShowSpallGeneration = true;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Debug|Spalling", meta = (EditCondition = "DebugEnabled && DebugSpalling")) bool ShowFragmentTrajectories = true;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Debug|Spalling", meta = (EditCondition = "DebugEnabled && DebugSpalling")) bool ShowSpallCones = true;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Debug|Spalling", meta = (EditCondition = "DebugEnabled && DebugSpalling")) float SpallDebugTime = 5.0f;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Debug|Spalling", meta = (EditCondition = "DebugEnabled && DebugSpalling")) FLinearColor SpallColorPrimary = FLinearColor(1, 0.5f, 0, 1);
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Debug|Spalling", meta = (EditCondition = "DebugEnabled && DebugSpalling")) FLinearColor SpallColorFragment = FLinearColor(0.8f, 0.4f, 0, 1);
// Debug Display Options
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Debug|Display") bool UseWorldSpaceText = true;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Debug|Display") bool UseOnScreenMessages = true;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Debug|Display") float WorldTextScale = 1.0f;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Debug|Display") int32 MaxOnScreenMessages = 10;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "World") FVector Wind;
UPROPERTY(BlueprintReadWrite, EditAnywhere, SaveGame, Category = "World", meta = (ToolTip = "Select atmosphere model")) EEBAtmosphereType AtmosphereType;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "World", meta = (ToolTip = "Air Density at sea level - in KG/m^3", ClampMin = "0")) float SeaLevelAirDensity = 1.21;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "World", meta = (ToolTip = "in cm/s", ClampMin = "0")) float SeaLevelSpeedOfSound = 34300;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "World", meta = (ToolTip = "Used for Density Curve atmosphere model")) UCurveFloat* AirDensityCurve;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "World") bool SpeedOfSoundVariesWithAltitude = false;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "World") UCurveFloat* SpeedOfSoundCurve;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "World") float WorldScale = 1.0;
UPROPERTY(BlueprintReadWrite, EditAnywhere, SaveGame, Category = "World", meta = (ToolTip = "Atmosphere pressure at 0,0,0 - in millibars", ClampMin = "0")) float SeaLevelAirPressure = 1012.5f;
UPROPERTY(BlueprintReadWrite, EditAnywhere, SaveGame, Category = "World", meta = (ToolTip = "Atmosphere Temperature at 0,0,0 - in degrees C")) float SeaLevelAirTemperature = 20.0f;
UPROPERTY(BlueprintReadWrite, EditAnywhere, SaveGame, Category = "World", meta = (ToolTip = "Temperature Decrease With Altitude, degrees per meter")) float TemperatureLapseRate = 0.00649f;
UPROPERTY(BlueprintReadWrite, EditAnywhere, SaveGame, Category = "World", meta = (ToolTip = "Altitude at which temperature stops decreasing, in meters")) float TropopauseAltitude = 11000.0f;
UPROPERTY(BlueprintReadWrite, EditAnywhere, SaveGame, Category = "World", meta = (ToolTip = "Specific Gas Constant, dry air = 287.058", ClampMin = "0")) float SpecificGasConstant = 287.058;
UPROPERTY(BlueprintReadWrite, EditAnywhere, SaveGame, Category = "World", meta = (ToolTip = "World Origin Location")) FVector WorldCenterLocation = FVector(0, 0, 0);
UPROPERTY(BlueprintReadWrite, EditAnywhere, SaveGame, Category = "World", meta = (ToolTip = "Use spherical planet model to get altitude")) bool SphericalAltitude = false;
UPROPERTY(BlueprintReadWrite, EditAnywhere, SaveGame, Category = "World", meta = (ToolTip = "Planet radius, in Unreal units", EditCondition = "SphericalAltitude", ClampMin = "0")) float SeaLevelRadius = 637100000.0f;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "World") bool OverrideGravity = false;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "World") FVector Gravity = FVector(0,0,-980);
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Safe launch") bool SafeLaunch = true;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Safe launch", Meta = (EditCondition = "SafeLaunch")) bool SafeLaunchIgnoreAttachParent = true;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Safe launch", Meta = (EditCondition = "SafeLaunchIgnoreAttachParent")) bool SafeLaunchIgnoreAllAttached = true;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Safe launch", Meta = (EditCondition = "SafeLaunch", ClampMin = "0")) float SafeDelay = 1.0;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Safe launch", Meta = (EditCondition = "SafeLaunch")) TArray<AActor*> SafeLaunchIgnoredActors;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Shotgun") bool Shotgun=false;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Shotgun", meta = (EditCondition = "Shotgun")) int ShotCount=10;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Shotgun", meta = (EditCondition = "Shotgun")) float ShotSpread=0.01;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Shotgun", meta = (EditCondition = "Shotgun")) float ShotVelocitySpread = 0.01;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Flight", meta = (ToolTip = "Minimum muzzle velocity in cm/s (Unreal units)")) float MuzzleVelocityMin = 91440.0; // ~3000 fps in cm/s
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Flight", meta = (ToolTip = "Maximum muzzle velocity in cm/s (Unreal units)")) float MuzzleVelocityMax = 91440.0; // ~3000 fps in cm/s
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Flight", meta = (ToolTip = "Maximum bullet spread, in radians", ClampMin = "0")) float Spread = 0.0f;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Flight", meta = (ToolTip = "Spread bias, higher is more accurate on average", ClampMin = "0")) float SpreadBias = 0.0f;
// Physics Mode Toggle
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Physics Mode", meta = (ToolTip = "Toggle between artistic (manual) and mathematical (realistic) physics calculations"))
bool UseMathematicalPhysics = false;
// Mathematical Properties (used when UseMathematicalPhysics is true)
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Mathematical Properties", meta = (EditCondition = "UseMathematicalPhysics", ToolTip = "Bullet properties asset for mathematical calculations"))
UEBBulletPropertiesAsset* BulletPropertiesAsset;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Mathematical Properties", meta = (EditCondition = "UseMathematicalPhysics", ToolTip = "Material properties asset for mathematical calculations"))
UEBMaterialPropertiesAsset* MaterialPropertiesAsset;
// Artistic Properties (used when UseMathematicalPhysics is false)
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Artistic Properties", meta = (EditCondition = "!UseMathematicalPhysics", ToolTip = "Bullet mass in kg"))
float Mass = 0.005;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Artistic Properties", meta = (EditCondition = "!UseMathematicalPhysics", ToolTip = "Bullet diameter in cm"))
float Diameter = 0.556;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Artistic Properties", meta = (EditCondition = "!UseMathematicalPhysics", ToolTip = "Form factor for drag calculations"))
float FormFactor = 1.0;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Artistic Properties", meta = (EditCondition = "!UseMathematicalPhysics", ToolTip = "Drag curve vs Mach number"))
UCurveFloat* MachDragCurve;
// Artistic Impact Properties (used when UseMathematicalPhysics is false)
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Artistic Impact", meta = (EditCondition = "!UseMathematicalPhysics"))
float GrazingAngleExponent = 2.0;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Artistic Impact", meta = (EditCondition = "!UseMathematicalPhysics"))
float MinPenetration = 10.0;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Artistic Impact", meta = (EditCondition = "!UseMathematicalPhysics"))
float MaxPenetration = 20.0;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Artistic Impact", meta = (EditCondition = "!UseMathematicalPhysics"))
float PenetrationNormalization = 0.5;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Artistic Impact", meta = (EditCondition = "!UseMathematicalPhysics"))
float PenetrationNormalizationGrazing = 0.0;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Artistic Impact", meta = (EditCondition = "!UseMathematicalPhysics"))
float PenetrationEntryAngleSpread = 0.1;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Artistic Impact", meta = (EditCondition = "!UseMathematicalPhysics"))
float PenetrationExitAngleSpread = 0.1;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Artistic Impact", meta = (EditCondition = "!UseMathematicalPhysics"))
float RicochetProbability = 0.1;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Artistic Impact", meta = (EditCondition = "!UseMathematicalPhysics"))
float RicochetProbabilityGrazing = 1;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Artistic Impact", meta = (EditCondition = "!UseMathematicalPhysics"))
float RicochetRestitution = 0.1;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Artistic Impact", meta = (EditCondition = "!UseMathematicalPhysics"))
float RicochetFriction = 0.0;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Artistic Impact", meta = (EditCondition = "!UseMathematicalPhysics"))
float RicochetSpread = 0.1;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Artistic Impact", meta = (EditCondition = "!UseMathematicalPhysics"))
bool SpeedControlsRicochetProbability = false;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Artistic Impact", meta = (EditCondition = "!UseMathematicalPhysics"))
bool AddImpulse = true;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Artistic Impact", meta = (EditCondition = "!UseMathematicalPhysics"))
float ImpulseMultiplier = 1.0;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Impact") EPenTraceType DefaultPenTraceType = EPenTraceType::PT_BackTrace;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Impact") UEBMaterialResponseMap* MaterialResponseMap;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Impact") bool MaterialDensityControlsPenetrationDepth = true;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Impact") bool MaterialRestitutionControlsRicochet = true;
// New Ballistic Impact System
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Impact")
UEBBallisticImpactComponent* BallisticImpactComponent;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Impact")
bool UseNewImpactSystem = false;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Impact", meta = (ToolTip = "Enable spalling fragment generation on impact"))
bool EnableSpalling = true;
/** Flag to indicate if this bullet has already generated spall, preventing repeated spalling. */
UPROPERTY(VisibleInstanceOnly, BlueprintReadOnly, Category = "Spalling")
bool bHasSpalled;
// Spalling properties (can be overridden by Material Response Map)
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Spalling")
TSubclassOf<AEBBullet> SpallFragmentClass;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Impact", meta = (ToolTip = "Indicates if this bullet is a spalling fragment"))
bool IsSpallFragment = false;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Replication") bool ReliableReplication = false;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Collision", meta = (ToolTip = "Allow components to collide, intended for use with trigger volumes. Do not use for actual collisions.")) bool AllowComponentCollisions = false;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Collision") TEnumAsByte<ECollisionChannel> TraceChannel;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Collision") bool TraceComplex;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Collision", meta = (ToolTip = "Margin to prevent surface clipping (cm). Lower values improve accuracy but may cause clipping.", ClampMin = "0.01", ClampMax = "5.0")) float CollisionMargin = 0.1;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Collision", meta = (ToolTip = "Bullets with lower velocity will automatically despawn on impact, never despawn if set to zero or negative")) float DespawnVelocity=100.0f;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Collision") TArray<AActor*> IgnoredActors;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Simulation", meta = (ToolTip = "Spawned bullet performs first trace immediately, instead of waiting for next simulation step")) bool DoFirstStepImmediately = true;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Simulation", meta = (EditCondition = "DoFirstStepImmediately")) bool RandomFirstStepDelta = true;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Simulation") bool FixedStep = false;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Simulation", meta = (EditCondition = "FixedStep", ClampMin = "0")) float FixedStepSeconds = 0.1;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Simulation", meta = (ToolTip = "Maximum number of surfaces to process per frame. Higher values allow penetrating more walls but may impact performance.", ClampMin = "1", ClampMax = "20")) int MaxTracesPerStep = 12;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Retrace") bool Retrace = true;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Retrace") bool RetraceOnAnotherChannel = false;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Retrace", meta=(EditCondition="RetraceOnAnotherChannel")) TEnumAsByte<ECollisionChannel> RetraceChannel;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Rotation") bool RotateActor = true;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Rotation") bool RotateRandomRoll = true;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Pooling") bool EnablePooling = false;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Pooling", meta = (EditCondition = "EnablePooling")) int MaxPoolSize = 50;
//rebase
virtual void ApplyWorldOffset(const FVector& InOffset, bool bWorldShift) override;
// Called when the game starts or when spawned
virtual void BeginPlay() override;
// Called every frame
virtual void Tick(float DeltaSeconds) override;
virtual void LifeSpanExpired() override;
UFUNCTION(BlueprintCallable, Category = "EBBullet|Spawn")
static void SpawnWithExactVelocity(TSubclassOf<class AEBBullet> BulletClass, AActor* BulletOwner, APawn* BulletInstigator, FVector BulletLocation, FVector BulletVelocity);
UFUNCTION(BlueprintCallable, Category = "EBBullet|Spawn")
static void SpawnWithExactVelocityFromBarrel(TSubclassOf<class AEBBullet> BulletClass, AActor* BulletOwner, APawn* BulletInstigator, FVector BulletLocation, FVector BulletVelocity, class UEBBarrel* SourceBarrel);
UFUNCTION(BlueprintCallable, Category = "EBBullet|Spawn")
static void Spawn(TSubclassOf<class AEBBullet> BulletClass, AActor* BulletOwner, APawn* BulletInstigator, FVector BulletLocation, FVector BulletVelocity);
UFUNCTION(NetMulticast, Unreliable)
void VelocityChangeBroadcast(FVector_NetQuantize NewLocation, FVector NewVelocity);
UFUNCTION(NetMulticast, Reliable)
void VelocityChangeBroadcastReliable(FVector_NetQuantize NewLocation, FVector NewVelocity);
UFUNCTION(BlueprintAuthorityOnly, BlueprintNativeEvent, Category = "EBBullet|Impact")
void OnImpact(bool Ricochet, bool PassedThrough, FVector Location, FVector IncomingVelocity, FVector Normal, FVector ExitLocation, FVector ExitVelocity, FVector Impulse, float PenetrationDepth, AActor* Actor, USceneComponent* Component, FName BoneName, UPhysicalMaterial* PhysMaterial, FHitResult HitResult);
UFUNCTION(BlueprintCosmetic, BlueprintNativeEvent, Category = "EBBullet|Impact")
void OnNetPredictedImpact(bool Ricochet, bool PassedThrough, FVector Location, FVector IncomingVelocity, FVector Normal, FVector ExitLocation, FVector ExitVelocity, FVector Impulse, float PenetrationDepth, AActor* Actor, USceneComponent* Component, FName BoneName, UPhysicalMaterial* PhysMaterial, FHitResult HitResult);
UFUNCTION(BlueprintImplementableEvent, Category = "EBBullet|Impact")
void OnTrace(FVector StartLocation, FVector EndLocation);
UFUNCTION(BlueprintImplementableEvent, Category = "EBBullet|Remote")
void OnTrajectoryUpdateReceived(FVector Location, FVector OldVelocity, FVector NewVelocity);
UFUNCTION(BlueprintNativeEvent, Category = "EBBullet|Activation")
void OnDeactivated();
UFUNCTION(BlueprintNativeEvent, Category = "EBBullet|Flight")FVector UpdateVelocity(UWorld* World, FVector Location, FVector PreviousVelocity, float DeltaTime) const;
UFUNCTION(BlueprintNativeEvent, Category = "EBBullet|World") FVector GetWind(UWorld* World, FVector Location) const;
UFUNCTION(BlueprintNativeEvent, Category = "EBBullet|World") float GetAirDensity(UWorld* World, FVector Location) const;
UFUNCTION(BlueprintNativeEvent, Category = "EBBullet|World") float GetSpeedOfSound(UWorld* World, FVector Location) const;
UFUNCTION(BlueprintNativeEvent, Category = "EBBullet|World") bool CollisionFilter(FHitResult HitResult) const;
// Mathematical Physics Functions
UFUNCTION(BlueprintCallable, Category = "EBBullet|Mathematical Physics")
float GetEffectiveMass() const;
UFUNCTION(BlueprintCallable, Category = "EBBullet|Mathematical Physics")
float GetEffectiveDiameter() const;
UFUNCTION(BlueprintCallable, Category = "EBBullet|Mathematical Physics")
float GetEffectiveDragCoefficient(float MachNumber) const;
UFUNCTION(BlueprintCallable, Category = "EBBullet|Mathematical Physics")
float CalculateMathematicalPenetration(UPhysicalMaterial* Material, float VelocityMPS, float ImpactAngle) const;
UFUNCTION(BlueprintCallable, Category = "EBBullet|Mathematical Physics")
float CalculateMathematicalRicochetProbability(UPhysicalMaterial* Material, float VelocityMPS, float ImpactAngle) const;
UFUNCTION(BlueprintCallable, Category = "EBBullet|Mathematical Physics")
FMathematicalMaterialProperties GetMaterialProperties(UPhysicalMaterial* Material) const;
// Enhanced Debug Functions
UFUNCTION(BlueprintCallable, Category = "EBBullet|Debug")
void CreateDebugImpactWidget(FVector Location, bool bRicochet, bool bPenetration, FVector ImpactVelocity, float PenetrationDepth, UPhysicalMaterial* Material);
UFUNCTION(BlueprintCallable, Category = "EBBullet|Debug")
void DrawTrajectoryDebug(FVector StartLocation, FVector EndLocation, FVector CurrentVelocity, float DeltaTime);
UFUNCTION(BlueprintCallable, Category = "EBBullet|Debug")
void DrawXRayTrajectory(FVector EntryPoint, FVector ExitPoint, FVector PenetrationDirection, float PenetrationDepth, UPhysicalMaterial* Material);
UFUNCTION(BlueprintCallable, Category = "EBBullet|Debug")
void DrawImpactDebug(FVector ImpactLocation, FVector ImpactVelocity, FVector ImpactNormal, bool bRicochet, bool bPenetration, float PenetrationDepth, UPhysicalMaterial* Material);
UFUNCTION(BlueprintCallable, Category = "EBBullet|Debug")
void DrawPhysicsDebug(FVector Location, FVector DragForce, FVector GravityForce, FVector WindForce, float AirDensity, float SpeedOfSound);
UFUNCTION(BlueprintCallable, Category = "EBBullet|Debug")
void DrawBallisticsDebug(FVector Location, FVector BulletVelocity, float KineticEnergy, float DragCoefficient, float MachNumber);
UFUNCTION(BlueprintCallable, Category = "EBBullet|Debug")
void DrawSpallDebug(FVector ImpactLocation, FVector ImpactVelocity, FVector ImpactNormal, TArray<FVector> FragmentVelocities);
UFUNCTION(BlueprintCallable, Category = "EBBullet|Debug")
void DrawPerformanceDebug(FVector Location, int32 TraceCount, float FrameTime, int32 PooledBullets);
UFUNCTION(BlueprintCallable, Category = "EBBullet|Debug")
void ClearDebugDisplay();
UFUNCTION(BlueprintCallable, Category = "EBBullet|Debug")
void ToggleDebugCategory(const FString& CategoryName, bool bEnabled);
UFUNCTION(BlueprintPure, Category = "EBBullet|Debug")
class UEBBarrel* GetFiringBarrel() const { return FiringBarrel; }
UFUNCTION(BlueprintPure, Category = "EBBullet|Debug")
FString GetDebugInfoString() const;
// Spalling Functions
UFUNCTION(BlueprintCallable, Category = "EBBullet|Spalling")
/**
* Generate spall fragments given impact parameters.
* @param ImpactLocation Location of impact in world space
* @param ImpactVelocity Incoming projectile velocity at impact (cm/s)
* @param ImpactNormal Surface normal at point of impact (unit vector)
* @param PlateThicknessCM Thickness of the target plate in centimetres (0 if unknown / no penetration)
* @param ImpactAngleDegrees Angle between velocity vector and surface normal in degrees (0 = perpendicular)
* @param Material Physical material hit
* @param HitActor Actor that was hit (for ignore lists etc.)
*/
void GenerateSpallFragments(FVector ImpactLocation, FVector ImpactVelocity, FVector ImpactNormal,
float PlateThicknessCM, float ImpactAngleDegrees,
UPhysicalMaterial* Material, AActor* HitActor);
UFUNCTION(BlueprintNativeEvent, Category = "EBBullet|Spalling")
void OnSpallFragmentGenerated(FVector FragmentLocation, FVector FragmentVelocity, float FragmentMass, UPhysicalMaterial* Material);
UFUNCTION(BlueprintCallable, Category = "EBBullet|Spalling")
bool ShouldGenerateSpalling(FVector ImpactVelocity, UPhysicalMaterial* Material) const;
UFUNCTION(BlueprintCallable, Category = "EBBullet|Spalling")
void ConfigureAsSpallFragment(float FragmentMass, float FragmentVelocity);
void SetFiringBarrel(class UEBBarrel* Barrel) { FiringBarrel = Barrel; }
//pooling
UFUNCTION(BlueprintAuthorityOnly, BlueprintCallable, Category = "EBBullet|Pooling")void Deactivate();
UFUNCTION(NetMulticast, Reliable)
void ReactivationBroadcast(FVector_NetQuantize NewLocation, FVector NewVelocity, AActor* BulletOwner, APawn* BulletInstigator);
UFUNCTION(NetMulticast, Reliable)
void DeactivationBroadcast();
private:
/**
* Returns a scaling factor (>1 increases spall likelihood/amount, <1 decreases) based on the bullet type.
*/
float GetSpallFactorByBulletType() const;
UPROPERTY() TArray<TWeakObjectPtr<AEBBullet>> Pooled;
static AEBBullet* GetFromPool(UWorld* World, UClass* BulletClass);
static AEBBullet* SpawnOrReactivate(UWorld* World, TSubclassOf<class AEBBullet> BulletClass, const FTransform& Transform, FVector BulletVelocity, AActor* BulletOwner, APawn* BulletInstigator);
static AEBBullet* SpawnOrReactivateFromBarrel(UWorld* World, TSubclassOf<class AEBBullet> BulletClass, const FTransform& Transform, FVector BulletVelocity, AActor* BulletOwner, APawn* BulletInstigator, class UEBBarrel* SourceBarrel);
void DeactivateToPool();
AEBBullet* FinishSpawning(FTransform Transform);
void Step(float DeltaTime);
float Trace(FVector start, FVector PreviousVelocity, float delta, TEnumAsByte<ECollisionChannel> channel);
TArray<AActor*> GetAttachedActorsRecursive(AActor* Actor, uint16 Depth = 0, TArray<AActor*> VisitedActors = TArray<AActor*>()) const;
float PenetrationTrace(FVector start, FVector end, TWeakObjectPtr<UPrimitiveComponent,FWeakObjectPtr> comp, EPenTraceType penType, TEnumAsByte<ECollisionChannel> channel, FVector &exitLoc, FVector &exitNormal);
// Helper function to process multiple hits in sequence (for close walls)
bool ProcessSequentialHits(TArray<FHitResult>& AllHits, FVector& CurrentVelocity, float DeltaTime, int32& ProcessedHitCount);
float GetCurveValue(const UCurveFloat* curve, float in, float deflt) const;
float AccumulatedDelta;
bool CanRetrace = false;
FVector LastTraceStart;
float LastTraceDelta;
FVector LastTraceVelocity;
FVector LastTracePrevVelocity;
bool IsRecycled;
FHitResult FilterHits(TArray<FHitResult> Results, bool &hit) const;
TArray<AActor*>GetSafeLaunchIgnoredActors(AActor* Owner) const;
class UEBBarrel* FiringBarrel;
// Debug tracking variables
TArray<FVector> DebugTrajectoryPoints;
TArray<float> DebugTrajectoryTimes;
TArray<FVector> DebugImpactLocations;
TArray<float> DebugImpactTimes;
int32 DebugTraceCounter;
float DebugFrameStartTime;
static int32 DebugMessageCounter;
float GetAltitude(UWorld* World, FVector Location) const;
float GetAltitudePressure(float AltitudeMeter) const;
float GetAltitudeTemperature(float AltitudeMeter) const;
float GetAltitudeDensity(float AltitudeMeter) const;
#ifdef WITH_EDITOR
FLinearColor GetDebugColor(float In) const{
return FMath::Lerp(DebugTrailColorSlow, DebugTrailColorFast, In);
}
#endif
};