247 lines
6.2 KiB
C++
247 lines
6.2 KiB
C++
// Copyright 2018 Mookie. All Rights Reserved.
|
|
#include "EBBullet.h"
|
|
|
|
// Sets default values
|
|
AEBBullet::AEBBullet() {
|
|
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
|
|
PrimaryActorTick.bCanEverTick = true;
|
|
SetTickGroup(ETickingGroup::TG_PrePhysics);
|
|
|
|
// Create the new ballistic impact component
|
|
BallisticImpactComponent = CreateDefaultSubobject<UEBBallisticImpactComponent>(TEXT("BallisticImpactComponent"));
|
|
BallisticImpactComponent->MaterialResponseMap = MaterialResponseMap;
|
|
}
|
|
|
|
// Called when the game starts or when spawned
|
|
void AEBBullet::BeginPlay() {
|
|
SetActorEnableCollision(AllowComponentCollisions);
|
|
|
|
// Update ballistic impact component with current settings
|
|
if (BallisticImpactComponent) {
|
|
BallisticImpactComponent->MaterialResponseMap = MaterialResponseMap;
|
|
BallisticImpactComponent->bUseMathematicalPenetration = UseMathematicalPhysics;
|
|
BallisticImpactComponent->bEnableBallisticCalculations = UseNewImpactSystem;
|
|
}
|
|
|
|
if(!IsRecycled){
|
|
Super::BeginPlay();
|
|
IsRecycled = true;
|
|
}
|
|
else{
|
|
ReceiveBeginPlay();
|
|
}
|
|
|
|
if (SafeLaunch) {
|
|
OwnerSafe = true;
|
|
}
|
|
|
|
if (DoFirstStepImmediately) {
|
|
float DeltaTime = GetWorld()->GetDeltaSeconds();
|
|
|
|
if (RandomFirstStepDelta) {
|
|
DeltaTime *= RandomStream.FRand();
|
|
};
|
|
|
|
if (FixedStep) {
|
|
Step(FixedStepSeconds);
|
|
}
|
|
else {
|
|
Step(DeltaTime);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Called every frame
|
|
void AEBBullet::Tick(float DeltaTime) {
|
|
Super::Tick(DeltaTime);
|
|
|
|
if (FixedStep) {
|
|
AccumulatedDelta += DeltaTime;
|
|
|
|
while (AccumulatedDelta >= FixedStepSeconds) {
|
|
Step(FixedStepSeconds);
|
|
AccumulatedDelta -= FixedStepSeconds;
|
|
}
|
|
|
|
}
|
|
else {
|
|
Step(DeltaTime);
|
|
}
|
|
}
|
|
|
|
void AEBBullet::Step(float DeltaTime) {
|
|
FVector start = GetActorLocation();
|
|
bool sendUpdate = false;
|
|
|
|
if (Retrace && CanRetrace) {
|
|
//time travel
|
|
float remainingTime = LastTraceDelta;
|
|
int remainingSteps = MaxTracesPerStep;
|
|
FVector PreviousVelocity = LastTracePrevVelocity;
|
|
SetActorLocation(LastTraceStart);
|
|
Velocity = LastTraceVelocity;
|
|
|
|
do {
|
|
if (RetraceOnAnotherChannel) {
|
|
remainingTime = Trace(GetActorLocation(),
|
|
PreviousVelocity,
|
|
remainingTime,
|
|
RetraceChannel);
|
|
}
|
|
else {
|
|
remainingTime = Trace(GetActorLocation(),
|
|
PreviousVelocity,
|
|
remainingTime,
|
|
TraceChannel);
|
|
}
|
|
PreviousVelocity = Velocity;
|
|
remainingSteps -= 1;
|
|
if (remainingTime > 0.0f) { sendUpdate = true; };
|
|
} while (remainingTime > 0.0f && remainingSteps > 0);
|
|
}
|
|
CanRetrace = false;
|
|
|
|
FVector PreviousVelocity = Velocity;
|
|
Velocity = UpdateVelocity(GetWorld(), GetActorLocation(), Velocity, DeltaTime);
|
|
|
|
//trace
|
|
float remainingTime = DeltaTime;
|
|
int remainingSteps = MaxTracesPerStep;
|
|
do {
|
|
remainingTime = Trace(GetActorLocation(),
|
|
PreviousVelocity,
|
|
remainingTime,
|
|
TraceChannel
|
|
);
|
|
PreviousVelocity = Velocity;
|
|
remainingSteps -= 1;
|
|
if (remainingTime > 0.0f) { sendUpdate = true; };
|
|
} while (remainingTime > 0.0f && remainingSteps > 0);
|
|
|
|
if (sendUpdate) {
|
|
if (ReliableReplication) {
|
|
VelocityChangeBroadcastReliable(UGameplayStatics::RebaseLocalOriginOntoZero(GetWorld(),GetActorLocation()), Velocity);
|
|
}
|
|
else {
|
|
VelocityChangeBroadcast(UGameplayStatics::RebaseLocalOriginOntoZero(GetWorld(), GetActorLocation()), Velocity);
|
|
}
|
|
}
|
|
|
|
if(SafeDelay <= 0.0f){
|
|
OwnerSafe = false;
|
|
}
|
|
else {
|
|
SafeDelay -= DeltaTime;
|
|
}
|
|
|
|
if (RotateActor) {
|
|
FRotator NewRot = UKismetMathLibrary::MakeRotFromX(Velocity);
|
|
NewRot.Roll = GetActorRotation().Roll;
|
|
SetActorRotation(NewRot);
|
|
}
|
|
}
|
|
|
|
float AEBBullet::GetCurveValue(const UCurveFloat* curve, float in, float deflt) const {
|
|
if (curve == nullptr) return deflt;
|
|
return curve->GetFloatValue(in);
|
|
}
|
|
|
|
void AEBBullet::ApplyWorldOffset(const FVector& InOffset, bool bWorldShift) {
|
|
Super::ApplyWorldOffset(InOffset, bWorldShift);
|
|
LastTraceStart += InOffset;
|
|
}
|
|
|
|
// Mathematical Physics Function Implementations
|
|
float AEBBullet::GetEffectiveMass() const
|
|
{
|
|
if (UseMathematicalPhysics && BulletPropertiesAsset)
|
|
{
|
|
return BulletPropertiesAsset->BulletProperties.GetMassKg();
|
|
}
|
|
return Mass;
|
|
}
|
|
|
|
float AEBBullet::GetEffectiveDiameter() const
|
|
{
|
|
if (UseMathematicalPhysics && BulletPropertiesAsset)
|
|
{
|
|
return BulletPropertiesAsset->BulletProperties.GetDiameterCm();
|
|
}
|
|
return Diameter;
|
|
}
|
|
|
|
float AEBBullet::GetEffectiveDragCoefficient(float MachNumber) const
|
|
{
|
|
if (UseMathematicalPhysics && BulletPropertiesAsset)
|
|
{
|
|
return UEBMathematicalBallistics::CalculateDragCoefficient(
|
|
BulletPropertiesAsset->BulletProperties, MachNumber);
|
|
}
|
|
|
|
// Use artistic drag calculation
|
|
float DragCoeff = GetCurveValue(MachDragCurve, MachNumber, 0.5f);
|
|
return DragCoeff * FormFactor;
|
|
}
|
|
|
|
float AEBBullet::CalculateMathematicalPenetration(UPhysicalMaterial* Material, float VelocityMPS, float ImpactAngle) const
|
|
{
|
|
if (!UseMathematicalPhysics || !BulletPropertiesAsset)
|
|
{
|
|
return 0.0f;
|
|
}
|
|
|
|
FMathematicalMaterialProperties MaterialProps = GetMaterialProperties(Material);
|
|
|
|
return UEBMathematicalBallistics::CalculatePenetrationDepth(
|
|
BulletPropertiesAsset->BulletProperties,
|
|
MaterialProps,
|
|
VelocityMPS,
|
|
ImpactAngle
|
|
);
|
|
}
|
|
|
|
float AEBBullet::CalculateMathematicalRicochetProbability(UPhysicalMaterial* Material, float VelocityMPS, float ImpactAngle) const
|
|
{
|
|
if (!UseMathematicalPhysics || !BulletPropertiesAsset)
|
|
{
|
|
return 0.0f;
|
|
}
|
|
|
|
FMathematicalMaterialProperties MaterialProps = GetMaterialProperties(Material);
|
|
|
|
return UEBMathematicalBallistics::CalculateRicochetProbability(
|
|
BulletPropertiesAsset->BulletProperties,
|
|
MaterialProps,
|
|
VelocityMPS,
|
|
ImpactAngle
|
|
);
|
|
}
|
|
|
|
FMathematicalMaterialProperties AEBBullet::GetMaterialProperties(UPhysicalMaterial* Material) const
|
|
{
|
|
// Default properties for unknown materials
|
|
FMathematicalMaterialProperties DefaultProps;
|
|
|
|
if (!Material || !MaterialResponseMap)
|
|
{
|
|
return DefaultProps;
|
|
}
|
|
|
|
// Check if we have custom properties for this material
|
|
if (MaterialResponseMap->Map.Contains(Material))
|
|
{
|
|
const FEBMaterialResponseMapEntry& Entry = MaterialResponseMap->Map[Material];
|
|
if (Entry.UseMathematicalProperties)
|
|
{
|
|
return Entry.MathematicalProperties;
|
|
}
|
|
}
|
|
|
|
// If we have a material properties asset, use that as fallback
|
|
if (MaterialPropertiesAsset)
|
|
{
|
|
return MaterialPropertiesAsset->MaterialProperties;
|
|
}
|
|
|
|
return DefaultProps;
|
|
} |