From 8a7ee5faee6559c2e30e036073c7c6dd578abeee Mon Sep 17 00:00:00 2001 From: Louis Hobbs Date: Mon, 13 Mar 2023 22:58:21 +0000 Subject: [PATCH] Add basic logic to `EnemyCharacter` `OnFire` functions --- Source/Nakatomi/EnemyCharacter.cpp | 60 +++++++++++++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/Source/Nakatomi/EnemyCharacter.cpp b/Source/Nakatomi/EnemyCharacter.cpp index 26b4fbf..ecdfadf 100644 --- a/Source/Nakatomi/EnemyCharacter.cpp +++ b/Source/Nakatomi/EnemyCharacter.cpp @@ -4,6 +4,8 @@ #include "GameFramework/CharacterMovementComponent.h" #include "EnemyAIController.h" +#define COLLISION_WEAPON ECC_GameTraceChannel1 + AEnemyCharacter::AEnemyCharacter() { PerceptionComponent = CreateDefaultSubobject(TEXT("Perception Component")); @@ -38,11 +40,17 @@ UAIPerceptionComponent* AEnemyCharacter::GetPerceptionComponent() void AEnemyCharacter::OnFire() { + CurrentWeapon->SetCurrentWeaponStatus(WeaponState::Firing); + TArray Hits = TArray(); CalculateHits(&Hits); ProcessHits(Hits); - GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("BANG")); + CurrentWeapon->PlayFireSoundAtLocation(GetActorLocation()); + + // TODO: Play some animation here + + CurrentWeapon->SetCurrentWeaponStatus(WeaponState::Cooldown); } void AEnemyCharacter::BeginPlay() @@ -52,8 +60,58 @@ void AEnemyCharacter::BeginPlay() void AEnemyCharacter::CalculateHits(TArray* hits) { + // Set up randomness + const int32 RandomSeed = FMath::Rand(); + FRandomStream WeaponRandomStream(RandomSeed); + const float Spread = CurrentWeapon->GetWeaponProperties()->WeaponSpread; + const float Range = CurrentWeapon->GetWeaponProperties()->ProjectileRange; + + // Calculate starting position and direction + FVector TraceStart = this->GetTransform().GetLocation(); + FRotator PlayerRot = this->GetTransform().GetRotation().Rotator(); + TraceStart = GetRootComponent()->GetComponentLocation(); + FVector AimDir = PlayerRot.Vector(); + AimDir.Z = 0.0; + TraceStart = TraceStart + AimDir * ((GetInstigator()->GetActorLocation() - TraceStart) | AimDir); + + // Calculate the hit results from the trace + TArray HitResults; + + // Set up the collision query params, use the Weapon trace settings, Ignore the actor firing this trace + FCollisionQueryParams TraceParams(SCENE_QUERY_STAT(WeaponTrace), true, GetInstigator()); + TraceParams.bReturnPhysicalMaterial = true; + + for (size_t i = 0; i < CurrentWeapon->GetWeaponProperties()->ProjectilesPerShot; i++) + { + // Calculate the maximum distance the weapon can fire + FVector ShootDir = WeaponRandomStream.VRandCone(AimDir, FMath::DegreesToRadians(Spread), FMath::DegreesToRadians(Spread)); + FVector MaxHitLoc = TraceStart + (ShootDir * Range); + + GetWorld()->LineTraceMultiByChannel(HitResults, TraceStart, MaxHitLoc, COLLISION_WEAPON, TraceParams); + + for (FHitResult Result : HitResults) + { + hits->Add(Result); + DrawDebugLine(GetWorld(), TraceStart, Result.ImpactPoint, FColor::Red, true, 500, 0U, 0); + } + } } void AEnemyCharacter::ProcessHits(TArray hits) { + for (FHitResult Hit : hits) + { + // TODO: Handle hits in a meaningful way + FActorSpawnParameters SpawnParameters; + SpawnParameters.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn; + + // Spawn field actor + FTransform transform; + transform.SetLocation(Hit.ImpactPoint); + auto field = GetWorld()->SpawnActor(CurrentWeapon->GetFieldSystemActor(), transform, SpawnParameters); + + if (Hit.GetActor()) + { + } + } }