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

DROJAN


Drojan logo
Team Size: 4
My Role: Programmer
Tools: Unreal Engine
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. This project was developed as a final year project at University of Bolton, England.


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)
  • Better understanding of Unreal Engine:
    • This project forced me to dig deep into the Unreal Engine source code and figure out how the AI Perception system works. It was a tough task, though I got through it and was able to achieve something that provided real challenge for the final project.
  • Character controls:
    • A big challenge when creating the project was the character controls, I wanted to give the player the feeling that they flying a real drone. I was able to achieved this using a hover/fly mechanic and by giving the drone some momentum for stopping and accelerating.
  • Camera controls:
    • This project forced me to re-think and re-work the camera system. Instead of just using one camera throughout the game, the user was able to switch between cameras, which provided them with more information at times, in order to traverse the level. If the player entered a vent, I added a feature where the camera would switch to first person due to a clipping bug.
  • Use of debugging tools:
    • Using the artificial intelligence debugging tools (provided by Unreal Engine), I was able to spot when an error occured, which helped speed up development.

CODE SAMPLES


Guard Patrolling

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 can see 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 & Variables

Examples of how functions and variables were exposed for the designers, to use with Blueprints.
// 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


AI Demo



Game Trailer