Syntax Souls
BSc Games Development Project Year 3
Description
Driving inspiration from the "get good" mentality, Syntax Souls takes on the Souls-like approach of a punishing action-rpg where you search the surrounding areas fighting off enemies until you are met by a challenging foe.
Poise
Poise is a hidden stat. It's an in-game statistic that increases your resistance to being staggered as an effect of taking hits from opponents
If the actor being attacked reaches 0 poise, they will be staggered. When the player/enemy has been staggered, they will be inable to move or attack.
void UHealthComponent::ApplyPoiseDamage(float value) { // Return if the value is 0 or less if(value <= 0) return; // Reset the PoiseResetCount PoiseResetCount = 0.0f; Poise = FMath::Clamp(Poise - value, 0.0f, PoiseMax); // If Poise falls below 0, Stagger Owner unless already staggered if(Poise <= 0 && !isStaggered) { AActor* FOwner = GetOwner(); OnPoiseBreak.Broadcast(FOwner); isStaggered = true; Poise = PoiseMax; PoiseResetCount = 0.0f; } }
void UHealthComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) { Super::TickComponent(DeltaTime, TickType, ThisTickFunction); if (Poise < PoiseMax) { PoiseResetCount += DeltaTime; if (PoiseResetCount >= PoiseResetTime) { PoiseResetCount = 0.0f; Poise = PoiseMax; } } }
Target Locking
Target locking allows the player to lock onto their target, so that their attacks are directed towards the intended enemy. The player is also able to switch between targets within proximty.
void APlayerCharacter::LockTarget() { // if target is locked, unlock it if(targetLocked) { targetLocked = false; bUseControllerRotationYaw = false; GetCharacterMovement()->bOrientRotationToMovement = true; lockedOnTarget = nullptr; } // if target is not locked, lock it else { FVector StartLocation = GetActorLocation() + 300.f * MainCamera->GetForwardVector(); FVector EndLocation = MainCamera->GetForwardVector() * 1000.0f + StartLocation; TArray<AActor*> IgnoredActors; IgnoredActors.Add(this); TArray<FHitResult> HitArray; bool bHasHit = UKismetSystemLibrary::SphereTraceMulti(this, StartLocation, EndLocation, 300.f, UEngineTypes::ConvertToTraceType(ECC_Camera), false, IgnoredActors, DrawDebugType, HitArray, true, FLinearColor::Yellow, FLinearColor::Blue, 5.0f); if(bHasHit) { for (const FHitResult HitResult : HitArray) { // if hitresult has the Target Component, then we have a target if(HitResult.GetActor()->FindComponentByClass<UTargetComponent>()) { UHealthComponent* targetHealth = HitResult.GetActor()->FindComponentByClass<UHealthComponent>(); if(targetHealth) { if(targetHealth->GetHealth() <= 0) { return; } } lockedOnTarget = HitResult.GetActor(); targetLocked = true; bUseControllerRotationYaw = true; GetCharacterMovement()->bOrientRotationToMovement = false; break; } } } } }
void APlayerCharacter::SwitchTarget(bool isLeft, float Distance, float Radius) { float offset = isLeft ? -1.0f : 1.0f; FVector playerLeft = GetActorRightVector() * offset * Distance; FVector targetLocation = lockedOnTarget->GetActorLocation() + (Radius * 1.1f) * (GetActorRightVector() * offset); TArray<AActor*> IgnoredActors; IgnoredActors.Add(this); IgnoredActors.Add(lockedOnTarget); TArray<FHitResult> HitArray; bool bHasHit = UKismetSystemLibrary::SphereTraceMulti(this, targetLocation, targetLocation + playerLeft, Radius, UEngineTypes::ConvertToTraceType(ECC_Camera), false, IgnoredActors, DrawDebugType, HitArray, true, FLinearColor::Yellow, FLinearColor::Blue, 5.0f); if(bHasHit) { for (const FHitResult HitResult : HitArray) { if(HitResult.GetActor()->FindComponentByClass<UTargetComponent>()) { UHealthComponent* targetHealth = HitResult.GetActor()->FindComponentByClass<UHealthComponent>(); if(targetHealth) { if(targetHealth->GetHealth() <= 0) { return; } } lockedOnTarget = HitResult.GetActor(); targetLocked = true; bUseControllerRotationYaw = true; GetCharacterMovement()->bOrientRotationToMovement = false; break; } } } }