Back to all projects

Gameplay Programmer

Dark Chamber

Developed and maintained AI behavior systems, player-AI interactions, AI-environment interactions, and UI features. The goal was to create a responsive and immersive AI that felt constantly present in the game world, increasing player tension and enhancing the overall horror experience.

Unreal Engine 5C++BlueprintBehavior Trees
Watch Trailer

Duration

4 months

Team

3 developers

Engine

Unreal Engine 5

Platforms

PC

Gameplay Pillars

  • >Immersive AI presence that enhances tension
  • >Reactive enemy behavior driven by player actions
  • >Enemy encounters that remain challenging without feeling unfair

My Responsibilities

  • >Implemented enemy AI behavior systems including perception, navigation, and combat.
  • >Implemented player-AI interaction systems, including enemy reactions to lock-on targeting, combat hits, and stagger states.
  • >Integrated AI-environment interactions, including trap responses, and detection of player actions.

Code Snippets

Practical samples from gameplay systems and runtime tools used in production.

Monster Attack System

BTTask_MeleeAttack.cpp | cpp

Behavior tree task that checks if the player is in range and executes the monster's melee attack.

#include "BTTask_MeleeAttack.h"
#include "Monster_AIController.h"
#include "DarkChamber/DarkChamberCharacter.h"

UBTTask_MeleeAttack::UBTTask_MeleeAttack()
{
	NodeName = TEXT("Melee attack");
}

EBTNodeResult::Type UBTTask_MeleeAttack::ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory)
{
	//if not in range, don't attack the player
	auto const OutOfRange = !OwnerComp.GetBlackboardComponent()->GetValueAsBool(GetSelectedBlackboardKey());

	if(OutOfRange)
	{
		//Finish task
		FinishLatentTask(OwnerComp, EBTNodeResult::Succeeded);
		return EBTNodeResult::Succeeded;
	}

	auto const * const Controller = OwnerComp.GetAIOwner();
	auto* const Monster = Cast<AMonster>(Controller->GetPawn());
	//If the Monster supports the Combat Interface, call and execute the Attack function
	if(auto* const ICombat = Cast<ICombatInterface>(Monster))
	{
		if(auto* const Player = Cast<ADarkChamberCharacter>(Controller->GetPawn()))
		{
			
			Player->PlayerHealth->ReduceHealth(Monster->AttackDamage);
		}
		ICombat->Execute_MeleeAttack(Monster);
	}
	FinishLatentTask(OwnerComp, EBTNodeResult::Succeeded);
	return EBTNodeResult::Type();
}

Monster-Trap Interaction

Monster.cpp | cpp

Implementation for monster that involve traps, using interfaces.

void AMonster::HoleAttack_Implementation()
{
	CharacterMovement->Deactivate();
	FTimerHandle TimerHandle;
	GetWorld()->GetTimerManager().SetTimer(TimerHandle, this, &AMonster::SetMovement, 7.0f, false, 5);
	GEngine->AddOnScreenDebugMessage(-1, 1, FColor::Red, "HoleAttack");
}

void AMonster::EletricAttack_Implementation()
{
	CharacterMovement->Deactivate();
	FTimerHandle TimerHandle;
	GetWorld()->GetTimerManager().SetTimer(TimerHandle, this, &AMonster::SetMovement, 5.0f, false, 5);
	GEngine->AddOnScreenDebugMessage(-1, 1, FColor::Red, "EletricAttack");
}

Production Outcomes

  • >Reduced encounter restart frequency following improvements to enemy telegraphing and attack readability, resulting in smoother learning curves during combat.
  • >Improved consistency of combat encounter duration by tuning AI aggression and decision pacing across different player skill levels.
Discuss this project