KYLE THOMAS
Game Programmer | Contact: kyle.j.t@live.co.uk

DROJAN


Drojan logo
Team Size: 4
My Role: Programmer
Tools: Unreal
Language: C++
Release date: TBA
Platform: PC (Steam Greenlight)


Game Overview

Drojan is a 3D stealth/puzzle hacking game, featuring a drone as the player, where you navigate through the office building to find and steal back the firmware that makes servers unhackable. Along the way there are guards, employees and security cameras that will stop you from doing your job so easily.


Story

A disgruntled Ex-employee of a private security firm, wants to steal back their firmware prototype that makes any server unhackable. But there is one set back, the security firm has their biometric data on record making it impossible for them to physically enter the building, so using a prototype drone that they have created, they will be able to break into the office to find and take back their firmware.


My Roles

  • Artificial Intelligence:
    • From the start, my goal was to create a semi-realistic AI that would patrol, chase, search and attack. This was achieved by giving the AI perception senses which was then called to a behavior tree to control them (refer to code smaple)
  • Gameplay:
    • As the sole programmer of the team, I also dealt with aspects of gameplay, such as character movement and object interaction. The character movement was a challenge at first as originally we had a point and click game, but then we decided to move onto third person camera controls which gave us the freedom to move around in all axis
  • Tools:
    • As we had two designers on the team, and my parts of the project was written in C++, I decided expose functions and variables to the designers to use freely in blueprint. This helped the project progress easily and helped avoid any refactoring in the long run (refer to code sample)



What the project taught me:

  • Teamwork:
    • This was the first real project that gave me the freedom to break away from programmers to work along side a team of designers and artists. It gave me an insight on how each member works within the industry and how I can implement certain features to assist other members of the team.
  • Better AI implementation:
    • Up until now, AI in my games have been pretty basic. Unreal Engine gave me the option to expand my knowledge by working with the AI perception system and the Environment Query System (EQS)

CODE SAMPLE


Guard Patrolling to Waypoints:

A code sample taken from the guard controller that deals with how the AI patrols to the next waypoint in queue.
void AGuardController::Patrol()
{
	Guard = Cast<AGuardCharacter>(Blackboard->GetValueAsObject(SelfActor_Key)); // Set guard as selfactor from BB

	if (Guard != nullptr) // check to make sure its not null to avoid any crashes
	{
		for (int i = 0; i < Guard->TargetPoint.Num(); i++)
		{
			if (Guard->TargetPoint[NextTarget] != nullptr) // if the next target isnt null to avoid anycrashes
			{
				if (Guard->GetActorLocation().Equals(Guard->TargetPoint[NextTarget]->GetActorLocation(), 100.0f)) // guard location equal to target location with tolerence
				{
					IsMoving = false;

					if (!IsMoving)
					{
						if (NextTarget >= (Guard->TargetPoint.Num() - 1))
						{
							NextTarget = 0; // Set back to 0 if no more targets
						}
						else
						{
							NextTarget = NextTarget + 1; // Go to next target if there is one to go to
							IsMoving = true;
						}
					}
				}
				else
				{
					BlackboardComp->SetValueAsVector(TargetPoint_Key, Guard->TargetPoint[NextTarget]->GetActorLocation()); // Set the vector of the target location -- passes to behavior tree
					IsMoving = true; // set this to true so we don't run the above code
				}
			}
		}
	}
}		
		

Guard Sight Perception:

A code sample taken from the guard controller that shows how the guard spots the player through sight perception.
GetAIPerceptionComponent()->GetActorsPerception(testActors[i], Info);

if (Info.LastSensedStimuli[i].Type == 0) // Sight
{
	const FAIStimulus Stimulus = Info.LastSensedStimuli[0];

	if (Stimulus.WasSuccessfullySensed())
	{
		// Player in sight
		Character = Cast<ADroneCharacter>(Info.Target);

		if (Character != nullptr) // Check if character isnt null
		{
			PlayerSpotted = true; // Set player spotted
			DelayTimer = 0.0f; // Reset delay timer
		}
	}
	else
	{
		PlayerSpotted = false;
		
		if (PlayerDetected)
		{
			LastKnownLocation = Stimulus.StimulusLocation; // Set last known location
			AIState = EAIState::SEARCH; // Change state
			BlackboardComp->SetValueAsEnum(EnumKey_Key, EAIState::SEARCH); // Update state in BB
		}
	}
}
		

Exposing Functions & Variable (For Designers):

Examples of how functions and variables were exposed for designers.
// All done in header files

// BlueprintReadWrite allows the designer to call it in Blueprint and EditAnywhere will enable the designer to change this value on the fly
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="AI Perception") // UPROPERTY for variables
	bool PlayerSpotted = false;
	
// BlueprintCallable lets the designer call this function to code	
UFUNCTION(BlueprintCallable, Category = "Camera View") // UFUNCTION for functions
	void HackingView();
UFUNCTION(BlueprintCallable, Category="Camera View")
	void PlayerView();
		

VIDEOS