
A 3D city-building simulation in which you manage a resort to satisfy aggressive alien tourists — or risk the world's destruction. Real-time resource management, placement mechanics, and a Needs-driven AI system where every alien has a priority queue of desires. If satisfaction drops too low, the global mood collapses and it's game over.
TryGetTask() picks the most urgent unsatisfied need and queries the world for a matching facility.SpawnRateUpdate at thresholds 80/60/40 and GameOver below 30.
Needs are sorted by CurValue (lowest = most urgent). On repeated failure the alien's mood is decremented; once all tasks are exhausted the alien state flips to Leaving.
void AAlien::TryGetTask()
{
// Sort needs ascending — lowest value is most urgent
Needs.Sort([](const FNeed& A, const FNeed& B)
{ return A.CurValue < B.CurValue; });
for (FNeed& Need : Needs)
{
if (Need.CurValue >= Need.SatisfiedThreshold) continue;
AActor* Facility = AlienSubsystem->FindFacilityFor(Need.Type, GetActorLocation());
if (Facility)
{
CurrentTask = { Need.Type, Facility };
AlienState = EAlienState::MovingToTask;
return;
}
// Facility not found — penalise mood
--CurFailedTasks;
ChangeMood(-BadMoodVal);
}
// No satisfiable need found — give up and leave
AlienState = EAlienState::Leaving;
}
The subsystem aggregates mood from all active aliens and fires spawn-rate delegates at each threshold. Dropping below 30 triggers the lose condition.
void UAlienSubsystem::UpdateGlobalMood()
{
float Total = 0.f;
for (AAlien* A : ActiveAliens) Total += A->GetMood();
GlobalMood = ActiveAliens.Num() > 0
? Total / ActiveAliens.Num()
: 100.f;
// Fire delegates at mood thresholds
if (GlobalMood <= 30.f) OnGameOver.Broadcast();
else if (GlobalMood <= 40.f) OnSpawnRateUpdate.Broadcast(ESpawnRate::Crisis);
else if (GlobalMood <= 60.f) OnSpawnRateUpdate.Broadcast(ESpawnRate::Slow);
else if (GlobalMood <= 80.f) OnSpawnRateUpdate.Broadcast(ESpawnRate::Normal);
else OnSpawnRateUpdate.Broadcast(ESpawnRate::Fast);
}
void UAlienSubsystem::TickStateMachine(AAlien* A, float DT)
{
switch (A->AlienState)
{
case EAlienState::Idle:
A->TryGetTask(); break;
case EAlienState::Arrived:
A->DoTask(DT); break;
case EAlienState::Leaving:
A->Leave();
ActiveAliens.Remove(A);
AlienPool.Return(A); // back to object pool
UpdateGlobalMood(); // re-evaluate after departure
break;
}
}