Project Cleaver
About
Project cleaver is a vertical slice of a first person combat game. Created in unreal engine using both Blueprints and C++.
Project Info
- Role: Game Programmer
- Team Size: 11
- Project Duration: 6 weeks
- Engine: Unreal Engine, C++
- Completion Date: 8th of April 2024
My contributions
Weapon System
When developing this game we needed a simple way to add multiple weapons to the game. This was done
using Unreal Engine's Data Assets, in this data asset you could enter every value a weapon could
have. If you want to use a weapon you would need to add a WeaponComponent to your actor. This
handles everything regarding the weapon. This component works together with the Health System I
created to have an easy-to-use and scalable combat system.
Health System
The Health system was the first thing that I created in C++. I wanted this component to be dynamic
and easy to use. This component makes use of Delegates to communicate updates of the health to
blueprints.
void UHealthSystem::TakeDamage(int32 amount)
{
CurrentHealth -= abs(amount);
OnDamageTaken.Broadcast(CurrentHealth);
OnHealthUpdate.Broadcast(GetNormalizedHealth());
if (CurrentHealth <= 0)
OnDeath.Broadcast();
}
View whole script
Door system
During development of the game we wanted the ability to lock the players progression behind certain
objectives this was done using a gate. The gate can be opened using a blueprintable function. This
component currently always takes the owner to move but this can easily be changed to a variable.
void UDoorSystem::MoveDoor(float MoveLerpAlpha)
{
const FVector NewLocation = FVector(FMath::Lerp(StartLocation, EndLocation, MoveLerpAlpha));
const FRotator NewRotator = FRotator(FMath::Lerp(StartRotator, EndRotator, MoveLerpAlpha));
GetOwner()->GetRootComponent()->SetWorldLocationAndRotation(NewLocation, NewRotator);
if (MoveLerpAlpha >= 1)
{
DoorState = Open;
SetComponentTickEnabled(false);
}
}
View whole script
Enemy locked event
We wanted the ability to track the amount of enemies currently living in a certain
place. To solve this, I created the EnemyLockedEvent component. This component acts like a
listener. It keeps an ear out for whenever an enemy dies (the enemy's OnDeath event). But it only
listens to enemies on a special list created by the designer. This way, the component can track
exactly how many of those designated enemies are still alive.
void UEnemyLockedEvent::BeginPlay()
{
Super::BeginPlay();
AliveEnemies = Enemies.Num();
for (const auto Enemy : Enemies)
{
UHealthSystem* HealthSystem = Enemy->GetComponentByClass<UHealthSystem>();
if (!HealthSystem) return;
HealthSystem->OnDeath.AddDynamic(this, &UEnemyLockedEvent::UpdateThreshold);
}
}
features I also made
- UI Integration
- Interact Shader
What I learned from this project
In this project I learned how to make my code more reusable using actor components and events. In the future I want to continue creating more reusable components and begin working on tools to improve the workflow.