Files
UnrealPrototyping/Source/Salty/Variant_Combat/AI/CombatEnemySpawner.cpp
T
Rainer LeitandClaude Fable 5.1 4f2c55cd2a Step 1: the Salty project, two modules, tests and the gym
Salty.uproject (UE 5.8) from the Third Person template with class redirects, the SaltyCore and Salty modules,
the three build targets, USaltyAssetManager calling InitGlobalData, Config/Tags with the 23 root namespaces,
Scripts/run-tests.sh, build.sh and Authoring/create_gym.py, L_Gym, Git LFS attributes and the placeholder test.
Template variants kept as reference (D-41). The four Fab packs stay out of the repository for now (~10 GB).
The editor serves the engine MCP plugin on 127.0.0.1:8000 through DefaultEditorPerProjectUserSettings.ini.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-16 20:10:43 +03:00

127 lines
3.3 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "CombatEnemySpawner.h"
#include "Engine/World.h"
#include "Components/SceneComponent.h"
#include "Components/CapsuleComponent.h"
#include "Components/ArrowComponent.h"
#include "TimerManager.h"
#include "CombatEnemy.h"
ACombatEnemySpawner::ACombatEnemySpawner()
{
PrimaryActorTick.bCanEverTick = false;
// create the root
RootComponent = CreateDefaultSubobject<USceneComponent>(TEXT("Root"));
// create the reference spawn capsule
SpawnCapsule = CreateDefaultSubobject<UCapsuleComponent>(TEXT("Spawn Capsule"));
SpawnCapsule->SetupAttachment(RootComponent);
SpawnCapsule->SetRelativeLocation(FVector(0.0f, 0.0f, 90.0f));
SpawnCapsule->SetCapsuleSize(35.0f, 90.0f);
SpawnCapsule->SetCollisionProfileName(FName("NoCollision"));
SpawnDirection = CreateDefaultSubobject<UArrowComponent>(TEXT("Spawn Direction"));
SpawnDirection->SetupAttachment(RootComponent);
}
void ACombatEnemySpawner::BeginPlay()
{
Super::BeginPlay();
// should we spawn an enemy right away?
if (bShouldSpawnEnemiesImmediately)
{
// schedule the first enemy spawn
GetWorld()->GetTimerManager().SetTimer(SpawnTimer, this, &ACombatEnemySpawner::SpawnEnemy, InitialSpawnDelay);
}
}
void ACombatEnemySpawner::EndPlay(EEndPlayReason::Type EndPlayReason)
{
Super::EndPlay(EndPlayReason);
// clear the spawn timer
GetWorld()->GetTimerManager().ClearTimer(SpawnTimer);
}
void ACombatEnemySpawner::SpawnEnemy()
{
// ensure the enemy class is valid
if (IsValid(EnemyClass))
{
// spawn the enemy at the reference capsule's transform
FActorSpawnParameters SpawnParams;
SpawnParams.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButAlwaysSpawn;
ACombatEnemy* SpawnedEnemy = GetWorld()->SpawnActor<ACombatEnemy>(EnemyClass, SpawnCapsule->GetComponentTransform(), SpawnParams);
// was the enemy successfully created?
if (SpawnedEnemy)
{
// subscribe to the death delegate
SpawnedEnemy->OnEnemyDied.AddDynamic(this, &ACombatEnemySpawner::OnEnemyDied);
}
}
}
void ACombatEnemySpawner::OnEnemyDied()
{
// decrease the spawn counter
--SpawnCount;
// is this the last enemy we should spawn?
if (SpawnCount <= 0)
{
// schedule the activation on depleted message
GetWorld()->GetTimerManager().SetTimer(SpawnTimer, this, &ACombatEnemySpawner::SpawnerDepleted, ActivationDelay);
return;
}
// schedule the next enemy spawn
GetWorld()->GetTimerManager().SetTimer(SpawnTimer, this, &ACombatEnemySpawner::SpawnEnemy, RespawnDelay);
}
void ACombatEnemySpawner::SpawnerDepleted()
{
// process the actors to activate list
for (AActor* CurrentActor : ActorsToActivateWhenDepleted)
{
// check if the actor is activatable
if (ICombatActivatable* CombatActivatable = Cast<ICombatActivatable>(CurrentActor))
{
// activate the actor
CombatActivatable->ActivateInteraction(this);
}
}
}
void ACombatEnemySpawner::ToggleInteraction(AActor* ActivationInstigator)
{
// stub
}
void ACombatEnemySpawner::ActivateInteraction(AActor* ActivationInstigator)
{
// ensure we're only activated once, and only if we've deferred enemy spawning
if (bHasBeenActivated || bShouldSpawnEnemiesImmediately)
{
return;
}
// raise the activation flag
bHasBeenActivated = true;
// spawn the first enemy
SpawnEnemy();
}
void ACombatEnemySpawner::DeactivateInteraction(AActor* ActivationInstigator)
{
// stub
}