In The Chamber
Contributions
Gameplay Programmer
Enabling Abilities using a system akin to GAS
Player responsiveness
Camera interactions
Compatibility with PC and Controller
Project Overview
Project Duration - 9 Weeks
Genre - Roguelike
Engine - Unreal Engine 5
Team Size - 17
Platfroms - PC & Playstation 5
Personal Notes
The team size was a warm welcome, enabling me to work on the things I really wanted to work on, getting able to know how one would approach an ability system was a unique insight into a genre I deeply love.
Knowing this was my first time ever doing a project in Unreal Engine, I was able to make a system for abilities in the game. Being able to implement them in both c++ and blueprints, while also making the player controller, empowering an understanding of Unreal Engine 5 in a way I wouldn't have otherwise.
Development Process
Ability System
We knew the ability system was important, so I started work on it as fast as possible, I started by looking up documentation for GAS, a system we consciously did not choose owing to the fact it would be beyond the scope of the project. I started with making an example ability that activated from blueprints. Then I branched out to make the code more blueprint friendly by making helper functions, both for c++ and blueprints, validating a more agile workflow for designers and other programmers.
I thought the most effective way of making an ability system would be to let any entity that would end up using an ability would end up as part of the "ability user" class. The ability system component would automatically make the associated ability from blueprints, and if necessary, bind it to an input.
const TObjectPtr<AAbility> NewAbility = NewObject<AAbility>( this, Class );
Abilities.Add( NewAbility );
if ( !IsValid( InputAction ) )
return;
NewAbility->BoundTo = InputAction;
if ( FAbilityStruct* Binding = BoundAbilities.Find( InputAction ) )
Binding->Abilities.Add( NewAbility );
else
{
FAbilityStruct BindingInfo( { NewAbility } );
BindingInfo.Handle = InputComponent->BindAction( InputAction, ETriggerEvent::Started, this,
&UAbilitySystemComponent::TryActivateAbilityWithInput, InputAction ).GetHandle();
BoundAbilities.Add( InputAction, BindingInfo );
}
An example of two ability users using an ability, the player and the spike trap on the ground
Player Controller
We wanted the camera to work in a specific way, meaning we would have to make custom camera functionality in c++. Likewise, the player control scheme had to be agnostic to the platforms we were planning to use. I also made the camera rotation, speed and distance from the player when moving modular.
void APlayerCharacter::RotateMesh() const
{
FVector DesiredDirection = LookInput.IsZero()
? FVector( MovementInput.X, -MovementInput.Y, 0.f ).GetSafeNormal() :
FVector( LookInput.X, LookInput.Y, 0.f ).GetSafeNormal();
FRotator TargetRotation = FRotationMatrix::MakeFromX( DesiredDirection ).Rotator();
TargetRotation = FMath::RInterpTo( GetMesh()->GetRelativeRotation(), TargetRotation,
GetWorld()->GetDeltaSeconds(), RotationSpeed );
GetMesh()->SetRelativeRotation( TargetRotation );
SetCameraRelative( CameraSpeed );
}
void APlayerCharacter::SetCameraRelative( float _CameraSpeed ) const
{
FVector DesiredDirection = LookInput.IsZero()
? CharacterMovementComponent->GetCurrentAcceleration().GetSafeNormal() * FVector( UE_SQRT_2 ) :
GetMesh()->GetRightVector();
FVector TargetLocation = FMath::VInterpTo( SpringArmComponent->GetComponentLocation(),
GetActorLocation() + DesiredDirection * FVector( CameraDistance ),
GetWorld()->GetDeltaSeconds(), _CameraSpeed );
SpringArmComponent->SetRelativeLocation( TargetLocation );
}
Using the assigned inputs, the camera will move appropirately