Bound Core is a 3D bossfight game where 2 players play against a third boss player. Ready to lose friends?
Engine: Unreal Engine 4
Programming: Primarily C++, Blueprints
Project Duration: 9 weeks
Team Size: 8 people
Project Role: Lead Programmer, Planner
Player Abilities
Player Controls
Projectiles
Boss Abilities
User Interface
Environmental Triggers
Audio-Based Skills
Artificial Intelligence
Animation System
Camera System
Leaderboard MySQL Intergration
Code Syleguide
Collision Interactions
Level Script
A code snippet of a PossessionController. This used to unposses both players when they are both ready and then start possesing the other player. It's been recycled into swapping the players their positions in a "Warp-Like" way.
Demonstration of the Warp:
// COPYRIGHT 2019 - Björk #include "BoundCorePossessionController.h" #include "BoundCoreMain.h" #include "ScoreActor.h" #include "Runtime/ActorSequence/Private/ActorSequencePrivatePCH.h" #include "BoundCoreMainCharacter.h" DEFINE_LOG_CATEGORY(BoundCorePossessionControllerLog); ABoundCorePossessionController::ABoundCorePossessionController() { PrimaryActorTick.bCanEverTick = true; ReadyForPossession = false; } void ABoundCorePossessionController::BeginPlay() { Super::BeginPlay(); for (TActorIteratorIt(GetWorld()); It; ++It) { AActor* BoundCoreActor = *It; BoundCoreActors.Add(BoundCoreActor); } for (TActorIterator It(GetWorld()); It; ++It) { BoundCoreActorsMainCharacter.Add(Cast (*It)); } } void ABoundCorePossessionController::Tick(float DeltaTime) { Super::Tick(DeltaTime); CheckMainCharactersSwapStatus(); if (ReadyDone) { for (int i = 0; i < BoundCoreActors.Num(); i++) { BoundCoreActorsMainCharacter[i]->SwapVFXHeightValue -= DeltaTime * 250; BoundCoreActorsMainCharacter[i]->Invulnerable = true; if (BoundCoreActorsMainCharacter[i]->SwapVFXHeightValue < -500.0f) { ReadyDone = false; BoundCoreActorsMainCharacter[i]->IsSwitching = false; BoundCoreActorsMainCharacter[i]->SwapVFXHeightValue = 500; BoundCoreActorsMainCharacter[i]->Invulnerable = false; TArray ScoreActors; UGameplayStatics::GetAllActorsOfClass(GetWorld(), AScoreActor::StaticClass(), ScoreActors); AScoreActor* TheScoreActor = Cast (ScoreActors[0]); if (i == 0) { if (BoundCoreActorsMainCharacter[i]->PregameSkillsEnabled) { TheScoreActor->ApplyScore(ScoreValue, EPlayerEnum::EP_PlayerRed); } } if (i == 1) { if (BoundCoreActorsMainCharacter[i]->PregameSkillsEnabled) { TheScoreActor->ApplyScore(ScoreValue, EPlayerEnum::EP_PlayerBlue); } } } } } } void ABoundCorePossessionController::CheckMainCharactersSwapStatus() { int ReadyCount = 0; for (int i = 0; i < BoundCoreActors.Num(); i++) { if (BoundCoreActorsMainCharacter[i]->AbilitySwapReady) { ReadyCount++; if (!BoundCoreActorsMainCharacter[i]->AbilitySwapHasParticle){ if (ReadyParticle) { UGameplayStatics::SpawnEmitterAttached( ReadyParticle, // Particle Class BoundCoreActors[i]->FindComponentByClass (), // ActorComponent to Attach to FName("AbilitySwapCharacterParticle"), // Name BoneSocket to attach to FVector(0, 0, 0), // Pos FRotator(0, 90, 0), // Rot EAttachLocation::KeepRelativeOffset, // Offset Relative true // World or Local Space ); BoundCoreActorsMainCharacter[i]->AbilitySwapHasParticle = true; } } } } if (ReadyCount == 2) { if (!ReadyDone) { FTimerHandle ParticleTimerTillReset; GetWorldTimerManager().ClearTimer(ParticleTimerTillReset); GetWorldTimerManager().SetTimer(ParticleTimerTillReset, this, &ABoundCorePossessionController::ResetParticles, ParticleTimeTillReset, false, -1.0f); ReadyCount = 0; for (int i = 0; i < BoundCoreActors.Num(); i++) { BoundCoreActorsMainCharacter[i]->IsSwitching = true; BoundCoreActorsMainCharacter[i]->AbilityDashCurrentCharges--; BoundCoreActorsMainCharacter[i]->AbilitySwapReady = false; BoundCoreActorsMainCharacter[i]->AbilityHealthRegen(); BoundCoreActorsMainCharacter[i]->ResetAbilitySwapCharacterTimerForVFX(); } ReadyDone = true; } } } TArray ABoundCorePossessionController::GetOldRotationsAndReset() { TArray OldRotations = TArray (); int BoundCoreActorsNum = BoundCoreActors.Num(); for (int i = 0; i < BoundCoreActorsNum; i++) { OldRotations.Add(BoundCoreActorsMainCharacter[i]->GetActorRotation()); FRotator NewRotation = FRotator::ZeroRotator; BoundCoreActors[i]->SetActorRotation(NewRotation); } return OldRotations; } TArray ABoundCorePossessionController::GetOldPositionsAndReset() { TArray OldPositions = TArray (); int BoundCoreActorsNum = BoundCoreActors.Num(); for (int i = 0; i < BoundCoreActorsNum; i++) { OldPositions.Add(BoundCoreActorsMainCharacter[i]->GetActorLocation()); FVector NewPosition = FVector::ZeroVector; BoundCoreActors[i]->SetActorLocation(NewPosition); } return OldPositions; } void ABoundCorePossessionController::SetNewRotations(TArray OldRotations) { int BoundCoreActorsNum = BoundCoreActors.Num(); for (int i = 0; i < BoundCoreActorsNum; i++) { BoundCoreActors[i]->SetActorRotation(OldRotations[i]); } } void ABoundCorePossessionController::SetNewPositions(TArray OldPositions) { int BoundCoreActorsNum = BoundCoreActors.Num(); for (int i = 0; i < BoundCoreActorsNum; i++) { BoundCoreActors[i]->SetActorLocation(OldPositions[i]); } } void ABoundCorePossessionController::ResetParticles() { int BoundCoreActorsNum = BoundCoreActors.Num(); for (int i = 0; i < BoundCoreActorsNum; i++) { TArray children; BoundCoreActors[i]->GetComponents (children); if (children.Num() > 0) { for (int j = 0; j < children.Num(); j++) { int MaterialCount = children[j]->GetNumMaterials(); if (MaterialCount == 1) { children[j]->DestroyComponent(); BoundCoreActorsMainCharacter[i]->AbilitySwapHasParticle = false; } } } } AbilitySwapCharacter(); } void ABoundCorePossessionController::AbilitySwapCharacter() { TArray BoundCoreCharacters; TArray BoundCoreCharacterControllers; int BoundCoreActorsNum = BoundCoreActors.Num(); for (int i = 0; i < BoundCoreActorsNum; i++) { ACharacter* NewCharacter = Cast (BoundCoreActors[i]); BoundCoreCharacters.Add(NewCharacter); } for (int i = 0; i < BoundCoreActorsNum; i++) { AController* NewController = BoundCoreCharacters[i]->GetController(); BoundCoreCharacterControllers.Add(NewController); } TArray OldPositions = GetOldPositionsAndReset(); TArray OldRotations = GetOldRotationsAndReset(); for (int i = 0; i < BoundCoreActorsNum; i++) { if (i == 0) { BoundCoreCharacters[i]->SetActorLocation(OldPositions[1]); //BoundCoreCharacterControllers[i]->Possess(BoundCoreCharacters[1]); } else if (i == 1) { BoundCoreCharacters[i]->SetActorLocation(OldPositions[0]); //BoundCoreCharacterControllers[i]->Possess(BoundCoreCharacters[0]); } } SetNewRotations(OldRotations); }