Implement flanking mechanics and slightly increase enemy speed
This commit is contained in:
@@ -34,6 +34,10 @@ AEnemySpaceship::AEnemySpaceship()
|
||||
EnemyMesh->SetCollisionResponseToChannel(ECC_Pawn, ECR_Ignore); // Ignore other pawns
|
||||
EnemyMesh->SetCollisionResponseToChannel(ECC_GameTraceChannel1, ECR_Block); // Block player (for damage)
|
||||
EnemyMesh->SetGenerateOverlapEvents(true);
|
||||
|
||||
CurrentVelocity = FVector::ZeroVector;
|
||||
TargetVelocity = FVector::ZeroVector;
|
||||
LastPosition = FVector::ZeroVector;
|
||||
}
|
||||
|
||||
void AEnemySpaceship::BeginPlay()
|
||||
@@ -52,20 +56,24 @@ void AEnemySpaceship::BeginPlay()
|
||||
|
||||
// Randomize initial strafe direction
|
||||
StrafeDirection = FMath::RandBool() ? 1.0f : -1.0f;
|
||||
|
||||
LastPosition = GetActorLocation();
|
||||
|
||||
bInitializedFlank = false;
|
||||
LastFlankUpdateTime = 0.0f;
|
||||
CurrentFlankTarget = GetActorLocation();
|
||||
}
|
||||
|
||||
// Modify Tick function to include flanking behavior
|
||||
void AEnemySpaceship::Tick(float DeltaTime)
|
||||
{
|
||||
Super::Tick(DeltaTime);
|
||||
|
||||
if (!PlayerPawn)
|
||||
{
|
||||
// Try to find player again if not set
|
||||
AActor* FoundPlayerPawn = UGameplayStatics::GetPlayerPawn(GetWorld(), 0);
|
||||
PlayerPawn = Cast<ASpaceshipPawn>(FoundPlayerPawn);
|
||||
|
||||
if (!PlayerPawn)
|
||||
return;
|
||||
if (!PlayerPawn) return;
|
||||
}
|
||||
|
||||
// Calculate distance to player
|
||||
@@ -89,6 +97,9 @@ void AEnemySpaceship::Tick(float DeltaTime)
|
||||
case EEnemyBehaviorState::Strafe:
|
||||
PerformStrafe(DeltaTime);
|
||||
break;
|
||||
case EEnemyBehaviorState::Flank:
|
||||
PerformFlank(DeltaTime);
|
||||
break;
|
||||
}
|
||||
|
||||
// Debug state information
|
||||
@@ -101,6 +112,7 @@ void AEnemySpaceship::Tick(float DeltaTime)
|
||||
case EEnemyBehaviorState::Attack: StateString = "Attack"; break;
|
||||
case EEnemyBehaviorState::Retreat: StateString = "Retreat"; break;
|
||||
case EEnemyBehaviorState::Strafe: StateString = "Strafe"; break;
|
||||
case EEnemyBehaviorState::Flank: StateString = "Flank"; break;
|
||||
}
|
||||
|
||||
GEngine->AddOnScreenDebugMessage(-1, 0.0f, FColor::Orange,
|
||||
@@ -108,30 +120,213 @@ void AEnemySpaceship::Tick(float DeltaTime)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void AEnemySpaceship::SmoothMove(const FVector& TargetLocation, float DeltaTime)
|
||||
{
|
||||
FVector CurrentLocation = GetActorLocation();
|
||||
FVector DirectionToTarget = (TargetLocation - CurrentLocation);
|
||||
float DistanceToTarget = DirectionToTarget.Size();
|
||||
|
||||
// Calculate target velocity
|
||||
FVector NewTargetVelocity = DirectionToTarget;
|
||||
if (DistanceToTarget > 1.0f)
|
||||
{
|
||||
NewTargetVelocity = DirectionToTarget.GetSafeNormal() * FMath::Min(MovementSpeed, DistanceToTarget / DeltaTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
NewTargetVelocity = FVector::ZeroVector;
|
||||
}
|
||||
|
||||
// Smoothly interpolate current velocity towards target velocity
|
||||
CurrentVelocity = FMath::VInterpTo(CurrentVelocity, NewTargetVelocity, DeltaTime, InterpSpeed);
|
||||
|
||||
// Clamp acceleration
|
||||
FVector Acceleration = (CurrentVelocity - (CurrentLocation - LastPosition) / DeltaTime);
|
||||
if (Acceleration.SizeSquared() > MaxAcceleration * MaxAcceleration)
|
||||
{
|
||||
Acceleration = Acceleration.GetSafeNormal() * MaxAcceleration;
|
||||
CurrentVelocity = ((CurrentLocation - LastPosition) / DeltaTime) + (Acceleration * DeltaTime);
|
||||
}
|
||||
|
||||
// Update position
|
||||
LastPosition = CurrentLocation;
|
||||
FVector NewLocation = CurrentLocation + (CurrentVelocity * DeltaTime);
|
||||
SetActorLocation(NewLocation);
|
||||
}
|
||||
|
||||
void AEnemySpaceship::UpdateBehaviorState()
|
||||
{
|
||||
// Override random behavior changes when distance requires specific behavior
|
||||
if (!PlayerPawn) return;
|
||||
|
||||
FVector DesiredPosition = CalculatePositionAwayFromOtherEnemies();
|
||||
FVector PlayerVelocity = PlayerPawn->GetVelocity();
|
||||
float PlayerSpeed = PlayerVelocity.Size();
|
||||
|
||||
float AggressionRoll = FMath::FRand();
|
||||
|
||||
if (DistanceToPlayer < MinDistanceToPlayer)
|
||||
{
|
||||
// Too close, retreat or strafe
|
||||
CurrentBehaviorState = FMath::RandBool() ? EEnemyBehaviorState::Retreat : EEnemyBehaviorState::Strafe;
|
||||
if (AggressionRoll < AggressionFactor * 0.3f)
|
||||
{
|
||||
CurrentBehaviorState = EEnemyBehaviorState::Attack;
|
||||
}
|
||||
else
|
||||
{
|
||||
CurrentBehaviorState = EEnemyBehaviorState::Retreat;
|
||||
}
|
||||
}
|
||||
else if (DistanceToPlayer < AttackRange)
|
||||
{
|
||||
// Within attack range but not too close, either attack or strafe
|
||||
if (CurrentBehaviorState != EEnemyBehaviorState::Attack &&
|
||||
CurrentBehaviorState != EEnemyBehaviorState::Strafe)
|
||||
// Increased chance of flanking
|
||||
if (AggressionRoll < AggressionFactor * FlankingFrequency)
|
||||
{
|
||||
CurrentBehaviorState = FMath::RandBool() ? EEnemyBehaviorState::Attack : EEnemyBehaviorState::Strafe;
|
||||
// Only change to flank state if we're not already flanking
|
||||
// This prevents unnecessary state changes that could cause position jumps
|
||||
if (CurrentBehaviorState != EEnemyBehaviorState::Flank)
|
||||
{
|
||||
CurrentBehaviorState = EEnemyBehaviorState::Flank;
|
||||
bIsFlankingRight = FMath::RandBool();
|
||||
bInitializedFlank = false; // Will trigger new flank position calculation
|
||||
LastFlankUpdateTime = GetWorld()->GetTimeSeconds();
|
||||
}
|
||||
}
|
||||
else if (AggressionRoll < AggressionFactor * 0.8f) // Increased from 0.7f
|
||||
{
|
||||
CurrentBehaviorState = EEnemyBehaviorState::Attack;
|
||||
}
|
||||
else
|
||||
{
|
||||
CurrentBehaviorState = EEnemyBehaviorState::Strafe;
|
||||
StrafeDirection = FMath::RandBool() ? 1.0f : -1.0f;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Too far, chase
|
||||
CurrentBehaviorState = EEnemyBehaviorState::Chase;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Add this new function to handle enemy spacing
|
||||
FVector AEnemySpaceship::CalculatePositionAwayFromOtherEnemies()
|
||||
{
|
||||
FVector AveragePosition = GetActorLocation();
|
||||
int32 EnemyCount = 0;
|
||||
|
||||
// Find all enemy spaceships
|
||||
TArray<AActor*> FoundEnemies;
|
||||
UGameplayStatics::GetAllActorsOfClass(GetWorld(), AEnemySpaceship::StaticClass(), FoundEnemies);
|
||||
|
||||
for (AActor* Enemy : FoundEnemies)
|
||||
{
|
||||
if (Enemy != this)
|
||||
{
|
||||
float Distance = FVector::Dist(GetActorLocation(), Enemy->GetActorLocation());
|
||||
if (Distance < MinDistanceToOtherEnemies)
|
||||
{
|
||||
AveragePosition += Enemy->GetActorLocation();
|
||||
EnemyCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (EnemyCount > 0)
|
||||
{
|
||||
AveragePosition /= (EnemyCount + 1);
|
||||
// Calculate position away from the cluster
|
||||
FVector AwayFromCrowd = GetActorLocation() - AveragePosition;
|
||||
AwayFromCrowd.Normalize();
|
||||
return GetActorLocation() + (AwayFromCrowd * MinDistanceToOtherEnemies);
|
||||
}
|
||||
|
||||
return GetActorLocation();
|
||||
}
|
||||
|
||||
FVector AEnemySpaceship::CalculateFlankPosition()
|
||||
{
|
||||
if (!PlayerPawn) return GetActorLocation();
|
||||
|
||||
// Get player's forward vector and velocity
|
||||
FVector PlayerForward = PlayerPawn->GetActorForwardVector();
|
||||
FVector PlayerVelocity = PlayerPawn->GetVelocity();
|
||||
|
||||
// Use player's velocity direction if they're moving, otherwise use their forward vector
|
||||
FVector BaseDirection = PlayerVelocity.SizeSquared() > 100.0f ?
|
||||
PlayerVelocity.GetSafeNormal() : PlayerForward;
|
||||
|
||||
// Calculate the flanking angle
|
||||
float AngleRadians = FMath::DegreesToRadians(FlankAngle * (bIsFlankingRight ? 1.0f : -1.0f));
|
||||
|
||||
// Rotate the vector for flanking
|
||||
FVector FlankDirection = BaseDirection.RotateAngleAxis(AngleRadians, FVector::UpVector);
|
||||
|
||||
// Calculate the final position with some variation in distance
|
||||
float VariedDistance = FlankDistance * FMath::RandRange(0.8f, 1.2f);
|
||||
return PlayerPawn->GetActorLocation() + (FlankDirection * VariedDistance);
|
||||
}
|
||||
|
||||
void AEnemySpaceship::PerformFlank(float DeltaTime)
|
||||
{
|
||||
if (!PlayerPawn) return;
|
||||
|
||||
float CurrentTime = GetWorld()->GetTimeSeconds();
|
||||
|
||||
// Initialize flank position if needed
|
||||
if (!bInitializedFlank)
|
||||
{
|
||||
CurrentFlankTarget = CalculateFlankPosition();
|
||||
bInitializedFlank = true;
|
||||
LastFlankUpdateTime = CurrentTime;
|
||||
}
|
||||
|
||||
// Update flank position periodically
|
||||
if (CurrentTime - LastFlankUpdateTime >= FlankPositionUpdateInterval)
|
||||
{
|
||||
// Smoothly transition to new flank position
|
||||
FVector NewFlankPosition = CalculateFlankPosition();
|
||||
CurrentFlankTarget = FMath::VInterpTo(
|
||||
CurrentFlankTarget,
|
||||
NewFlankPosition,
|
||||
DeltaTime,
|
||||
2.0f // Interpolation speed
|
||||
);
|
||||
|
||||
LastFlankUpdateTime = CurrentTime;
|
||||
|
||||
// Occasionally switch flanking direction
|
||||
if (FMath::FRand() < 0.3f) // 30% chance to switch direction
|
||||
{
|
||||
bIsFlankingRight = !bIsFlankingRight;
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate distance to current flank target
|
||||
float DistanceToFlankTarget = FVector::Dist(GetActorLocation(), CurrentFlankTarget);
|
||||
|
||||
// Calculate movement speed based on distance
|
||||
float CurrentFlankSpeed = FMath::Min(FlankingSpeed, DistanceToFlankTarget * 2.0f);
|
||||
|
||||
// Move towards flank position
|
||||
FVector DirectionToFlank = (CurrentFlankTarget - GetActorLocation()).GetSafeNormal();
|
||||
FVector TargetPosition = GetActorLocation() + DirectionToFlank * CurrentFlankSpeed * DeltaTime;
|
||||
|
||||
// Use smooth movement
|
||||
SmoothMove(TargetPosition, DeltaTime);
|
||||
|
||||
// Face the player while flanking
|
||||
FVector DirectionToPlayer = (PlayerPawn->GetActorLocation() - GetActorLocation()).GetSafeNormal();
|
||||
FRotator TargetRotation = DirectionToPlayer.Rotation();
|
||||
FRotator NewRotation = FMath::RInterpTo(GetActorRotation(), TargetRotation, DeltaTime, InterpSpeed);
|
||||
SetActorRotation(NewRotation);
|
||||
|
||||
// Fire more frequently while flanking
|
||||
if (bCanFire && DistanceToPlayer < AttackRange)
|
||||
{
|
||||
Fire();
|
||||
}
|
||||
}
|
||||
|
||||
void AEnemySpaceship::ChangeBehaviorState()
|
||||
{
|
||||
// Random chance to change behavior state
|
||||
@@ -154,18 +349,21 @@ void AEnemySpaceship::PerformChase(float DeltaTime)
|
||||
if (PlayerPawn)
|
||||
{
|
||||
// Calculate direction to player
|
||||
FVector Direction = (PlayerPawn->GetActorLocation() - GetActorLocation()).GetSafeNormal();
|
||||
FVector DirectionToPlayer = (PlayerPawn->GetActorLocation() - GetActorLocation()).GetSafeNormal();
|
||||
|
||||
// Move towards the player
|
||||
FVector NewLocation = GetActorLocation() + Direction * MovementSpeed * DeltaTime;
|
||||
SetActorLocation(NewLocation);
|
||||
// Calculate target position
|
||||
FVector TargetPosition = GetActorLocation() + DirectionToPlayer * MovementSpeed * DeltaTime;
|
||||
|
||||
// Face towards the player
|
||||
FRotator NewRotation = Direction.Rotation();
|
||||
// Use smooth movement
|
||||
SmoothMove(TargetPosition, DeltaTime);
|
||||
|
||||
// Smoothly rotate to face player
|
||||
FRotator TargetRotation = DirectionToPlayer.Rotation();
|
||||
FRotator NewRotation = FMath::RInterpTo(GetActorRotation(), TargetRotation, DeltaTime, InterpSpeed);
|
||||
SetActorRotation(NewRotation);
|
||||
|
||||
// If within attack range, fire occasionally
|
||||
if (DistanceToPlayer < AttackRange && bCanFire && FMath::FRand() < 0.3f)
|
||||
// Fire if within range
|
||||
if (DistanceToPlayer < AttackRange && bCanFire)
|
||||
{
|
||||
Fire();
|
||||
}
|
||||
@@ -193,24 +391,32 @@ void AEnemySpaceship::PerformRetreat(float DeltaTime)
|
||||
{
|
||||
if (PlayerPawn)
|
||||
{
|
||||
// Move away from player
|
||||
FVector Direction = (GetActorLocation() - PlayerPawn->GetActorLocation()).GetSafeNormal();
|
||||
FVector NewLocation = GetActorLocation() + Direction * MovementSpeed * DeltaTime;
|
||||
SetActorLocation(NewLocation);
|
||||
// Calculate ideal retreat position
|
||||
FVector DirectionFromPlayer = (GetActorLocation() - PlayerPawn->GetActorLocation()).GetSafeNormal();
|
||||
FVector DesiredPosition = PlayerPawn->GetActorLocation() + (DirectionFromPlayer * OptimalCombatDistance);
|
||||
|
||||
// Keep facing the player while backing up
|
||||
FVector FaceDirection = (PlayerPawn->GetActorLocation() - GetActorLocation()).GetSafeNormal();
|
||||
FRotator NewRotation = FaceDirection.Rotation();
|
||||
// Consider other enemies
|
||||
FVector AvoidCrowdingPosition = CalculatePositionAwayFromOtherEnemies();
|
||||
FVector FinalTargetPosition = FMath::Lerp(DesiredPosition, AvoidCrowdingPosition, 0.3f);
|
||||
|
||||
// Use smooth movement
|
||||
SmoothMove(FinalTargetPosition, DeltaTime);
|
||||
|
||||
// Smoothly rotate to face player
|
||||
FVector DirectionToPlayer = (PlayerPawn->GetActorLocation() - GetActorLocation()).GetSafeNormal();
|
||||
FRotator TargetRotation = DirectionToPlayer.Rotation();
|
||||
FRotator NewRotation = FMath::RInterpTo(GetActorRotation(), TargetRotation, DeltaTime, InterpSpeed);
|
||||
SetActorRotation(NewRotation);
|
||||
|
||||
// Fire while retreating
|
||||
if (bCanFire)
|
||||
// Fire while retreating if in range
|
||||
if (bCanFire && DistanceToPlayer < AttackRange)
|
||||
{
|
||||
Fire();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void AEnemySpaceship::PerformStrafe(float DeltaTime)
|
||||
{
|
||||
if (PlayerPawn)
|
||||
@@ -218,19 +424,44 @@ void AEnemySpaceship::PerformStrafe(float DeltaTime)
|
||||
// Calculate direction to player
|
||||
FVector DirectionToPlayer = (PlayerPawn->GetActorLocation() - GetActorLocation()).GetSafeNormal();
|
||||
|
||||
// Calculate strafe direction (perpendicular to direction to player)
|
||||
// Calculate ideal combat distance
|
||||
float CurrentDistance = DistanceToPlayer;
|
||||
float DistanceAdjustment = 0.0f;
|
||||
|
||||
if (CurrentDistance < OptimalCombatDistance)
|
||||
{
|
||||
DistanceAdjustment = -1.0f; // Move away
|
||||
}
|
||||
else if (CurrentDistance > OptimalCombatDistance + 200.0f)
|
||||
{
|
||||
DistanceAdjustment = 1.0f; // Move closer
|
||||
}
|
||||
|
||||
// Calculate strafe direction
|
||||
FVector StrafeVector = FVector::CrossProduct(DirectionToPlayer, FVector::UpVector) * StrafeDirection;
|
||||
|
||||
// Move sideways while maintaining distance
|
||||
FVector NewLocation = GetActorLocation() + StrafeVector * StrafeSpeed * DeltaTime;
|
||||
SetActorLocation(NewLocation);
|
||||
// Calculate target position
|
||||
FVector DistanceAdjustmentVector = DirectionToPlayer * DistanceAdjustment * MovementSpeed * 0.5f;
|
||||
FVector StrafeMovement = StrafeVector * StrafeSpeed;
|
||||
FVector DesiredMovement = (StrafeMovement + DistanceAdjustmentVector) * DeltaTime;
|
||||
|
||||
// Get position avoiding other enemies
|
||||
FVector CrowdAvoidancePosition = CalculatePositionAwayFromOtherEnemies();
|
||||
|
||||
// Blend between desired movement and crowd avoidance
|
||||
FVector TargetPosition = GetActorLocation() + DesiredMovement;
|
||||
FVector FinalTargetPosition = FMath::Lerp(TargetPosition, CrowdAvoidancePosition, 0.3f);
|
||||
|
||||
// Use smooth movement
|
||||
SmoothMove(FinalTargetPosition, DeltaTime);
|
||||
|
||||
// Face towards the player
|
||||
FRotator NewRotation = DirectionToPlayer.Rotation();
|
||||
FRotator TargetRotation = DirectionToPlayer.Rotation();
|
||||
FRotator NewRotation = FMath::RInterpTo(GetActorRotation(), TargetRotation, DeltaTime, InterpSpeed);
|
||||
SetActorRotation(NewRotation);
|
||||
|
||||
// Fire while strafing
|
||||
if (bCanFire)
|
||||
// Fire while strafing if in range
|
||||
if (bCanFire && DistanceToPlayer < AttackRange)
|
||||
{
|
||||
Fire();
|
||||
}
|
||||
@@ -239,12 +470,7 @@ void AEnemySpaceship::PerformStrafe(float DeltaTime)
|
||||
|
||||
void AEnemySpaceship::Fire()
|
||||
{
|
||||
if (!ProjectileClass)
|
||||
{
|
||||
if (GEngine)
|
||||
GEngine->AddOnScreenDebugMessage(-1, 2.0f, FColor::Red, TEXT("Enemy ProjectileClass not set!"));
|
||||
return;
|
||||
}
|
||||
if (!ProjectileClass) return;
|
||||
|
||||
UWorld* World = GetWorld();
|
||||
if (World)
|
||||
@@ -252,9 +478,11 @@ void AEnemySpaceship::Fire()
|
||||
FVector SpawnLocation = ProjectileSpawnPoint->GetComponentLocation();
|
||||
FRotator SpawnRotation = GetActorRotation();
|
||||
|
||||
// Add slight randomness to rotation for less perfect aim
|
||||
float RandPitch = FMath::RandRange(-5.0f, 5.0f);
|
||||
float RandYaw = FMath::RandRange(-5.0f, 5.0f);
|
||||
// Less random spread during flanking for more accurate shots
|
||||
float SpreadMultiplier = (CurrentBehaviorState == EEnemyBehaviorState::Flank) ? 0.9f : 1.0f;
|
||||
float RandPitch = FMath::RandRange(-5.0f, 5.0f) * SpreadMultiplier;
|
||||
float RandYaw = FMath::RandRange(-5.0f, 5.0f) * SpreadMultiplier;
|
||||
|
||||
SpawnRotation.Pitch += RandPitch;
|
||||
SpawnRotation.Yaw += RandYaw;
|
||||
|
||||
@@ -262,7 +490,6 @@ void AEnemySpaceship::Fire()
|
||||
SpawnParams.Owner = this;
|
||||
SpawnParams.Instigator = GetInstigator();
|
||||
|
||||
// Spawn the projectile using EnemyProjectile class
|
||||
AEnemyProjectile* Projectile = World->SpawnActor<AEnemyProjectile>(
|
||||
ProjectileClass,
|
||||
SpawnLocation,
|
||||
@@ -270,12 +497,6 @@ void AEnemySpaceship::Fire()
|
||||
SpawnParams
|
||||
);
|
||||
|
||||
if (Projectile)
|
||||
{
|
||||
if (GEngine)
|
||||
GEngine->AddOnScreenDebugMessage(-1, 0.5f, FColor::Yellow, TEXT("Enemy Fired!"));
|
||||
}
|
||||
|
||||
// Start fire rate timer
|
||||
bCanFire = false;
|
||||
GetWorldTimerManager().SetTimer(FireTimerHandle, this, &AEnemySpaceship::ResetFire, FireRate, false);
|
||||
|
||||
@@ -11,7 +11,8 @@ enum class EEnemyBehaviorState : uint8
|
||||
Chase, // Actively pursue the player
|
||||
Attack, // Stop and shoot at the player
|
||||
Retreat, // Move away from player when too close
|
||||
Strafe // Move sideways while attacking
|
||||
Strafe, // Move sideways while attacking
|
||||
Flank // Execute flanking maneuver
|
||||
};
|
||||
|
||||
UCLASS()
|
||||
@@ -32,17 +33,45 @@ protected:
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Combat")
|
||||
USceneComponent* ProjectileSpawnPoint;
|
||||
|
||||
// Add interpolation speed for smooth movement
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Movement")
|
||||
float MovementSpeed = 500.0f;
|
||||
float InterpSpeed = 3.0f;
|
||||
|
||||
// Add max acceleration to prevent sudden movements
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Movement")
|
||||
float MaxAcceleration = 2000.0f;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Movement")
|
||||
float AttackRange = 1500.0f;
|
||||
float MovementSpeed = 1200.0f;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Movement")
|
||||
float MinDistanceToPlayer = 500.0f;
|
||||
float FlankingSpeed = 1200.0f; // Even faster during flanking
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Movement")
|
||||
float StrafeSpeed = 300.0f;
|
||||
float FlankAngle = 60.0f; // Angle for flanking maneuver
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Movement")
|
||||
float FlankDistance = 2000.0f; // Distance to maintain during flanking
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Movement")
|
||||
float FlankPositionUpdateInterval = 1.0f; // How often to update flank position
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Movement")
|
||||
float AttackRange = 4000.0f;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Movement")
|
||||
float MinDistanceToPlayer = 1500.0f;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Movement")
|
||||
float StrafeSpeed = 500.0f;
|
||||
|
||||
// Add new property for minimum distance to other enemies
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Movement")
|
||||
float MinDistanceToOtherEnemies = 800.0f;
|
||||
|
||||
// Add new property for optimal combat distance
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Movement")
|
||||
float OptimalCombatDistance = 2500.0f;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Combat")
|
||||
float MaxHealth = 100.0f;
|
||||
@@ -74,6 +103,12 @@ protected:
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "AI")
|
||||
float StateChangeChance = 0.3f;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "AI")
|
||||
float AggressionFactor = 0.7f; // Higher values make the enemy more likely to choose aggressive actions
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "AI")
|
||||
float FlankingFrequency = 0.6f; // Increased chance of flanking (was 0.4f)
|
||||
|
||||
public:
|
||||
virtual void Tick(float DeltaTime) override;
|
||||
|
||||
@@ -105,9 +140,28 @@ private:
|
||||
void ChangeBehaviorState();
|
||||
void Die();
|
||||
|
||||
void SmoothMove(const FVector& TargetLocation, float DeltaTime);
|
||||
|
||||
// AI behavior implementation functions
|
||||
void PerformChase(float DeltaTime);
|
||||
void PerformAttack(float DeltaTime);
|
||||
void PerformRetreat(float DeltaTime);
|
||||
void PerformStrafe(float DeltaTime);
|
||||
void PerformFlank(float DeltaTime);
|
||||
|
||||
FVector CalculatePositionAwayFromOtherEnemies();
|
||||
FVector CalculateFlankPosition();
|
||||
|
||||
FVector CurrentVelocity;
|
||||
FVector TargetVelocity;
|
||||
FVector LastPosition;
|
||||
|
||||
FVector FlankPosition;
|
||||
float FlankTimer;
|
||||
bool bIsFlankingRight;
|
||||
FTimerHandle FlankUpdateTimer;
|
||||
|
||||
float LastFlankUpdateTime;
|
||||
FVector CurrentFlankTarget;
|
||||
bool bInitializedFlank;
|
||||
};
|
||||
Reference in New Issue
Block a user