From 67ac9d1935d88423bc96cb88e131474fdf6bf7df Mon Sep 17 00:00:00 2001 From: aicorr Date: Wed, 16 Apr 2025 07:28:07 +0530 Subject: [PATCH] Implement flanking mechanics and slightly increase enemy speed --- Content/Blueprints/BP_EnemySpaceship.uasset | 4 +- Content/Blueprints/BP_SpaceshipPawn.uasset | 4 +- Content/Materials/Material.uasset | 3 + Content/Materials/Material_001.uasset | 3 + Content/Materials/Material_002.uasset | 3 + Content/Meshes/spaceship_lowpoly.uasset | 3 + Source/MyProject3/EnemySpaceship.cpp | 325 ++++++++++++++++---- Source/MyProject3/EnemySpaceship.h | 64 +++- 8 files changed, 348 insertions(+), 61 deletions(-) create mode 100644 Content/Materials/Material.uasset create mode 100644 Content/Materials/Material_001.uasset create mode 100644 Content/Materials/Material_002.uasset create mode 100644 Content/Meshes/spaceship_lowpoly.uasset diff --git a/Content/Blueprints/BP_EnemySpaceship.uasset b/Content/Blueprints/BP_EnemySpaceship.uasset index ad0ae9e..3c84129 100644 --- a/Content/Blueprints/BP_EnemySpaceship.uasset +++ b/Content/Blueprints/BP_EnemySpaceship.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8dc909a51aa86f1721b8bee661ac1823a38bdef7544a11dae37982de892ab929 -size 30916 +oid sha256:39d36dfd7a1231daa0438638e93117111c923c4bf8602f92c7786d1b8c933943 +size 34382 diff --git a/Content/Blueprints/BP_SpaceshipPawn.uasset b/Content/Blueprints/BP_SpaceshipPawn.uasset index 94d849b..35baa83 100644 --- a/Content/Blueprints/BP_SpaceshipPawn.uasset +++ b/Content/Blueprints/BP_SpaceshipPawn.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:36c53041140c765d2c91438f7219c8004e61d61ab1c49335b870999232792e6c -size 33621 +oid sha256:d6e62fcec27bc08d7fe4b98fc7ff15dd02f3b3564831c0e8311f424ecacad8e4 +size 33771 diff --git a/Content/Materials/Material.uasset b/Content/Materials/Material.uasset new file mode 100644 index 0000000..0ad64b8 --- /dev/null +++ b/Content/Materials/Material.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a81c8d77252a0dfda8c46952296dc1ecbcbac8dd7670df577fa232960629de30 +size 28437 diff --git a/Content/Materials/Material_001.uasset b/Content/Materials/Material_001.uasset new file mode 100644 index 0000000..c55aa8b --- /dev/null +++ b/Content/Materials/Material_001.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0864954a6dc67c4c0dcbed64aff08907f818d3125b30cd8110e9ece491d6849f +size 30232 diff --git a/Content/Materials/Material_002.uasset b/Content/Materials/Material_002.uasset new file mode 100644 index 0000000..06f293a --- /dev/null +++ b/Content/Materials/Material_002.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:55c0828d20226f316e35a5f28a3ebfeb00376089beec37c362d695e26c92476a +size 28704 diff --git a/Content/Meshes/spaceship_lowpoly.uasset b/Content/Meshes/spaceship_lowpoly.uasset new file mode 100644 index 0000000..0038448 --- /dev/null +++ b/Content/Meshes/spaceship_lowpoly.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:137a889f0c3e4093147a9b4e44fc0d02743e9420bd0ad4f9bbb4cdad9b1ba87c +size 206419 diff --git a/Source/MyProject3/EnemySpaceship.cpp b/Source/MyProject3/EnemySpaceship.cpp index c95b13d..4817a28 100644 --- a/Source/MyProject3/EnemySpaceship.cpp +++ b/Source/MyProject3/EnemySpaceship.cpp @@ -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(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 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( 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); diff --git a/Source/MyProject3/EnemySpaceship.h b/Source/MyProject3/EnemySpaceship.h index cf96471..61fad5d 100644 --- a/Source/MyProject3/EnemySpaceship.h +++ b/Source/MyProject3/EnemySpaceship.h @@ -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; }; \ No newline at end of file