HAxis sos

This commit is contained in:
guus
2018-08-11 16:46:35 +02:00
commit 510654f8a1
480 changed files with 54126 additions and 0 deletions

View File

@@ -0,0 +1,37 @@
#include "UnrealProject.h"
#include "AnimationProxy.h"
bool FMainAnimProxy::Evaluate(FPoseContext& pose)
{
// Evalueate the animation pose according to the blueprint
if(GetRootNode() != NULL)
{
GetRootNode()->Evaluate(pose);
}
// Now set bone scales for character customizations
SetBoneScale(boneNames[0], FVector(charCustomization.headScale), pose);
SetBoneScale(boneNames[1], FVector(1, charCustomization.legThicknessYScale, charCustomization.legThicknessZScale), pose);
SetBoneScale(boneNames[2], FVector(1, charCustomization.legThicknessYScale, charCustomization.legThicknessZScale), pose);
SetBoneScale(boneNames[3], FVector(charCustomization.leftArmScale), pose);
SetBoneScale(boneNames[4], FVector(charCustomization.rightArmScale), pose);
SetBoneScale(boneNames[5], FVector(charCustomization.torsoScale), pose);
SetBoneScale(boneNames[6], FVector(charCustomization.overallScale), pose);
return true;
}
void FMainAnimProxy::SetBoneScale(const FName boneName, const FVector scale, FPoseContext& pose)
{
int32 boneIndex = this->GetSkelMeshComponent()->GetBoneIndex(boneName);
// Check if bone is in the skeleton.
if(boneIndex != INDEX_NONE)
{
FTransform& boneTransform = pose.Pose[FCompactPoseBoneIndex(boneIndex)];
boneTransform.SetScale3D(scale);
}
}

View File

@@ -0,0 +1,22 @@
#pragma once
#include "Animation/AnimInstanceProxy.h"
#include "PlayerSetupState.h"
// Animation instance proxy that sets bone scales for character customizations
// This animation proxy just calculates the animation blueprint's pose and then applies bone scaled to them based on character customizations
struct FMainAnimProxy : FAnimInstanceProxy
{
// The parent animation
FCharacterCustomization charCustomization;
// Head
// Thigh L
// Thigh R
// UpperArm L
// UpperArm R
// Root
FName boneNames[7];
virtual bool Evaluate(FPoseContext& pose) override;
void SetBoneScale(const FName boneName, const FVector scale, FPoseContext& pose);
};

View File

@@ -0,0 +1,64 @@
// Project Lab - NHTV Igad
#include "UnrealProject.h"
#include "BTTaskNodeClimb.h"
#include "EnemyAIController.h"
#include "BehaviorTree/BehaviorTree.h"
#include "BehaviorTree/BlackboardComponent.h"
#include "BehaviorTree/Blackboard/BlackboardKeyType_Object.h"
#include "BehaviorTree/Blackboard/BlackboardKeyType_Vector.h"
UBTTaskNodeClimb::UBTTaskNodeClimb()
{
NodeName = "Climb";
bNotifyTick = true;
// accept only actors and vectors
BlackboardKey.AddObjectFilter(this, GET_MEMBER_NAME_CHECKED(UBTTaskNodeClimb, BlackboardKey), AActor::StaticClass());
BlackboardKey.AddVectorFilter(this, GET_MEMBER_NAME_CHECKED(UBTTaskNodeClimb, BlackboardKey));
directionKey.AddVectorFilter(this, GET_MEMBER_NAME_CHECKED(UBTTaskNodeClimb, directionKey));
directionKey.AddObjectFilter(this, GET_MEMBER_NAME_CHECKED(UBTTaskNodeClimb, directionKey), AActor::StaticClass());
}
void UBTTaskNodeClimb::InitializeFromAsset(UBehaviorTree& Asset)
{
Super::InitializeFromAsset(Asset);
UBlackboardData &BBAsset = *GetBlackboardAsset();
BlackboardKey.ResolveSelectedKey(BBAsset);
directionKey.ResolveSelectedKey(BBAsset);
}
EBTNodeResult::Type UBTTaskNodeClimb::ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory)
{
EBTNodeResult::Type NodeResult = EBTNodeResult::InProgress;
NodeResult = PeformClimbTask(OwnerComp, NodeMemory);
return NodeResult;
}
EBTNodeResult::Type UBTTaskNodeClimb::PeformClimbTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory)
{
const UBlackboardComponent* MyBlackboard = OwnerComp.GetBlackboardComponent();
AAIController* MyController = OwnerComp.GetAIOwner();
AEnemyAIController* cont = Cast<AEnemyAIController>(OwnerComp.GetAIOwner());
EBTNodeResult::Type NodeResult = EBTNodeResult::Failed;
if (cont && MyBlackboard)
{
const FVector TargetLocation = MyBlackboard->GetValue<UBlackboardKeyType_Vector>(BlackboardKey.GetSelectedKeyID());
FVector TargetDirection = FVector::ZeroVector;
MyBlackboard->GetLocationFromEntry(directionKey.GetSelectedKeyID(), TargetDirection);
if (cont->VerticleMoveTo(TargetLocation, TargetDirection,AcceptableRadius ))
{
NodeResult = EBTNodeResult::Succeeded;
}
else NodeResult = EBTNodeResult::InProgress;
}
return NodeResult;
}
void UBTTaskNodeClimb::TickTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory, float DeltaSeconds)
{
const EBTNodeResult::Type NodeResult = PeformClimbTask(OwnerComp, NodeMemory);
if (NodeResult != EBTNodeResult::InProgress)
{
FinishLatentTask(OwnerComp, NodeResult);
}
}

View File

@@ -0,0 +1,36 @@
// Project Lab - NHTV Igad
#pragma once
#include "BehaviorTree/Tasks/BTTask_BlackboardBase.h"
#include "BTTaskNodeClimb.generated.h"
/**
*
*/
UCLASS(config = Game)
class UNREALPROJECT_API UBTTaskNodeClimb : public UBTTaskNode
{
GENERATED_BODY()
public :
UPROPERTY(config, Category = Node, EditAnywhere, meta = (ClampMin = "0.0"))
float AcceptableRadius;
FName GetSelectedBlackboardKey() const;
UBTTaskNodeClimb();
virtual EBTNodeResult::Type ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory) override;
virtual void TickTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory, float DeltaSeconds) override;
virtual void InitializeFromAsset(UBehaviorTree& Asset) override;
UPROPERTY(EditAnywhere, Category = Blackboard)
FBlackboardKeySelector directionKey;
UPROPERTY(EditAnywhere, Category = Blackboard)
FBlackboardKeySelector BlackboardKey;
protected:
EBTNodeResult::Type PeformClimbTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory);
};
FORCEINLINE FName UBTTaskNodeClimb::GetSelectedBlackboardKey() const
{
return directionKey.SelectedKeyName;
}

View File

@@ -0,0 +1,56 @@
// Project Lab - NHTV Igad
#include "UnrealProject.h"
#include "BTTaskNodeJumpFence.h"
#include "EnemyAIController.h"
#include "BehaviorTree/BehaviorTree.h"
#include "BehaviorTree/BlackboardComponent.h"
#include "BehaviorTree/Blackboard/BlackboardKeyType_Object.h"
#include "BehaviorTree/Blackboard/BlackboardKeyType_Vector.h"
UBTTaskNodeJumpFence::UBTTaskNodeJumpFence()
{
NodeName = "Jump Fence";
bNotifyTick = true;
BlackboardKey.AddObjectFilter(this, GET_MEMBER_NAME_CHECKED(UBTTaskNodeJumpFence, BlackboardKey), AActor::StaticClass());
BlackboardKey.AddVectorFilter(this, GET_MEMBER_NAME_CHECKED(UBTTaskNodeJumpFence, BlackboardKey));
}
void UBTTaskNodeJumpFence::InitializeFromAsset(UBehaviorTree& asset)
{
Super::InitializeFromAsset(asset);
UBlackboardData& BBAsset = *GetBlackboardAsset();
BlackboardKey.ResolveSelectedKey(BBAsset);
}
EBTNodeResult::Type UBTTaskNodeJumpFence::ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory)
{
EBTNodeResult::Type NodeResult = EBTNodeResult::InProgress;
NodeResult = PefromJumpFenceTask(OwnerComp, NodeMemory);
return NodeResult;
}
EBTNodeResult::Type UBTTaskNodeJumpFence::PefromJumpFenceTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory)
{
const UBlackboardComponent* MyBlackboard = OwnerComp.GetBlackboardComponent();
AAIController* MyController = OwnerComp.GetAIOwner();
AEnemyAIController* cont = Cast<AEnemyAIController>(OwnerComp.GetAIOwner());
EBTNodeResult::Type NodeResult = EBTNodeResult::Failed;
if (cont && MyBlackboard)
{
const FVector TargetLocation = MyBlackboard->GetValue<UBlackboardKeyType_Vector>(BlackboardKey.GetSelectedKeyID());
FVector TargetDirection = FVector::ZeroVector;
if (cont->JumpFence(TargetLocation))
{
NodeResult = EBTNodeResult::Succeeded;
}
else NodeResult = EBTNodeResult::InProgress;
}
return NodeResult;
}
void UBTTaskNodeJumpFence::TickTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory, float DeltaSeconds)
{
const EBTNodeResult::Type NodeResult = PefromJumpFenceTask(OwnerComp, NodeMemory);
if (NodeResult != EBTNodeResult::InProgress)
{
FinishLatentTask(OwnerComp, NodeResult);
}
}

View File

@@ -0,0 +1,25 @@
// Project Lab - NHTV Igad
#pragma once
#include "BehaviorTree/BTTaskNode.h"
#include "BTTaskNodeJumpFence.generated.h"
/**
*
*/
UCLASS()
class UNREALPROJECT_API UBTTaskNodeJumpFence : public UBTTaskNode
{
GENERATED_BODY()
public:
UBTTaskNodeJumpFence();
virtual EBTNodeResult::Type ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory) override;
virtual void TickTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory, float DeltaSeconds) override;
virtual void InitializeFromAsset(UBehaviorTree& Asset) override;
UPROPERTY(EditAnywhere, Category = Blackboard)
FBlackboardKeySelector BlackboardKey;
protected:
EBTNodeResult::Type PefromJumpFenceTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory);
};

View File

@@ -0,0 +1,178 @@
// Project Lab - NHTV Igad
#include "UnrealProject.h"
#include "EnemyAIController.h"
#include "EnemyBase.h"
#include "NetworkCharacter.h"
#include "Navigation/CrowdFollowingComponent.h"
#include "BehaviorTree/BehaviorTree.h"
#include "BehaviorTree/BlackboardComponent.h"
#include "BehaviorTree/BehaviorTreeComponent.h"
#include "BehaviorTree/BlackBoard/BlackboardKeyAllTypes.h"
#include "DrawDebugHelpers.h"
AEnemyAIController::AEnemyAIController(const FObjectInitializer& PCIP)
//: Super(PCIP.SetDefaultSubobjectClass<UCrowdFollowingComponent>(TEXT("PathFollowingComponent")))
{
blackBoardComp = CreateDefaultSubobject<UBlackboardComponent>(FName("BlackBoardComp"));
behaviorTreeComp = CreateDefaultSubobject<UBehaviorTreeComponent>(FName("BehaviorTreeComp"));
climbSpeed = 1.0f;
}
void AEnemyAIController::Tick(float deltaTime)
{
Super::Tick(deltaTime);
}
void AEnemyAIController::Possess(APawn* pawn)
{
Super::Possess(pawn);
AEnemyBase* enemy = Cast<AEnemyBase>(pawn);
if (enemy &&enemy->treeBehavior)
{
if (!enemy->treeBehavior->BlackboardAsset)
{
RERROR("There is no blackboard asset in the behavior tree");
return;
}
blackBoardComp->InitializeBlackboard(*(enemy->treeBehavior->BlackboardAsset));
behaviorTreeComp->StartTree(*enemy->treeBehavior);
}
}
bool AEnemyAIController::VerticleMoveTo(FVector destination, FVector direction,float acceptRadius)
{
FVector location =GetPawn()->GetActorLocation();
FVector dest = destination;
dest -= location;
dest *= direction;
FVector newDest= dest;
float height = newDest.Size();
if (height < acceptRadius&&destination.Z <location.Z)
{
// GetCharacter()->GetCharacterMovement()->GravityScale = 1;
return true;
}
GetPawn()->SetActorLocation(FVector(location.X+(direction.X*10), location.Y+(direction.Y*10) , (location.Z)+(direction.Z*10)));
GetCharacter()->GetCharacterMovement()->GravityScale = 0;
return false;
}
bool AEnemyAIController::JumpFence(FVector destination)
{
TArray<FHitResult> result;
UNavigationSystem* navsys = UNavigationSystem::GetCurrent(GetWorld());
if (!navsys)
{
RERROR("There is no navigation system in the current level, please check if there is one or contact a developer!");
return false;
}
ANPCBase* character = Cast<ANPCBase>(GetPawn());
FVector direction;
FNavLocation navLocation;
character->SetActorEnableCollision(false);
DrawDebugLine(GetWorld(), GetPawn()->GetActorLocation(), GetPawn()->GetActorLocation() + GetActorUpVector()*-10000.0f, FColor(255, 0, 0),false, -1, 0, 12.333);
FCollisionQueryParams collisionParams;
collisionParams.AddIgnoredActor(this->GetPawn());
GetWorld()->LineTraceMultiByChannel(result, GetPawn()->GetActorLocation(), GetPawn()->GetActorLocation() + GetActorUpVector()*-10000.0f, ECollisionChannel::ECC_WorldStatic, collisionParams);
for (int i = 0; i < result.Num(); i++)
{
if(result[i].ImpactPoint!=GetPawn()->GetActorLocation())
{
if (!navsys->ProjectPointToNavigation(GetPawn()->GetActorLocation(), navLocation))
{
continue;
}
GetCharacter()->GetCharacterMovement()->GravityScale = 1;
SetBool(false,FName("ClimbKey"));
navsys->SimpleMoveToLocation(this,destination);
character->PlayNormalAnimation();
character->SetActorEnableCollision(true);
return true;
}
}
character->PlayFencAnimation();
direction = destination - GetPawn()->GetActorLocation();
direction.Normalize();
GetPawn()->SetActorLocation(GetPawn()->GetActorLocation()+(direction * 10));
return false;
}
void AEnemyAIController::BeginInactiveState()
{
Super::BeginInactiveState();
}
void AEnemyAIController::SetVector(FVector vector, FName name)
{
if (blackBoardComp)
{
blackBoardComp->SetValueAsVector(name, (vector));
}
}
void AEnemyAIController::SetBool(bool boolean, FName name)
{
if (blackBoardComp)
{
blackBoardComp->SetValueAsBool(name, (boolean));
}
}
void AEnemyAIController::SetTarget(ANetworkCharacter* player)
{
if (blackBoardComp)
{
blackBoardComp->SetValueAsObject((FName("Target")), (player));
}
}
ANetworkCharacter* AEnemyAIController::GetTarget()
{
if (blackBoardComp)
{
return Cast<ANetworkCharacter>(blackBoardComp->GetValue<UBlackboardKeyType_Object>(FName("Target")));
}
return nullptr;
}
FVector AEnemyAIController::GetLocationTarget()
{
if (blackBoardComp)
{
return FVector(blackBoardComp->GetValue<UBlackboardKeyType_Vector>(FName("TargetLocation")));
}
return FVector();
}
FVector AEnemyAIController::GetHomeLocation()
{
if (blackBoardComp)
{
return FVector(blackBoardComp->GetValue<UBlackboardKeyType_Vector>(FName("HomeLocation")));
}
return FVector();
}
FVector AEnemyAIController::GetSelfLocation()
{
if (blackBoardComp)
{
return FVector(blackBoardComp->GetValue<UBlackboardKeyType_Vector>(FName("SelfLocation")));
}
return FVector();
}
bool AEnemyAIController::GetClimbKey()
{
if (blackBoardComp)
{
return blackBoardComp->GetValue<UBlackboardKeyType_Bool>((FName("ClimbKey")));
}
else return false;
}

View File

@@ -0,0 +1,56 @@
// Project Lab - NHTV Igad
#pragma once
#include "AIController.h"
#include "EnemyAIController.generated.h"
/**
*
*/
UCLASS()
class UNREALPROJECT_API AEnemyAIController : public AAIController
{
GENERATED_BODY()
public:
AEnemyAIController(const FObjectInitializer& PCIP);
UPROPERTY(transient)
class UBlackboardComponent* blackBoardComp;
UPROPERTY(transient)
class UBehaviorTreeComponent* behaviorTreeComp;
UPROPERTY(transient)
float climbSpeed;
virtual void Tick(float deltaTime)override;
virtual void Possess(APawn* pawn) override;
virtual void BeginInactiveState() override;
bool VerticleMoveTo(FVector destination,FVector direction, float acceptRadius);
bool JumpFence(FVector destination);
UFUNCTION(BlueprintCallable, Category = Behavior)
void SetVector(FVector vector, FName name);
UFUNCTION(BlueprintCallable, Category = Behavior)
void SetBool(bool boolean, FName name);
UFUNCTION(BlueprintCallable, Category = Behavior)
void SetTarget(class ANetworkCharacter* player);
UFUNCTION(BlueprintCallable, Category = Behavior)
class ANetworkCharacter* GetTarget();
UFUNCTION(BlueprintCallable, Category = Behavior)
FVector GetLocationTarget();
UFUNCTION(BlueprintCallable, Category = Behavior)
FVector GetHomeLocation();
UFUNCTION(BlueprintCallable, Category = Behavior)
FVector GetSelfLocation();
// UFUNCTION(BlueprintCallable, Category = Behavior)
// bool GetEnableTree();
UFUNCTION(BlueprintCallable, Category = Behavior)
bool GetClimbKey();
protected:
uint8 targetkey;
};

View File

@@ -0,0 +1,96 @@
// Project Lab - NHTV Igad
#include "UnrealProject.h"
#include "BossBase.h"
#include "MusicPlayer.h"
#include "SpawnerBase.h"
#include "NetworkPlayer.h"
#include "KingOfTheHillGameMode.h"
#include "KOTHBossSpawner.h"
ABossBase::ABossBase()
{
PrimaryActorTick.bCanEverTick = true;
}
void ABossBase::BeginPlay()
{
Super::BeginPlay();
m_usesMana = false;
m_musicPlayer = nullptr;
// Search for a music player in the world.
for (TActorIterator<AMusicPlayer> actorItr(GetWorld()); actorItr; ++actorItr)
{
m_musicPlayer = *actorItr;
break;
}
if (Role != ROLE_Authority)
return;
}
void ABossBase::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
Super::EndPlay(EndPlayReason);
if (Role != ROLE_Authority)
return;
// Stop playing boss music.
if (m_musicPlayer != nullptr)
m_musicPlayer->SetInCombat(false);
}
void ABossBase::Tick(float deltaTime)
{
Super::Tick(deltaTime);
if (Role != ROLE_Authority)
return;
if((!IsPendingKill() || !IsPendingKill()) && GetTeam() < 5)
{
AKOTHBossSpawner* bSpawner = Cast<AKOTHBossSpawner>(m_spawn);
AKingOfTheHillGameMode* kothMode = Cast<AKingOfTheHillGameMode>(GetWorld()->GetAuthGameMode());
if(kothMode&&bSpawner)
kothMode->AddScore(GetTeam(), deltaTime);
}
}
void ABossBase::m_Engaged()
{
// Set music to combat music.
if (m_musicPlayer != nullptr)
m_musicPlayer->SetInCombat(true);
}
void ABossBase::m_Disengaged()
{
// Set music to regular music.
if (m_musicPlayer != nullptr)
m_musicPlayer->SetInCombat(false);
}
void ABossBase::NativeOnKilled(class ANetworkCharacter* killer, class UAbilityInfo* ability)
{
Super::NativeOnKilled(killer, ability);
if (Role != ROLE_Authority)
return;
if (m_spawn &&m_spawn->possesable)
{
// m_spawn->CaptureCamp(killer->GetTeam());
//AKOTHBossSpawner* bSpawner = Cast<AKOTHBossSpawner>(m_spawn);
//AKingOfTheHillGameMode* kothMode = Cast<AKingOfTheHillGameMode>(GetWorld()->GetAuthGameMode());
//if (kothMode&&bSpawner)
//{
/* for (TActorIterator<ASpawnerBase>actorIt(GetWorld()); actorIt; ++actorIt)
{
ASpawnerBase *spawn = *actorIt;
if(!spawn->possesable)
spawn->SetTeam(killer->GetTeam());
}
}*/
}
}

View File

@@ -0,0 +1,28 @@
// Project Lab - NHTV Igad
#pragma once
#include "Creatures/NPCBase.h"
#include "BossBase.generated.h"
/**
*
*/
UCLASS()
class UNREALPROJECT_API ABossBase : public ANPCBase
{
GENERATED_BODY()
public:
ABossBase();
virtual void BeginPlay() override;
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
virtual void Tick(float deltaTime) override;
virtual void NativeOnKilled(class ANetworkCharacter* killer, class UAbilityInfo* ability) override;
protected:
virtual void m_Engaged();
virtual void m_Disengaged();
float timer;
private:
UPROPERTY()
class AMusicPlayer* m_musicPlayer;
};

View File

@@ -0,0 +1,300 @@
#include "UnrealProject.h"
#include "SpawnerBase.h"
#include "CharacterBase.h"
#include "ItemBase.h"
#include "BaseSkillObject.h"
#include "WiebertAnimation.h"
#include "DefaultGameState.h"
#include "MainCharacterAnimation.h"
#include "SkillTreeState.h"
ACharacterBase::ACharacterBase()
{
m_team = 0;
bReplicates = true;
visionRadius = 1000;
}
void ACharacterBase::BeginPlay()
{
Super::BeginPlay();
// If this actor is attached to a spawner base, it must be ignored
AActor* const parent = GetAttachParentActor();
if (parent != nullptr && parent->IsA<ASpawnerBase>())
return;
// Register to the minimap
UWorld* const world = GetWorld();
if (IsValid(world))
{
ADefaultGameState* const gameState = Cast<ADefaultGameState>(world->GetGameState());
if (IsValid(gameState))
{
const FVector location = GetActorLocation();
minimapHandle.position = FVector2D(location.X, location.Y);
minimapHandle.character = this;
gameState->minimapQuadtree.AddObject(minimapHandle);
}
}
}
void ACharacterBase::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
Super::EndPlay(EndPlayReason);
// Unregister to the minimap
ADefaultGameState* const gameState = Cast<ADefaultGameState>(GetWorld()->GetGameState());
if (IsValid(gameState) && minimapHandle.root)
gameState->minimapQuadtree.RemoveObject(minimapHandle);
minimapHandle.root = nullptr;
minimapHandle.node = nullptr;
minimapHandle.character = nullptr;
}
void ACharacterBase::Tick(float deltaTime)
{
Super::Tick(deltaTime);
const FVector location = GetActorLocation();
minimapHandle.position = FVector2D(location.X, location.Y);
}
void ACharacterBase::m_EquipSkills_Implementation(const TArray<UBaseSkillObject*>& skills)
{
for(UBaseSkillObject* skill : skills)
{
// Check if not yet equiped
if(!m_equipedSkills.Contains(skill))
{
AItemBase::CreateItemsFromSkill(GetWorld(), skill, this);
m_equipedSkills.Add(skill);
}
}
}
void ACharacterBase::EquipSkills(const TArray<UBaseSkillObject*>& skills)
{
m_EquipSkills(skills);
}
void ACharacterBase::EquipSkillsFromSkillTreeState(const struct FSkillTreeState& skState)
{
TArray<UBaseSkillObject*> skillObjects;
for(const FSkillTreeStateObject& obj : skState.objects)
{
UBaseSkillObject* skillObj = obj.skillObject->GetDefaultObject<UBaseSkillObject>();
if(!skillObj)
continue;
skillObjects.Add(skillObj);
}
m_EquipSkills(skillObjects);
}
void ACharacterBase::EquipItems_Implementation(const TArray<TSubclassOf<AItemBase>>& itemClasses)
{
for(auto& itemClass : itemClasses)
{
EquipItem_Implementation(itemClass);
}
}
void ACharacterBase::EquipItem_Implementation(TSubclassOf<class AItemBase> itemClass)
{
if(itemClass == nullptr)
return;
AItemBase* item = GetWorld()->SpawnActor<AItemBase>(itemClass);
AItemBase* existing = AItemBase::CheckSlotOccupied(item->type, this);
if(existing)
existing->Destroy();
if(item)
{
if(!item->AttachItemToCharacter(this))
{
item->Destroy();
}
}
}
void ACharacterBase::SendInitialAppearance(APlayerController* pc)
{
if(Role == ROLE_Authority)
{
m_ReceiveInitialAppearance(pc, GetEquipedSkills(), GetCharacterCustomization());
}
}
void ACharacterBase::m_ReceiveInitialAppearance_Implementation(APlayerController* pc, const TArray<class UBaseSkillObject*>& itemClasses, const FCharacterCustomization& cc)
{
APlayerController* localPC = GetGameInstance()->GetFirstLocalPlayerController();
if(pc == localPC)
{
EquipSkills(itemClasses);
SetCustomizations_Implementation(cc);
}
}
void ACharacterBase::Destroyed()
{
auto destroyItems = m_items;
for(auto item : destroyItems)
{
if(IsValid(item))
{
item->Destroy();
}
}
Super::Destroyed();
}
TArray<TSubclassOf<AItemBase>> ACharacterBase::GetEquipedItemClasses() const
{
TArray<TSubclassOf<AItemBase>> ret;
for(auto item : m_items)
{
ret.Add(item->GetClass());
}
return ret;
}
const TArray<class AItemBase*>& ACharacterBase::GetEquipedItems() const
{
return m_items;
}
const FCharacterCustomization& ACharacterBase::GetCharacterCustomization() const
{
static FCharacterCustomization dummy;
USkeletalMeshComponent* skMesh = GetMesh();
if(skMesh)
{
UWiebertAnimation* animBP = Cast<UWiebertAnimation>(skMesh->GetAnimInstance());
if(animBP)
{
return animBP->charCustomization;
}
else
{
UMainCharacterAnimation* charBP = Cast<UMainCharacterAnimation>(skMesh->GetAnimInstance());
if (charBP)
{
return charBP->charCustomization;
}
}
}
return dummy;
}
const TArray<class UBaseSkillObject*>& ACharacterBase::GetEquipedSkills() const
{
return m_equipedSkills;
}
void ACharacterBase::UnequipSkills_Implementation(const TArray<UBaseSkillObject*>& skills)
{
for(auto skill : skills)
{
if(m_equipedSkills.Contains(skill))
{
TArray<AItemBase*> items;
m_mappedItems.MultiFind(skill, items);
for(auto item : items)
item->Destroy();
m_equipedSkills.Remove(skill);
}
}
}
void ACharacterBase::ClearEquipment_Implementation()
{
auto clearItems = m_items;
for(auto item : clearItems)
{
if(IsValid(item))
{
item->Destroy();
}
}
m_mappedItems.Reset();
m_equipedSkills.SetNum(0);
m_items.SetNum(0);
}
void ACharacterBase::SetCustomizations_Implementation(const FCharacterCustomization& cc)
{
USkeletalMeshComponent* skMesh = GetMesh();
if(skMesh)
{
UWiebertAnimation* animBP = Cast<UWiebertAnimation>(skMesh->GetAnimInstance());
if(animBP)
{
animBP->SetCharacterCustomization(cc);
}
else
{
UMainCharacterAnimation* charBP = Cast<UMainCharacterAnimation>(skMesh->GetAnimInstance());
if (charBP)
{
charBP->SetCharacterCustomization(cc);
}
}
}
else
{
GERROR("Can't set customization, no skeletal mesh on character");
}
}
void ACharacterBase::m_OnItemAdded(AItemBase* item)
{
// Add item to list of items assigned to given skill object
if(item->skillObject)
m_mappedItems.Add(item->skillObject, item);
m_items.Add(item);
}
void ACharacterBase::m_OnItemRemoved(AItemBase* item)
{
// Remove mapped item
m_mappedItems.RemoveSingle(item->skillObject, item);
m_items.Remove(item);
}
void ACharacterBase::m_OnRep_Team()
{
}
int32 ACharacterBase::GetTeam() const
{
return m_team;
}
void ACharacterBase::SetTeam(int32 team)
{
check(Role == ROLE_Authority); // Server only call
m_team = team;
m_OnRep_Team();
}
void ACharacterBase::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
DOREPLIFETIME(ACharacterBase, m_team);
DOREPLIFETIME(ACharacterBase, playerName);
}
void ACharacterBase::RegisterEffect(class AEffect* effect)
{
if(effect != nullptr)
m_effects.Add(effect);
}
void ACharacterBase::UnRegisterEffect(class AEffect* effect)
{
if(effect == nullptr)
{
FWARNING("invalid effect is unregistering");
return;
}
m_effects.Remove(effect);
}
TArray<class AEffect*> ACharacterBase::GetEffects()
{
return m_effects;
}

View File

@@ -0,0 +1,94 @@
#pragma once
#include "GameFramework/Character.h"
#include "PlayerSetupState.h"
#include "MiniMap.h"
#include "CharacterBase.generated.h"
UCLASS()
class ACharacterBase : public ACharacter
{
GENERATED_BODY()
friend class AItemBase;
public:
ACharacterBase();
virtual void BeginPlay() override;
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
virtual void Tick(float deltaTime) override;
UFUNCTION(BlueprintCallable, Category = "Appearance")
void EquipSkills(const TArray<UBaseSkillObject*>& skills);
UFUNCTION(BlueprintCallable, Category = "Appearance")
void EquipSkillsFromSkillTreeState(const struct FSkillTreeState& skState);
UFUNCTION(NetMulticast, Reliable)
void EquipItems(const TArray<TSubclassOf<class AItemBase>>& itemClasses);
UFUNCTION(NetMulticast, Reliable)
void EquipItem(TSubclassOf<class AItemBase> itemClasses);
void SendInitialAppearance(APlayerController* pc);
void Destroyed() override;
UFUNCTION(BlueprintCallable, NetMulticast, Reliable, Category = "Appearance")
void UnequipSkills(const TArray<UBaseSkillObject*>& skills);
UFUNCTION(BlueprintCallable, NetMulticast, Reliable, Category = "Appearance")
void ClearEquipment();
UFUNCTION(BlueprintCallable, NetMulticast, Reliable, Category = "Appearance")
void SetCustomizations(const FCharacterCustomization& cc);
UFUNCTION(BlueprintCallable, Category = "Appearance")
const TArray<class UBaseSkillObject*>& GetEquipedSkills() const;
UFUNCTION(BlueprintCallable, Category = "Appearance")
const TArray<class AItemBase*>& GetEquipedItems() const;
UFUNCTION(BlueprintCallable, Category = "Appearance")
TArray<TSubclassOf<class AItemBase>> GetEquipedItemClasses() const;
UFUNCTION(BlueprintCallable, Category = "Appearance")
const FCharacterCustomization& GetCharacterCustomization() const;
UFUNCTION(BlueprintCallable, Category = "Team")
int32 GetTeam() const;
UFUNCTION(BlueprintCallable, Category = "Team")
virtual void SetTeam(int32 team);
// Tracking functions for effects on characters
UFUNCTION(BlueprintCallable, Category = "Effect")
void RegisterEffect(class AEffect* effect);
UFUNCTION(BlueprintCallable, Category = "Effect")
void UnRegisterEffect(class AEffect* effect);
UFUNCTION(BlueprintCallable, Category = "Effect")
TArray<class AEffect*> GetEffects();
// The name of the player that controls this unit (Only for ghosts, players and illusions)
UPROPERTY(BlueprintReadOnly, Replicated)
FString playerName;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Vision")
float visionRadius;
MiniMap::MinimapHandle minimapHandle;
private:
// Trigerred from RequestInitialAppearance send back to the client
UFUNCTION(NetMulticast, Reliable)
void m_ReceiveInitialAppearance(APlayerController* pc, const TArray<class UBaseSkillObject*>& itemClasses, const FCharacterCustomization& cc);
// Internal usage EquipSkills to allow multiple ways to call this function from blueprints
UFUNCTION(NetMulticast, Reliable)
void m_EquipSkills(const TArray<UBaseSkillObject*>& skills);
void m_OnItemAdded(AItemBase* item);
void m_OnItemRemoved(AItemBase* item);
protected:
UFUNCTION()
virtual void m_OnRep_Team();
UPROPERTY(ReplicatedUsing=m_OnRep_Team)
int32 m_team;
// Maps skills to the items it spawned
TMultiMap<class UBaseSkillObject*, class AItemBase*> m_mappedItems;
TArray<class UBaseSkillObject*> m_equipedSkills;
UPROPERTY()
TArray<class AItemBase*> m_items;
TArray<class AEffect*> m_effects;
};

View File

@@ -0,0 +1,190 @@
// Project Lab - NHTV Igad
#include "UnrealProject.h"
#include "SpawnerBase.h"
#include "EnemyBase.h"
#include "AbilityInfo.h"
#include "NetworkPlayer.h"
#include "GeneralEnemy.h"
#include "BehaviorTree/EnemyAIController.h"
#include "BehaviorTree/BehaviorTree.h"
#include "MinionAnimInstance.h"
AEnemyBase::AEnemyBase()
{
PrimaryActorTick.bCanEverTick = true;
finnishedAttack = false;
informGeneralTime = 2.0f;
m_tempTarget = nullptr;
// AIControllerClass = AEnemyAIController::StaticClass();
}
void AEnemyBase::BeginPlay()
{
Super::BeginPlay();
specialAbilityChance = m_ReCalcChance(specialAbilityChance);
enemycontroller = Cast<AEnemyAIController>(GetController());
if (enemycontroller && m_spawn)
{
enemycontroller->SetBool(true, FName("ClimbKey"));
enemycontroller->SetVector(FVector(0, 0, 1), FName("ClimbDirection"));
enemycontroller->SetVector(m_spawn->GetActorLocation() + FVector(0, 0, 100), FName("ClimbLocation"));
}
else
{
FActorSpawnParameters SpawnInfo;
SpawnInfo.Instigator = Instigator;
SpawnInfo.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
SpawnInfo.OverrideLevel = GetLevel();
SpawnInfo.ObjectFlags |= RF_Transient; // We never want to save AI controllers into a map
AController* NewController = GetWorld()->SpawnActor<AController>(AEnemyAIController::StaticClass(), GetActorLocation(), GetActorRotation(), SpawnInfo);
if (NewController != NULL)
{
// if successful will result in setting this->Controller
// as part of possession mechanics
NewController->Possess(this);
}
enemycontroller = Cast<AEnemyAIController>(GetController());
if (enemycontroller && m_spawn)
{
if (m_spawn->SpawnLocation.Num() > 0)
{
PlayClimbingAnimation();
enemycontroller->SetBool(true, FName("ClimbKey"));
enemycontroller->SetVector(FVector(0, 0, 1), FName("ClimbDirection"));
enemycontroller->SetVector(m_spawn->GetActorLocation() + FVector(0, 0, 100), FName("ClimbLocation"));
}
}
else
{
// RERROR("There is no valid controller on this enemy");
}
}
hasSpawned = false;
}
void AEnemyBase::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
Super::EndPlay(EndPlayReason);
general = nullptr;
if (m_spawn)
{
if (m_spawn->hasGeneral)
{
m_spawn->formationEnemies.Remove(this);
}
}
}
void AEnemyBase::Tick(float deltaTime)
{
Super::Tick(deltaTime);
if (Role != ROLE_Authority)
{
return;
}
m_confusionTimer -= deltaTime;
if (!IsA(AGeneralEnemy::StaticClass()))
m_hasGeneral = hasGeneral;
if (!hasGeneral && enemycontroller && enemycontroller->IsA(AEnemyAIController::StaticClass()))
{
enemycontroller->SetBool(false, FName("EnableTree"));
}
if (IsValid(target))
{
if (hasGeneral)
{
m_informGeneralTimer -= deltaTime;
if (m_informGeneralTimer < 0.0f&&IsValid(general))
InformGeneral();
}
else
{
SwitchAgro();
}
}
else if(!hasGeneral)
{
FVector randpos = FMath::VRand();
randpos.Z = 0.0f;
float randomRange = FMath::FRandRange(m_spawn->aggroRadius / 4, m_spawn->aggroRadius);
randpos = randpos*randomRange;
MoveToPointSlow(randpos + m_spawn->GetActorLocation(), 50.0f);
}
}
void AEnemyBase::InformGeneral()
{
if (!IsValid(general) || !IsValid(target))
return;
if (FVector::DistSquared(m_spawn->GetActorLocation(), target->GetActorLocation()) > m_spawn->deaggroRadius*m_spawn->deaggroRadius)
return;
if( !IsValid(general->target))
{
general->target = m_tempTarget;
ChangeNPCAnimation((uint8)EMinionAnimState::MAS_Pointing);
//CHANGEANIMATION(EMinionAnimState::MAS_Pointing);
m_informGeneralTimer = informGeneralTime;
m_tempTarget = nullptr;
}
}
void AEnemyBase::SwitchAgro()
{
if (m_spawn->GetNearbyPlayers().Num() <= 1)
return;
float mostDamage =0.0f;
ANetworkCharacter* character = nullptr;
for (int i = 0; i < m_spawn->GetNearbyPlayers().Num(); i++)
{
if (m_spawn->GetNearbyPlayers()[i]->GetTotalDamage()>mostDamage)
{
mostDamage = m_spawn->GetNearbyPlayers()[i]->GetTotalDamage();
character = m_spawn->GetNearbyPlayers()[i];
}
}
if(IsValid(character))
this->target = character;
}
void AEnemyBase::ConfusionBehavior()
{
FVector randpos = FMath::VRand();
randpos.Z = 0.0f;
float randomRange = FMath::FRandRange(m_spawn->aggroRadius / 4, m_spawn->aggroRadius);
randpos = randpos*randomRange;
MoveToPointSlow(randpos + m_spawn->GetActorLocation(), 50.0f);
}
void AEnemyBase::ChargeBehavior()
{
}
void AEnemyBase::OffensiveBehavior()
{
}
void AEnemyBase::RangedBehavior()
{
}
void AEnemyBase::ResetConfusionTimer(float confusionTime)
{
m_confusionTimer = confusionTime;
}
float AEnemyBase::m_ReCalcChance(float chance)
{
return (1000 - (chance * 10));
}
int32 AEnemyBase::NativeDealDamage(class ANetworkCharacter* dealer, int32 damage, float armorPercentageIgnore, class UAbilityInfo* ability)
{
m_tempTarget = dealer;
m_informGeneralTimer = informGeneralTime;
return Super::NativeDealDamage(dealer, damage, armorPercentageIgnore, ability);
}

View File

@@ -0,0 +1,60 @@
// Project Lab - NHTV Igad
#pragma once
#include "Creatures/NPCBase.h"
#include "EnemyBase.generated.h"
/**
*
*/
UCLASS()
class UNREALPROJECT_API AEnemyBase : public ANPCBase
{
GENERATED_BODY()
public:
AEnemyBase();
virtual void BeginPlay() override;
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
virtual void Tick(float deltaTime) override;
virtual int32 NativeDealDamage(class ANetworkCharacter* dealer, int32 damage, float armorPercentageIgnore, class UAbilityInfo* ability) override;
void OffensiveBehavior();
void RangedBehavior();
void ChargeBehavior();
void InformGeneral();
void SwitchAgro();
void ConfusionBehavior();
void ResetConfusionTimer(float confusionTime);
UPROPERTY(EditAnywhere, Category = Behavior)
class UBehaviorTree* treeBehavior;
UPROPERTY(EditAnywhere, Category = "Attack Settings")
float informGeneralTime;
UPROPERTY(EditAnywhere, Category = "Ability Settings")
class UAbilityInfo* specialAbility;
UPROPERTY(EditAnywhere, Category = "Ability Settings")
class UAbilityInfo* meleeAbility;
UPROPERTY(EditAnywhere, Category = "Ability Settings")
class UAbilityInfo* rangedAbility;
UPROPERTY(EditAnywhere, Category = "Ability Settings")
float specialAbilityChance;
FVector scatterLocation;
bool hasGeneral;
bool finnishedAttack;
bool hasSpawned;
UPROPERTY()
class AEnemyAIController* enemycontroller;
UPROPERTY()
class AGeneralEnemy* general;
UPROPERTY()
ANetworkCharacter* m_tempTarget;
protected:
float m_ReCalcChance(float chance);
bool m_rotateToPlayer;
float m_lastPercentage;
class UAbilityInfo* m_tempAbility;
float m_informGeneralTimer;
float m_confusionTimer;
};

View File

@@ -0,0 +1,237 @@
// Project Lab - NHTV Igad
#include "UnrealProject.h"
#include "GeneralEnemy.h"
#include "SpawnerBase.h"
#include "BehaviorTree/EnemyAIController.h"
#include "NetworkPlayer.h"
#include "OffensiveEnemy.h"
#include "MinionAnimInstance.h"
AGeneralEnemy::AGeneralEnemy()
{
PrimaryActorTick.bCanEverTick = true;
}
void AGeneralEnemy::BeginPlay()
{
Super::BeginPlay();
if (Role != ROLE_Authority)
return;
if (m_spawn)
{
m_spawn->hasGeneral = true;
FVector addVector;
for (int i = 0; i < 4; i++)
{
addVector = m_spawn->GetActorForwardVector().RotateAngleAxis(i * 90, FVector::UpVector);
patrolLocations.Add(addVector);
}
}
if (distance == 0)
{
distance = 100.0f;
}
/* for (int i = 0; i < formationEnemies.Num(); i++)
{
formationEnemies[i]->general = this;
}*/
}
void AGeneralEnemy::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
Super::EndPlay(EndPlayReason);
if (Role != ROLE_Authority)
return;
for (int i = 0; i < formationEnemies.Num(); i++)
{
formationEnemies[i]->ResetConfusionTimer(3.0f);
formationEnemies[i]->general = nullptr;
}
if (m_spawn != nullptr)
m_spawn->hasGeneral = false;
//formationEnemies.Empty();
}
void AGeneralEnemy::Tick(float deltaTime)
{
Super::Tick(deltaTime);
if (Role != ROLE_Authority)
return;
if (!IsValid(m_spawn))
{
RERROR("There is no spawn for the general enemy");
return;
}
for (int i = 0; i < formationEnemies.Num(); i++)
{
if (IsValid(formationEnemies[i]->general))
continue;
formationEnemies[i]->general = this;
}
if (IsValid(target))
{
FVector2D locationVec = FVector2D(target->GetActorLocation()) - FVector2D(GetActorLocation());
locationVec.Normalize();
if (FVector::DistSquaredXY(GetActorLocation(), target->GetActorLocation()) > m_spawn->formationDistance* m_spawn->formationDistance)
{
MoveToPoint((target->GetActorLocation()));// +(FVector(locationVec, 0))* m_spawn->formationDistance));
DefaultFormation();
}
else
{
GetCharacterMovement()->Velocity = FVector::ZeroVector;
MoveToPoint(GetActorLocation());
GetCharacterMovement()->Velocity = FVector::ZeroVector;
SetActorRotation(FVector(target->GetActorLocation() - GetActorLocation()).Rotation());
ChargeFormation();
}
}
else
{
IdleFormation(deltaTime);
}
}
void AGeneralEnemy::SingleTargetFormation(int enemyNum)
{
if ((formationEnemies[enemyNum]->enemycontroller)->IsA(AEnemyAIController::StaticClass()))
{
formationEnemies[enemyNum]->target = target;
formationEnemies[enemyNum]->enemycontroller->SetBool(true, FName("EnableTree"));
formationEnemies[enemyNum]->SetActorRotation(FVector(target->GetActorLocation() - formationEnemies[enemyNum]->GetActorLocation()).Rotation());
if (count < 3)
{
formationEnemies[enemyNum]->enemycontroller->SetBool(false, FName("GuardKey"));
formationEnemies[enemyNum]->enemycontroller->SetVector(target->GetActorLocation() + target->GetActorForwardVector() * 200, FName("FrontLoc"));
formationEnemies[enemyNum]->enemycontroller->SetVector(target->GetActorLocation() + target->GetActorForwardVector() * -200, FName("BacktLoc"));
formationEnemies[enemyNum]->enemycontroller->SetVector(target->GetActorLocation() + target->GetActorRightVector() *-200, FName("LeftLoc"));
formationEnemies[enemyNum]->enemycontroller->SetVector(target->GetActorLocation() + target->GetActorRightVector() * 200, FName("RightLoc"));
}
else
{
formationEnemies[enemyNum]->enemycontroller->SetBool(true, FName("GuardKey"));
formationEnemies[enemyNum]->enemycontroller->SetVector(GetActorLocation() + GetActorForwardVector() * 100, FName("HomeLocation"));
}
count++;
}
}
void AGeneralEnemy::ChargeFormation()
{
if (!IsValid(target))
return;
count = 0;
TArray<ANetworkPlayer*> targetArray = m_spawn->GetNearbyPlayers();
if (targetArray.Num() == 0)
return;
for (int i = 0; i < formationEnemies.Num(); i++)
{
if (targetArray.Num() == 1)
{
SingleTargetFormation(i);
continue;
}
if (Cast<AOffensiveEnemy>(formationEnemies[i]))
{
formationEnemies[i]->target = m_spawn->GetClosestPlayer();
formationEnemies[i]->MoveToPoint(target->GetActorLocation());
}
else
{
ANetworkPlayer* newTarget = nullptr;
for (int j = 0; j < targetArray.Num(); j++)
{
if(targetArray[j]==m_spawn->GetClosestPlayer())
continue;
newTarget = targetArray[j];
continue;
}
formationEnemies[i]->target = newTarget;
}
}
}
void AGeneralEnemy::DefaultFormation()
{
FVector rotatedFormation;
for (int i = 0; i < formationEnemies.Num(); i++)
{
if (!IsValid(formationEnemies[i]) || !IsValid(m_spawn) || (m_spawn->formationPoints.Num() + 1) < formationEnemies.Num())
{
continue;
}
formationEnemies[i]->target = target;
rotatedFormation = GetActorRotation().RotateVector(FVector(m_spawn->formationPoints[i + 1].X - m_spawn->formationPoints[0].X, m_spawn->formationPoints[i + 1].Y - m_spawn->formationPoints[0].Y, 0));
formationEnemies[i]->MoveToPoint(GetActorLocation() + rotatedFormation);
formationEnemies[i]->SetActorRotation(FRotator(0, m_spawn->formationRotation[i + 1], 0) + (GetActorRotation()));
formationEnemies[i]->enemycontroller->SetBool(false, FName("EnableTree"));
formationEnemies[i]->enemycontroller->SetVector(formationEnemies[i]->GetActorLocation(), FName("HomeLocation"));
}
}
int AGeneralEnemy::NativeDealDamage(class ANetworkCharacter* dealer, int32 damage, float armorPercentageIgnore, class UAbilityInfo* ability)
{
//CHANGEANIMATION(EMinionAnimState::MAS_Pointing);
ChangeNPCAnimation((uint8)EMinionAnimState::MAS_Pointing);
return Super::NativeDealDamage(dealer, damage, armorPercentageIgnore, ability);
}
void AGeneralEnemy::NativeOnKilled(class ANetworkCharacter* killer, class UAbilityInfo* ability)
{
Super::NativeOnKilled(killer, ability);
if (Role != ROLE_Authority)
return;
if (m_spawn &&m_spawn->possesable)
{
int32 team = killer->GetTeam();
m_spawn->CaptureCamp(team);
}
}
void AGeneralEnemy::IdleFormation(float deltaTime)
{
// Move to a random point near the spawn point;
//controll enemies in the formation
int counter = 0;
for (int i = 0; i < formationEnemies.Num(); i++)
{
if (!IsValid(formationEnemies[i]) || !IsValid(m_spawn) || (m_spawn->formationPoints.Num() + 1) < formationEnemies.Num())
{
continue;
}
if (!formationEnemies[i]->m_tempTarget)
{
if (Cast<AOffensiveEnemy>(formationEnemies[i])&&counter<4)
{
formationEnemies[i]->PatrolBetweenLocations (patrolLocations[counter].RotateAngleAxis( 90, FVector::UpVector)*500+ patrolLocations[counter]* 500 + m_spawn->GetActorLocation(), patrolLocations[counter].RotateAngleAxis( 270, FVector::UpVector) * 500 + patrolLocations[counter] * 500 + m_spawn->GetActorLocation(), deltaTime);
counter++;
continue;
}
formationEnemies[i]->MoveToPoint(FVector(m_spawn->formationPoints[i + 1],0)+m_spawn->GetActorLocation());
//formationEnemies[i]->MoveToPointSlow(randpos + m_spawn->GetActorLocation(), 50.0f);
}
else
{
if(formationEnemies[i]->IsA(AOffensiveEnemy::StaticClass()))
Cast<AOffensiveEnemy>(formationEnemies[i])->BasicBehavior();
if(formationEnemies[i]->IsA(ARangedEnemy::StaticClass()))
Cast<ARangedEnemy>(formationEnemies[i])->BasicBehavior();
}
formationEnemies[i]->target = nullptr;
}
}

View File

@@ -0,0 +1,40 @@
// Project Lab - NHTV Igad
#pragma once
#include "Creatures/RangedEnemy.h"
#include "GeneralEnemy.generated.h"
/**
*
*/
UCLASS()
class UNREALPROJECT_API AGeneralEnemy : public ARangedEnemy
{
GENERATED_BODY()
public:
AGeneralEnemy();
virtual void BeginPlay() override;
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
virtual void Tick(float deltaTime) override;
virtual void NativeOnKilled(class ANetworkCharacter* killer, class UAbilityInfo* ability) override;
virtual int NativeDealDamage(class ANetworkCharacter* dealer, int32 damage, float armorPercentageIgnore, class UAbilityInfo* ability)override;
void IdleFormation(float deltaTime);
void ChargeFormation();
void DefaultFormation();
void SingleTargetFormation(int enemyNum );
TArray<FVector2D> formationPoints;
TArray<FVector> patrolLocations;
UPROPERTY()
TArray<class AEnemyBase*> formationEnemies;
UPROPERTY(EditAnywhere, Category = "General settings")
float distance;
UPROPERTY(EditAnywhere, Category = "General settings")
float oFormationRadius;
private:
int count;
};

View File

@@ -0,0 +1,189 @@
// Project Lab - NHTV Igad
#include "UnrealProject.h"
#include "Creatures/NetworkCharacter.h"
#include "Creatures/NetworkPlayer.h"
#include "IllusionCharacter.h"
#include "BlueprintAbilityLibrary.h"
#include "AIController.h"
#include "DealDamageProxy.h"
#include "AbilityInfo.h"
#include "NativeModifiers.h"
AIllusionCharacter::AIllusionCharacter()
{
PrimaryActorTick.bCanEverTick = true;
aggroRange = 400;
acceptenceDistance = 200;
lifeTime = 30;
}
void AIllusionCharacter::BeginPlay()
{
Super::BeginPlay();
if (Role != ROLE_Authority)
{
return;
}
FActorSpawnParameters SpawnInfo;
SpawnInfo.Instigator = Instigator;
SpawnInfo.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
SpawnInfo.OverrideLevel = GetLevel();
SpawnInfo.ObjectFlags |= RF_Transient; // We never want to save AI controllers into a map
AController* NewController = GetWorld()->SpawnActor<AController>(AAIController::StaticClass(), GetActorLocation(), GetActorRotation(), SpawnInfo);
if (NewController != NULL)
{
// if successful will result in setting this->Controller
// as part of possession mechanics
NewController->Possess(this);
}
if (IsValid(illOwner))
{
m_maxHealth = illOwner->GetMaxHealth();
m_health = illOwner->GetHealth();
}
else
{
FERROR("NO ILLOWNER IN ILLUSIONCHARACTER");
}
if (illOwner)
{
abilities.Add(illOwner->abilities[0]);
m_attackSpeed =illOwner->m_attackSpeed;
}
m_isdying = false;
}
void AIllusionCharacter::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
Super::EndPlay(EndPlayReason);
}
void AIllusionCharacter::Tick(float deltaTime)
{
Super::Tick(deltaTime);
if (Role != ROLE_Authority)
{
return;
}
lifeTime -= deltaTime;
if (lifeTime <= 0)
{
if(!m_isdying)
Kill();
return;
}
UNavigationSystem* NavSys = UNavigationSystem::GetCurrent(GetWorld());
if (!NavSys)
{
RERROR("there is no nav sys");
}
if (!GetController())
{
RERROR("there is no controller");
}
if (!IsValid(illOwner))
{
Kill();
return;
}
if (!IsValid(target))
{
attacking = false;
//targetList = ULib::GetCharacterOverlaps();
target = GetClosestTarget();
if (FVector::DistSquared(illOwner->GetActorLocation(), GetActorLocation()) > acceptenceDistance*acceptenceDistance)
{
MoveTo(illOwner->GetActorLocation());
FPRINT("moving to the illOwner");
}
else MoveTo(GetActorLocation());
return;
}
if (!attacking)
{
attacking = IsAttacking(1.0f);
return;
}
Attack();
}
void AIllusionCharacter::Attack()
{
int randdistance =0;
randdistance += ((int)abilities[0]->AICastRange / 2);
if (FVector::Dist(GetActorLocation(), target->GetActorLocation()) < randdistance)
{
MoveTo(GetActorLocation());
SetActorRotation(FVector(target->GetActorLocation() - GetActorLocation()).Rotation());
}
else MoveTo(target->GetActorLocation());
for (int i = 0; i < abilities.Num(); i++)
{
if ((abilities[i])&&FVector::DistSquared(GetActorLocation(),target->GetActorLocation())<abilities[i]->AICastRange*abilities[i]->AICastRange)
{
CastAbility(abilities[i]);
}
}
}
ANetworkCharacter* AIllusionCharacter::GetClosestTarget()
{
ANetworkCharacter* returnTarget = nullptr;
float distance = 1e34;
for (ANetworkCharacter* character : targetList)
{
if(!IsValid(character)||character==this || character->GetTeam()==GetTeam())
continue;
float tempdistance = FVector::DistSquared(character->GetActorLocation(), GetActorLocation());
if (distance > tempdistance)
{
distance = tempdistance;
returnTarget = character;
}
}
return returnTarget;
}
void AIllusionCharacter::MoveTo(FVector Location)
{
UNavigationSystem* NavSys = UNavigationSystem::GetCurrent(GetWorld());
if (IsPendingKill() || IsPendingKillPending())
return;
if (!IsStunned())
{
NavSys->SimpleMoveToLocation(this->Controller, Location);
}
else
{
NavSys->SimpleMoveToLocation(this->Controller, GetActorLocation());
}
}
bool AIllusionCharacter::IsAttacking(float changePercentage)
{
int num = rand() % 100;
if (num > (int)changePercentage)
{
return false;
}
return true;
}
void AIllusionCharacter::Kill()
{
if (IsPendingKill() || IsPendingKillPending())
{
RERROR("the character is pending kill");
return;
}
ADOTModifier* deathMod = GetWorld()->SpawnActor<ADOTModifier>();
deathMod->damagePerTick = 500;
deathMod->lifeTime = 0;
deathMod->target = this;
deathMod->character = this;
deathMod->abilityInfo = abilityInfo;
m_modifierManager->AddModifier(deathMod);
m_isdying = true;
//m_health = 0;
// m_shouldBeDestroyed = true;
}

View File

@@ -0,0 +1,46 @@
// Project Lab - NHTV Igad
#pragma once
#include "Creatures/NetworkCharacter.h"
#include "IllusionCharacter.generated.h"
/**
*
*/
UCLASS()
class UNREALPROJECT_API AIllusionCharacter : public ANetworkCharacter
{
GENERATED_BODY()
public:
AIllusionCharacter();
virtual void BeginPlay() override;
virtual void Tick(float deltaTime)override;
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
void MoveTo(FVector Location);
void Attack();
UFUNCTION(BluePrintCallable, Category = "Illusion Properties")
void Kill();
class ANetworkCharacter* target;
class ANetworkCharacter* GetClosestTarget();
// float percentage is a range between 0 and 100 where 100 is always attacking and 0 never attacking
bool IsAttacking(float changePercentage);
UPROPERTY(EditAnywhere, BlueprintReadWrite,Category = "Illusion Properties", meta = (ExposeOnSpawn))
class ANetworkPlayer* illOwner;
UPROPERTY(editAnywhere, Category = "Illusion Properties")
float aggroRange;
UPROPERTY(editAnywhere, BlueprintReadWrite,Category = "Illusion Properties", meta = (ExposeOnSpawn))
float lifeTime;
UPROPERTY(editAnywhere, BlueprintReadWrite, Category = "Illusion Properties", meta = (ExposeOnSpawn))
class UAbilityInfo* abilityInfo;
UPROPERTY(editAnywhere, Category = "Illusion Properties")
float acceptenceDistance;
UPROPERTY(editAnywhere, BlueprintReadWrite, Category = "Illusion Properties", meta = (ExposeOnSpawn))
TArray<class ANetworkCharacter*> targetList;
bool attacking;
private:
bool m_isdying;
};

View File

@@ -0,0 +1,69 @@
// Project Lab - NHTV Igad
#include "UnrealProject.h"
#include "MainCharacterAnimation.h"
#include "NetworkCharacter.h"
#include "Animation/AnimNodeBase.h"
#include "AnimationProxy.h"
UMainCharacterAnimation::UMainCharacterAnimation(const FObjectInitializer& init)
: Super(init)
{
m_mainAnimProxy = nullptr;
character = nullptr;
attacking = false;
charCustomization = FCharacterCustomization();
m_swingAnimationSequence = 0;
}
void UMainCharacterAnimation::NativeInitializeAnimation()
{
attacking = false;
Super::NativeInitializeAnimation();
character = Cast<ANetworkCharacter>(this->GetOwningActor());
if (character)
{
m_swingAnimationSequence = character->swingAnimationSequence;
}
}
void UMainCharacterAnimation::NativeUpdateAnimation(float DeltaSeconds)
{
if(character && character->swingAnimationSequence > m_swingAnimationSequence)
{
attacking = true;
m_swingAnimationSequence = character->swingAnimationSequence;
}
}
void UMainCharacterAnimation::SetCharacterCustomization(const FCharacterCustomization& characterCustomization)
{
charCustomization = characterCustomization;
if(m_mainAnimProxy)
{
m_mainAnimProxy->charCustomization = charCustomization;
}
}
FAnimInstanceProxy* UMainCharacterAnimation::CreateAnimInstanceProxy()
{
check(!m_mainAnimProxy);
m_mainAnimProxy = new FMainAnimProxy();
m_mainAnimProxy->boneNames[0] = "Slave_Head_Ctrl_Jnt";
m_mainAnimProxy->boneNames[1] = "Slave_L_Hip_Ctrl_Jnt";
m_mainAnimProxy->boneNames[2] = "Slave_R_Hip_Ctrl_Jnt";
m_mainAnimProxy->boneNames[3] = "Slave_L_Result_Shoulder_Ctrl_Jnt";
m_mainAnimProxy->boneNames[4] = "Slave_R_Result_Shoulder_Ctrl_Jnt";
m_mainAnimProxy->boneNames[5] = "Slave_Result_Spine06";
m_mainAnimProxy->boneNames[6] = "skeleton";
return m_mainAnimProxy;
}
void UMainCharacterAnimation::DestroyAnimInstanceProxy(FAnimInstanceProxy* InProxy)
{
check(InProxy == m_mainAnimProxy);
delete InProxy;
m_mainAnimProxy = nullptr;
}
void UMainCharacterAnimation::OnSwingAnimation_Implementation()
{
}

View File

@@ -0,0 +1,43 @@
// Project Lab - NHTV Igad
#pragma once
#include "Animation/AnimInstance.h"
#include "PlayerSetupState.h"
#include "MainCharacterAnimation.generated.h"
/**
*
*/
UCLASS()
class UNREALPROJECT_API UMainCharacterAnimation : public UAnimInstance
{
GENERATED_BODY()
public:
UMainCharacterAnimation(const FObjectInitializer& init);
virtual void NativeInitializeAnimation() override;
virtual void NativeUpdateAnimation(float DeltaSeconds) override;
virtual FAnimInstanceProxy* CreateAnimInstanceProxy();
virtual void DestroyAnimInstanceProxy(FAnimInstanceProxy* InProxy);
UFUNCTION(BlueprintNativeEvent, Category = "Animation")
void OnSwingAnimation();
UFUNCTION(BlueprintCallable, Category = "Animation")
void SetCharacterCustomization(const FCharacterCustomization& characterCustomization);
UPROPERTY(BlueprintReadOnly, Category = "Animation")
class ANetworkCharacter* character;
UPROPERTY(BlueprintReadWrite, Category = "Animation")
bool attacking;
FCharacterCustomization charCustomization;
private:
// Keeps track of how many times an animation was triggered
int32 m_swingAnimationSequence;
struct FMainAnimProxy* m_mainAnimProxy;
};

View File

@@ -0,0 +1,113 @@
// Project Lab - NHTV Igad
#include "UnrealProject.h"
#include "MiniBossCreature.h"
#include "NetworkPlayer.h"
#include "CreatureSpawn.h"
#include "AbilityInfo.h"
#include "Effect.h"
AMiniBossCreature::AMiniBossCreature()
{
PrimaryActorTick.bCanEverTick = true;
m_usesMana = false;
target = nullptr;
m_spawn = nullptr;
m_castTimer = 0;
keyDropped = PlayerKeyType::None;
}
void AMiniBossCreature::BeginPlay()
{
Super::BeginPlay();
if (Role != ROLE_Authority)
return;
// Select two random abilities to cast
if (IsValid(inheritAbilities) && IsValid(inheritAbilities.GetDefaultObject()))
{
TArray<class UAbilityInfo*>& bossAbilities = inheritAbilities.GetDefaultObject()->abilities;
if (bossAbilities.Num() > 1)
{
TArray<int32> abilityIndices;
for (int32 i = 0; i < bossAbilities.Num(); i++)
abilityIndices.Add(i);
while (m_bossAbilityPattern.Num() < 2)
{
const int32 index = FMath::Rand() % abilityIndices.Num();
const int32 ability = abilityIndices[index];
abilityIndices.RemoveAt(index);
m_bossAbilityPattern.Add(ability);
}
}
else if (bossAbilities.Num() == 1)
m_bossAbilityPattern.Add(0);
}
}
void AMiniBossCreature::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
Super::EndPlay(EndPlayReason);
if (Role != ROLE_Authority)
return;
// Drop a key
if (m_health <= 0)
{
ANetworkPlayer* const killedBy = Cast<ANetworkPlayer>(GetLastPlayerDamage());
if (IsValid(killedBy) && keyDropped != PlayerKeyType::None && IsValid(m_spawn) && !m_spawn->hasDroppedKey)
{
killedBy->AssignKey(keyDropped, m_spawn);
}
}
}
void AMiniBossCreature::Tick(float deltaTime)
{
Super::Tick(deltaTime);
if (Role != ROLE_Authority)
return;
// If the distance of the target to the spawn is greater than the aggro range of the spawner,
// then lose the target.
if (IsValid(target))
{
float targetDistSqr = FVector::DistSquared(target->GetActorLocation(), m_spawn->SpawnResetPosition());
float aggroSqr = m_spawn->deaggroRadius * m_spawn->deaggroRadius;
if (aggroSqr < targetDistSqr)
{
// Reset
target = nullptr;
m_castTimer = 0;
}
}
if (!IsValid(target))
return;
// Boss casting logic
MoveToPoint(target->GetActorLocation());
m_castTimer += deltaTime;
if (m_castTimer > 2.5f && IsValid(inheritAbilities) && IsValid(inheritAbilities.GetDefaultObject()))
{
TArray<class UAbilityInfo*>& bossAbilities = inheritAbilities.GetDefaultObject()->abilities;
if (bossAbilities.Num() > 0 && m_bossAbilityPattern.Num() > 0)
{
// Cast a random ability
UAbilityInfo* ability = bossAbilities[m_bossAbilityPattern[FMath::Rand() % m_bossAbilityPattern.Num()]];
if (IsValid(ability)&& ability->AICastRange*ability->AICastRange>FVector::DistSquared(GetActorLocation(),target->GetActorLocation()))
CastAbility(ability);
}
m_castTimer = 0;
}
}

View File

@@ -0,0 +1,34 @@
// Project Lab - NHTV Igad
#pragma once
#include "Creatures/BossBase.h"
#include "PlayerKeyType.h"
#include "MiniBossCreature.generated.h"
/**
*
*/
UCLASS()
class UNREALPROJECT_API AMiniBossCreature : public ABossBase
{
GENERATED_BODY()
public:
AMiniBossCreature();
virtual void BeginPlay() override;
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
virtual void Tick(float deltaTime) override;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Miniboss")
TSubclassOf<class ABossBase> inheritAbilities;
PlayerKeyType keyDropped;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Miniboss")
TSubclassOf<class AEffect> keyEffect;
private:
TArray<int32> m_bossAbilityPattern;
float m_castTimer;
};

View File

@@ -0,0 +1,61 @@
// Project Lab - NHTV Igad
#include "UnrealProject.h"
#include "MinionAnimInstance.h"
UMinionAnimInstance::UMinionAnimInstance(const FObjectInitializer& init)
: Super(init)
{
m_animationState = EMinionAnimState::MAS_Idle;
}
void UMinionAnimInstance::NativeInitializeAnimation()
{
Super::NativeInitializeAnimation();
m_animationState = EMinionAnimState::MAS_Idle;
}
void UMinionAnimInstance::NativeUpdateAnimation(float deltaSeconds)
{
Super::NativeUpdateAnimation(deltaSeconds);
APawn* ownerPawn = TryGetPawnOwner();
if (IsValid(ownerPawn))
{
const FVector velocity = ownerPawn->GetVelocity();
const FVector forward = ownerPawn->GetActorForwardVector().GetSafeNormal2D();
m_movementSpeed = velocity.Size();
float angleBetween = FMath::FindDeltaAngle(forward.HeadingAngle(), velocity.GetSafeNormal2D().HeadingAngle());
m_movementDirectionRelative = FVector(cos(angleBetween), sin(angleBetween), 0);
}
}
EMinionAnimState UMinionAnimInstance::GetAnimationState()
{
return m_animationState;
}
bool UMinionAnimInstance::IsInAnimationState(const EMinionAnimState minionStateCheck)
{
return (m_animationState == minionStateCheck);
}
void UMinionAnimInstance::ChangeAnimationStateTo(EMinionAnimState newState)
{
m_animationState = newState;
}
void UMinionAnimInstance::BPChangeAnimationStateTo(EMinionAnimState newState)
{
m_animationState = newState;
OnAnimationStateChanged.Broadcast(newState);
}
void UMinionAnimInstance::PlaySpecificAnimationByInt(int32 animationToPlay)
{
m_specificAnimationIndex = animationToPlay;
ChangeAnimationStateTo(EMinionAnimState::MAS_Specific);
}

View File

@@ -0,0 +1,66 @@
// Project Lab - NHTV Igad
#pragma once
#include "Animation/AnimInstance.h"
#include "MinionAnimInstance.generated.h"
// Enum that shows in what state the Animation Instance is in.
UENUM(BlueprintType)
enum class EMinionAnimState : uint8
{
MAS_Idle UMETA(DisplayName = "Idle"),
MAS_Pointing UMETA(DisplayName = "Pointing"),
MAS_Attacking UMETA(DisplayName = "Attacking"),
MAS_Casting UMETA(DisplayName = "Casting"),
MAS_Guarding UMETA(DisplayName = "Guarding"),
MAS_Staggered UMETA(DisplayName = "Staggered"),
MAS_Stunned UMETA(DisplayName = "Stunned"),
MAS_Killed UMETA(DisplayName = "Killed"),
MAS_Specific UMETA(DisplayName = "Specific")
};
// Delegate declaration for when the Animation Instance changes its state from within.
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnAnimationStateChanged, EMinionAnimState, newState);
/**
* Animation instance that handles all state changing, variable gathering and notifying the AI class.
*/
UCLASS()
class UNREALPROJECT_API UMinionAnimInstance : public UAnimInstance
{
GENERATED_BODY()
public:
UMinionAnimInstance(const FObjectInitializer& init);
virtual void NativeInitializeAnimation() override;
virtual void NativeUpdateAnimation(float deltaSeconds) override;
// Function to get the animation state of the animation instance.
EMinionAnimState GetAnimationState();
// Helper function for checking if the minion is in a certain state.
bool IsInAnimationState(const EMinionAnimState minionStateCheck);
// Function that changes the state of the minion. Does not trigger OnAnimationStateChanged.
UFUNCTION(BlueprintCallable, Category = "Animation State")
void ChangeAnimationStateTo(EMinionAnimState newState);
// Function that changes the state of the minion. Triggers OnAnimationStateChanged.
// Made specifically for use in the Animation Blueprint.
UFUNCTION(BlueprintCallable, Category = "Animation State")
void BPChangeAnimationStateTo(EMinionAnimState newState);
// Delegate for when the state of the minion changes.
UPROPERTY(BlueprintAssignable, Category = "Animation State")
FOnAnimationStateChanged OnAnimationStateChanged;
UFUNCTION()
void PlaySpecificAnimationByInt(int32 animationToPlay);
protected: // Member variables are protected.
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Animation State")
EMinionAnimState m_animationState;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Animation State")
float m_movementSpeed;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Animation State")
FVector m_movementDirectionRelative;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Animation State")
int32 m_specificAnimationIndex;
};

View File

@@ -0,0 +1,349 @@
// Project Lab - NHTV Igad
#include "UnrealProject.h"
#include "NPCBase.h"
#include "MinionAnimInstance.h"
#include "SpawnerBase.h"
#include "modifier.h"
#include "NetworkPlayer.h"
#include "TeamData.h"
#include "BossBase.h"
#include "DrawDebugHelpers.h"
#include "AI/Navigation/NavigationPath.h"
static UTeamData* teamData;
ANPCBase::ANPCBase()
{
teamData = ConstructorHelpers::FObjectFinder<UTeamData>(L"/Game/Assets/TeamData").Object;
PrimaryActorTick.bCanEverTick = true;
m_spawn = nullptr;
m_dead = false;
baseAttackSpeed = 2.0f;
baseMaxHealth = 200.0f;
baseArmor = 30.0f;
baseMaxMana = 1000.0f;
baseAttackSpeed = 1.0f;
maxAvoidanceForce = 200.0f;
m_reachedStart = false;
//visionTrigger = CreateDefaultSubobject<UCubeComponent>(TEXT("Vision Trigger"));
}
void ANPCBase::BeginPlay()
{
Super::BeginPlay();
if (Role != ROLE_Authority)
return;
m_health = m_maxHealth = baseMaxHealth;
m_mana = m_maxMana = baseMaxMana;
if (m_spawn)
m_targetPoint = m_spawn->GetActorLocation();
else m_targetPoint = GetActorLocation();
collisionRadius = GetCapsuleComponent()->GetScaledCapsuleRadius();
m_walkSpeed = GetCharacterMovement()->MaxWalkSpeed;
m_OnRep_Team();
GetCapsuleComponent()->BodyInstance.bLockXRotation = true;
GetCapsuleComponent()->BodyInstance.bLockYRotation = true;
animInstance = Cast<UMinionAnimInstance>(GetMesh()->GetAnimInstance());
patrolTime = 5.0f;
}
void ANPCBase::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
Super::EndPlay(EndPlayReason);
if (Role != ROLE_Authority)
return;
if(m_spawn && EndPlayReason == EEndPlayReason::Destroyed)
m_spawn->OnMobDie(this);
}
void ANPCBase::Tick(float deltaTime)
{
Super::Tick(deltaTime);
if (Role != ROLE_Authority)
return;
UNavigationSystem* navSys = UNavigationSystem::GetCurrent(GetWorld());
if (!navSys || !GetController() || !m_spawn)
{
//RERROR("Boss base does not have a navigation system");
return;
}
if (!IsValid(target))
target = nullptr;
if (m_dead)
{
return;
}
if (!IsValid(target))
{
m_spawn->GetNewTarget(this);
}
if (!IsValid(target) && !m_hasGeneral)
{
MoveToPoint(m_targetPoint);
}
else
{
if (FVector::DistSquared(m_spawn->GetActorLocation(), GetActorLocation()) > m_spawn->deaggroRadius * m_spawn->deaggroRadius)
{
// Reset aggro radius
target = nullptr;
m_isPulled = false;
}
}
}
int32 ANPCBase::NativeDealDamage(class ANetworkCharacter* dealer, int32 damage, float armorPercentageIgnore, class UAbilityInfo* ability)
{
target = dealer;
m_OnRep_Team();
return Super::NativeDealDamage(dealer, damage, armorPercentageIgnore, ability);
}
void ANPCBase::ResetModifiers()
{
Super::ResetModifiers();
m_maxHealth = baseMaxHealth;
m_maxMana = baseMaxMana;
m_attackSpeed = baseAttackSpeed;
m_armor = baseArmor;
}
void ANPCBase::OnDeath(UAbilityInfo* ability)
{
//should be removed later, this is in here untill the animations are actually in the game
Super::OnDeath(ability);
return;
target = nullptr;
m_dead = true;
m_modifierManager->ClearModifiers();
}
void ANPCBase::CalcAvoidance(const FVector& target)
{
UNavigationSystem* NavSys = UNavigationSystem::GetCurrent(GetWorld());
// NavSys->SimpleMoveToLocation(this->Controller, target);
if (Cast<ABossBase>(this))
{
NavSys->SimpleMoveToLocation(this->Controller, target);
return;
}
FVector newLoc = FVector::ZeroVector;
newLoc = GetClosestPathLocation(target) - GetActorLocation();
newLoc.Normalize();
newLoc *= GetCharacterMovement()->GetMaxSpeed();
newLoc = newLoc + CalcAvoidanceVector(); //+ calc avoicance vector;
FVector vel = TruncateVector(GetCharacterMovement()->Velocity + newLoc, GetCharacterMovement()->GetMaxSpeed());
vel += GetActorLocation();
NavSys->SimpleMoveToLocation(this->Controller, vel);
SetActorRotation(FVector(FVector(vel.X, vel.Y, GetActorLocation().Z) - GetActorLocation()).Rotation());
}
void ANPCBase::PatrolBetweenLocations(FVector startlocation, FVector endLocation, float deltaTime)
{
FVector actorlocation = GetActorLocation();
if (m_reachedStart)
{
MoveToPoint(endLocation);
enableVisonCone = false;
}
else
{
MoveToPoint(startlocation);
enableVisonCone = false;
}
//wait a few second to walk back
float dist = FVector::DistSquaredXY(startlocation, actorlocation);
if (dist < 50.0f*50.0f)
{
m_patrolTimer -= deltaTime;
enableVisonCone = true;
if (m_patrolTimer <= 0)
{
m_reachedStart = true;
m_patrolTimer = patrolTime;
}
}
dist = FVector::DistSquaredXY(endLocation, actorlocation);
if (dist< 50.0f*50.0f)
{
m_patrolTimer -= deltaTime;
enableVisonCone = true;
if (m_patrolTimer <= 0)
{
m_reachedStart = false;
m_patrolTimer = patrolTime;
}
}
}
void ANPCBase::MoveToPoint(const FVector& target)
{
UNavigationSystem* NavSys = UNavigationSystem::GetCurrent(GetWorld());
GetCharacterMovement()->MaxWalkSpeed = m_walkSpeed;
float distance = FVector::DistSquared(target, GetActorLocation());
if (IsPendingKill() || IsPendingKillPending())
return;
if (!IsStunned())
{
CalcAvoidance( target);
SetActorRotation(FVector(FVector(target.X, target.Y, GetActorLocation().Z) - GetActorLocation()).Rotation());
}
else
{
NavSys->SimpleMoveToLocation(this->Controller, GetActorLocation());
}
}
void ANPCBase::MoveToPointSlow(const FVector& target, float dist)
{
UNavigationSystem* NavSys = UNavigationSystem::GetCurrent(GetWorld());
if (IsPendingKill() || IsPendingKillPending())
return;
GetCharacterMovement()->MaxWalkSpeed = m_walkSpeed/2;
if (m_lastLoc != target)
{
if (m_lastLoc == FVector::ZeroVector || FVector::DistSquaredXY(m_lastLoc, GetActorLocation()) < dist*dist)
{
//RPRINT("test");
m_lastLoc =UNavigationSystem::ProjectPointToNavigation(GetWorld(), target);
//m_lastLoc = target;
}
}
MoveToPoint(m_lastLoc);
}
void ANPCBase::OnOverlapBegin(class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
if (!IsValid(OtherActor))
return;
if (!OtherActor->IsA(ANPCBase::StaticClass()))
return;
collisionList.Add(Cast<ANPCBase>(OtherActor));
}
void ANPCBase::OnOverlapEnd(class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex)
{
if (!IsValid(OtherActor))
return;
if (!OtherActor->IsA(ANPCBase::StaticClass()))
return;
collisionList.Remove(Cast<ANPCBase>(OtherActor));
}
void ANPCBase::SetSpawn(class ASpawnerBase* spawn)
{
check(Role == ROLE_Authority);
check(!m_spawn);
m_spawn = spawn;
}
void ANPCBase::SetControlPoint(FVector controlPoint)
{
check(Role == ROLE_Authority);
m_targetPoint = controlPoint;
}
void ANPCBase::m_OnRep_Team()
{
Super::m_OnRep_Team();
if(!m_materialInstance)
{
m_materialInstance = GetMesh()->CreateDynamicMaterialInstance(0);
}
if(m_materialInstance)
{
float scalar = (float)m_health / (float)m_maxHealth;
m_materialInstance->SetVectorParameterValue("TeamColor", teamData->GetTeamColor(GetTeam()));
m_materialInstance->SetScalarParameterValue("FlameEdgeSoftness", 100.0f - (100.0f*scalar));
m_materialInstance->SetScalarParameterValue("FlameEffectIntensity", (scalar));
m_materialInstance->SetScalarParameterValue("RandomOffset", FMath::FRand());
}
}
void ANPCBase::UnsetSpawn()
{
check(Role == ROLE_Authority);
m_spawn = nullptr;
}
void ANPCBase::ChangeNPCAnimation_Implementation(uint8 state )
{
if (IsValid(animInstance))
animInstance->ChangeAnimationStateTo((EMinionAnimState)(state));
}
FVector ANPCBase::CalcAvoidanceVector()
{
FVector retVector = FVector::ZeroVector;
float dynLenght = GetCharacterMovement()->Velocity.Size() / GetCharacterMovement()->GetMaxSpeed();
//change getactorforward by velocity
FVector vel = GetCharacterMovement()->Velocity;
vel.Normalize();
aheadvec1 =GetActorLocation()+ vel*dynLenght;
aheadvec2 = GetActorLocation() + vel*dynLenght*0.5;
// DrawDebugSphere(GetWorld(), aheadvec1, 24, 32, FColor(255, 255, 255));
// DrawDebugSphere(GetWorld(), aheadvec2, 24, 32, FColor(255, 0, 0));
ANPCBase* obstacle = GetClosestObstacle();
if (IsValid(obstacle))
{
retVector = aheadvec1 - obstacle->GetActorLocation();
retVector.Z = 0.0f;
retVector.Normalize();
retVector *= maxAvoidanceForce;
}
// DrawDebugLine(GetWorld(), GetActorLocation(), GetActorLocation() + retVector, FColor(255, 255, 0));
return retVector;
}///
ANPCBase* ANPCBase::GetClosestObstacle()
{
ANPCBase* obstacle = nullptr;
float distance = 1e34;
for (int i = 0; i < m_spawn->m_mobs.Num(); i++)
{
ANPCBase* current = m_spawn->m_mobs[i];
if(!IsValid(current)||current==this)
continue;
float tempdistance = FVector::DistSquared(current->GetActorLocation(), this->GetActorLocation());
if (tempdistance < distance)
{
distance = tempdistance;
obstacle = current;
}
}
if (!IsValid(obstacle))
return nullptr;
if (FVector::DistSquared(aheadvec1, obstacle->GetActorLocation())>100 * 100 && FVector::DistSquared(aheadvec2, obstacle->GetActorLocation())>100 * 100)
obstacle = nullptr;
return obstacle;
}
FVector ANPCBase::TruncateVector(FVector inVector, float maxForce)
{
if (inVector.Size() > maxForce)
{
inVector.Normalize();
inVector *= maxForce;
}
return inVector;
}
FVector ANPCBase::GetClosestPathLocation(FVector endlocation)
{
FVector returnVec = FVector();
UNavigationPath *tpath;
UNavigationSystem* navsys = UNavigationSystem::GetCurrent(GetWorld());
tpath = navsys->FindPathToLocationSynchronously(GetWorld(), GetActorLocation(), endlocation);
if (tpath == nullptr||tpath->PathPoints.Num()<=1)
return endlocation;
return tpath->PathPoints[tpath->PathPoints.Num()-1];
}

View File

@@ -0,0 +1,109 @@
// Project Lab - NHTV Igad
#pragma once
#include "Creatures/NetworkCharacter.h"
#include "NPCBase.generated.h"
/**
*
*/
UCLASS()
class UNREALPROJECT_API ANPCBase : public ANetworkCharacter
{
GENERATED_BODY()
public:
ANPCBase();
virtual void BeginPlay() override;
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
virtual void Tick(float deltaTime) override;
virtual int32 NativeDealDamage(class ANetworkCharacter* dealer, int32 damage, float armorPercentageIgnore, class UAbilityInfo* ability) override;
// Clears all the modifier stat modifications from this character
virtual void ResetModifiers();
void SetSpawn(class ASpawnerBase* spawn);
void UnsetSpawn();
void SetControlPoint(FVector controlPoint);
UPROPERTY(BlueprintAssignable, Category = "Collision")
FComponentBeginOverlapSignature OnComponentBeginOverlap;
UPROPERTY(BlueprintAssignable, Category = "Collision")
FComponentBeginOverlapSignature OnComponentExitOverlap;
UPROPERTY(VisibleAnywhere, Category = "Custom Collision")
float maxAvoidanceForce;
UPROPERTY(BlueprintReadWrite)
TArray< class ANPCBase*>collisionList;
UPROPERTY(BlueprintReadWrite)
class ANetworkCharacter* target;
UFUNCTION(BlueprintImplementableEvent, Category = "Animation")
void PlayFencAnimation();
UFUNCTION(BlueprintImplementableEvent, Category = "Animation")
void PlayNormalAnimation();
UFUNCTION(BlueprintImplementableEvent, Category = "Animation")
void PlayClimbingAnimation();
UFUNCTION(BlueprintImplementableEvent, Category = "Animation")
void PlayPointAnimation();
UFUNCTION(NetMulticast, Reliable, Category = "Animation")
void ChangeNPCAnimation(uint8 state);
//Trigger components for the vision of the npcs
float patrolTime;
float collisionRadius;
void CalcAvoidance(const FVector& target);
virtual void MoveToPoint(const FVector& target);
virtual void MoveToPointSlow(const FVector& target, float dist);
void PatrolBetweenLocations(FVector startlocation, FVector endLocation,float deltaTime);
ANPCBase* GetClosestObstacle();
FVector CalcAvoidanceVector();
FVector TruncateVector(FVector inVector, float maxForce);
FVector GetClosestPathLocation(FVector endlocation);
FVector aheadvec1;
FVector aheadvec2;
protected:
virtual void m_OnRep_Team() override;
UFUNCTION(BlueprintImplementableEvent, category = "death")
void PlayDeathAnimation(UAbilityInfo* ability);
virtual void OnDeath(UAbilityInfo* ability) override;
UFUNCTION()
void OnOverlapBegin(class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);
UFUNCTION()
void OnOverlapEnd(class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex);
UPROPERTY()
UMaterialInstanceDynamic* m_materialInstance;
// Base Stats
UPROPERTY(EditDefaultsOnly, Category = "Stats")
int32 baseMaxHealth;
UPROPERTY(EditDefaultsOnly, Category = "Stats")
int32 baseMaxMana;
// AKA Attacks per second
UPROPERTY(EditDefaultsOnly, Category = "Stats")
float baseAttackSpeed;
UPROPERTY(BlueprintReadWrite)
bool enableVisonCone;
bool m_dead;
UPROPERTY()
class ASpawnerBase* m_spawn;
FVector m_targetPoint;
bool m_isPulled;
bool m_hasGeneral;
class UMinionAnimInstance* animInstance;
private:
FVector m_lastLoc;
float m_walkSpeed;
bool lastcollision;
bool m_reachedStart;
FVector previousDirection;
float m_patrolTimer;
};

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,324 @@
// Project Lab - NHTV Igad
#pragma once
#include <unordered_map>
using std::unordered_map;
#include "AbilityState.h"
#include "ScalingGraph.h"
#include "NetworkPossessable.h"
#include "IngameSkillTree.h"
#include "NetworkCharacter.generated.h"
class ACreatureSpawn;
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FCharacterKilled, ANetworkCharacter*, killer, UAbilityInfo*, ability);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FOnDamageTaken, ANetworkCharacter*, dealer, int32, damage, UAbilityInfo*, ability);
UCLASS(config = Game)
class ANetworkCharacter : public ANetworkPossessable
{
GENERATED_BODY()
public:
ANetworkCharacter();
virtual void BeginPlay() override;
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
virtual void Destroyed() override;
virtual void OnDeath(UAbilityInfo* ability);
void RegisterHealthBar();
void UnregisterHealthBar();
virtual void Tick(float DeltaSeconds) override;
// This processes the learned abilities on the server and calls LearnSkills on the owning client
void LearnSkills_Server(const TArray<FIngameSkillTreeSkill>& skills);
// This creates a list of all learned skills on the client's version of the character so that he gets an updated casting bar, etc.
UFUNCTION(Client, Reliable)
void LearnSkills(const TArray<FIngameSkillTreeSkill>& skills);
// The Buff/Modifier manager, for server side characters
class ModifierManager* GetModifierManager();
UFUNCTION(BlueprintCallable, Category = "modifiers")
TArray<class AModifier*> GetModifiersOfClass(TSubclassOf<class AModifier> modifierClass);
virtual void ResetModifiers();
void CheckStatsOverflow();
// Damage dealing
UFUNCTION(BlueprintCallable, Category = "Damage", meta = (WorldContext="WorldContextObject"))
int32 DealDamage(class UObject* WorldContextObject, int32 damage, float armorPercentageIgnore = 0.0f);
virtual int32 NativeDealDamage(class ANetworkCharacter* dealer, int32 damage, float armorPercentageIgnore = 0.0f, UAbilityInfo* ability = nullptr);
virtual void NativeOnKilled(class ANetworkCharacter* killer, class UAbilityInfo* ability);
UFUNCTION(BlueprintCallable, Category = "Damage")
void OnStandardAttack(ANetworkCharacter* targetCharacter);
// Healing
UFUNCTION(BlueprintCallable, Category = "Healing")
void AddHealth(int32 health);
virtual void NativeAddHealth(int32 health);
void RemoveHealth(int32 health);
void AddMana(float mana);
void RemoveMana(float mana);
UFUNCTION(BlueprintCallable, Category = "Damage")
float GetTimeSinceDamage() const;
UFUNCTION(BlueprintCallable, Category = "Animation")
void TriggerSwingAnimation_Server();
UFUNCTION(BlueprintCallable, Category = "State")
int32 GetHealth() const;
UFUNCTION(BlueprintCallable, Category = "State")
int32 GetMana() const;
UFUNCTION(BlueprintCallable, Category = "State")
int32 GetBlockedMana() const;
UFUNCTION(BlueprintCallable, Category = "State")
int32 GetMaxHealth() const;
UFUNCTION(BlueprintCallable, Category = "State")
int32 GetMaxMana() const;
UFUNCTION(BlueprintCallable, Category = "State")
int32 GetArmor() const;
UFUNCTION(BlueprintCallable, Category = "State")
bool GetHitable() const;
UFUNCTION(BlueprintCallable, Category = "State")
void SetHitable(bool hitable);
UFUNCTION(BlueprintCallable, Category = "State")
float GetDamageMultiplier() const;
UFUNCTION(BlueprintCallable, Category = "State")
float GetCooldownReduction() const;
UFUNCTION(BlueprintCallable, Category = "State")
float GetAttackSpeed() const;
UFUNCTION(BlueprintCallable, Category = "State")
float GetAttackDamage() const;
UFUNCTION(BlueprintCallable, Category = "State")
float GetMagicDamage() const;
UFUNCTION(BlueprintCallable, Category = "State")
float GetTotalDamage() const;
UFUNCTION(BlueprintCallable, Category = "State")
bool IsStunned() const;
UFUNCTION(BlueprintCallable, Category = "State")
bool CanRotate() const;
UFUNCTION(BlueprintCallable, Category = "State")
bool IsSilenced() const;
UFUNCTION(BlueprintCallable, Category = "State")
bool IsChanneling() const;
UFUNCTION(BlueprintCallable, Category = "State")
bool IsRanged() const;
bool CanBeStunned() const;
ANetworkCharacter* GetLastPlayerDamage() const;
void CastAbility(int32 abilityIndex);
void CastAbility(class UAbilityInfo* abilityInfo);
// Returns the ability that is currently being casted(channeling)
UFUNCTION(BlueprintCallable, Category = "Ability")
class UAbilityInfo* GetCastingAbility();
// Gets the persistent state of an ability between casts
class AAbilityState* GetAbilityState(class UAbilityInfo* abilityInfo);
// Gets the toggle state for abilities that have isToggleAbility set
bool GetAbilityToggleState(class UAbilityInfo* abilityInfo);
bool m_initialised;
// Minimap/FoW visibility
bool IsVisible() const;
// The collection of abilities this character has, for players.
// The first ability in this array is always treated the character's basic attack,
// and thus is affected by the attack speed variable of the character
UPROPERTY(EditDefaultsOnly, Category = "Ability")
TArray<class UAbilityInfo*> abilities;
UPROPERTY(BlueprintReadOnly, Replicated, Category = "Ability")
class UAbilityInfo* basicAttack;
UPROPERTY(EditDefaultsOnly, Category = "Ability")
TArray<class UAbilityInfo*> passives;
UPROPERTY(Replicated, BlueprintReadOnly, Category = "Animation")
int32 swingAnimationSequence;
UPROPERTY(EditAnywhere, Category = "Experience Settings")
int32 experienceGainOnKill;
// Intervals at which damage and healing combat text are spawned
UPROPERTY(EditAnywhere, Category = "Combat Text")
float healthAccumTimer;
UPROPERTY(EditAnywhere, Category = "Combat Text")
float damageAccumTimer;
// Duration before a team's damage is no longer valid
// Gets refreshed when a team deals damage to the creature
UPROPERTY(EditAnywhere, Category = "Team Damage Table")
float teamDamageTimer;
UPROPERTY(BlueprintAssignable, Category = "Character")
FCharacterKilled onCharacterKilled;
// SERVER ONLY
UPROPERTY(BlueprintAssignable, Category = "Character")
FOnDamageTaken onDamageTaken;
METRICS_EXPR(Metrics::PlayerHandle* metricsHandle);
protected:
// Called when the character is spawned or reset to set initial modifiers like fixed health/mana-regen
// overridable
virtual void m_SpawnModifiers();
// This checks stunn state, etc. to allow NetworkPossessable to move
virtual bool m_AllowedToMove() override;
virtual bool m_AllowedToRotate() override;
virtual void m_SetLevelStats();
UPROPERTY(EditDefaultsOnly, Category = "Stats")
int32 baseMovementSpeed;
UPROPERTY(EditDefaultsOnly, Category = "Stats")
int32 baseArmor;
UPROPERTY(EditDefaultsOnly, Category = "Stats")
int32 passiveManaRegen;
UPROPERTY(EditDefaultsOnly, Category = "Stats")
int32 passiveHealthRegen;
UPROPERTY(Replicated)
int32 m_blockedMana;
UPROPERTY(Replicated)
float m_damageMultiplier;
UPROPERTY(Replicated)
float m_ignoreArmor;
UPROPERTY(Replicated)
float m_manaRegenMultiplier;
UPROPERTY(Replicated)
float m_manaUsageMultiplier;
UPROPERTY(Replicated)
float m_positiveEffectMultiplier;
UPROPERTY(Replicated)
float m_negativeEffectMultiplier;
UPROPERTY(Replicated)
float m_damageTakenMultiplier;
UPROPERTY(Replicated)
int32 m_armor;
UPROPERTY(Replicated)
bool m_stunned;
UPROPERTY(Replicated)
bool m_silenced;
//sileneCount is the ammount of silences by modifiers, silence by casting is not taking into account.
UPROPERTY(Replicated)
uint32 m_silenceCount;
UPROPERTY(Replicated)
bool m_visible;
UPROPERTY(Replicated)
bool m_hitable;
UPROPERTY(Replicated)
bool m_isRanged;
UPROPERTY(EditDefaultsOnly, Category = "Stats")
bool canBeStunned;
UPROPERTY(EditDefaultsOnly, Category = "Stats")
bool canBeSilenced;
UPROPERTY(Replicated)
int32 m_health;
UPROPERTY(Replicated)
int32 m_maxHealth;
UPROPERTY(Replicated)
float m_mana;
UPROPERTY(Replicated)
int32 m_maxMana;
UPROPERTY(Replicated)
float m_cooldownReduction;
UPROPERTY(Replicated)
float m_attackSpeed;
UPROPERTY(Replicated)
float m_attackDamageMultiplier;
UPROPERTY(Replicated)
float m_magicDamageMultiplier;
UPROPERTY(Replicated)
bool m_usesMana;
UPROPERTY(Replicated)
float m_castingMovementspeedMultiplier;
friend class ModifierManager;
friend class APreCastAbilityEventGroup;
friend class AIllusionCharacter;
friend class ADefaultPlayerController;
class ModifierManager* m_modifierManager;
bool m_shouldBeDestroyed = false;
private:
// Request to the server to cast an ability
UFUNCTION(Reliable, Server, WithValidation)
void m_CastAbility_Server(class UAbilityInfo* ability);
void m_InitAbilitySequence(class UAbilityInfo* ability, class AAbilityState* state);
// Updates all the cooldown timers and ticks modifiers
void m_TickAbilities(float DeltaSeconds);
void m_SetAbilityCooldown(class UAbilityInfo* ability, class AAbilityState* state);
// Server only casting interupt
void m_InteruptSpellcasting();
// Called if we know an ability is successfully casted or not
UFUNCTION(Reliable, Client)
void m_OnAbilityCastConfirm(UAbilityInfo* ability, bool success, bool toggleState, float cooldown, float cooldownTime);
void m_PreCast(UAbilityInfo* ability);
// Called if we know an ability is successfully casted or not (server-side)
virtual void m_OnAbilityCastConfirm_Server(UAbilityInfo* ability, bool success);
// Callback for when an ability progresses to it's next state
UFUNCTION()
void m_OnAbilityEventGroupEnded(class UAbilityInfo* ability, class AAbilityEventGroup* current, class AAbilityEventGroup* next);
friend class ADefaultPlayerState;
// Active Stats
struct DamagePeriod
{
DamagePeriod(int32 damage, float timer) : damage(damage), timer(timer) {}
int32 damage;
float timer;
};
unordered_map<class ADefaultPlayerController*, DamagePeriod> m_damageAccum;
int32 m_damageAccumValue;
float m_damageAccumTimer;
int32 m_healAccumValue;
float m_healAccumTimer;
float m_totalDamage;
unordered_map<int32, DamagePeriod> m_teamDamageDealt;
UPROPERTY()
ANetworkCharacter* m_lastPlayerDamage;
// Keeps ability persistent state between casts
UPROPERTY()
TMap<class UAbilityInfo*, class AAbilityState*> m_abilityStates;
// Keeps ability execution states / active group (server-side)
UPROPERTY()
TMap<class UAbilityInfo*, class AAbilityEventGroup*> m_activeAbilities;
friend class AModifier;
friend class AVisibilityModifier;
float m_timeSinceDamage;
UPROPERTY()
class AAbilityEventGroup* m_channelGroup;
UPROPERTY(Replicated)
class UAbilityInfo* m_castingAbility;
UPROPERTY(Replicated)
bool m_channelStun;
UPROPERTY(Replicated)
bool m_allowChannelRotation;
class APreCastAbilityEventGroup* m_currentPreCast;
};

View File

@@ -0,0 +1,91 @@
// Project Lab - NHTV Igad
#include "UnrealProject.h"
#include "NetworkGhost.h"
#include "NetworkPlayer.h"
#include "DefaultPlayerState.h"
// Sets default values
ANetworkGhost::ANetworkGhost()
{
bReplicates = true;
postProcess = CreateDefaultSubobject<UPostProcessComponent>(TEXT("PostProcess"));
postProcess->bEnabled = false;
postProcess->AttachTo(RootComponent);
m_SetupCamera();
// Configure character movement
GetCharacterMovement()->bOrientRotationToMovement = true; // Rotate character to moving direction
GetCharacterMovement()->RotationRate = FRotator(0.f, 640.f, 0.f);
GetCharacterMovement()->bConstrainToPlane = true;
GetCharacterMovement()->bSnapToPlaneAtStart = true;
shrinesInRange = 0;
respawnDuration = 15;
allyRespawnRange = 300;
}
void ANetworkGhost::BeginPlay()
{
Super::BeginPlay();
m_respawnTime = respawnDuration;
}
void ANetworkGhost::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
// Update the respawn timer (server only)
if (Role == ROLE_Authority)
{
if (m_respawnTime > 0)
m_respawnTime -= DeltaTime;
}
// Enable the post process on clients
if (IsValid(GetController()))
postProcess->bEnabled = GetController()->IsLocalController();
}
bool ANetworkGhost::CanRespawn() const
{
// Cannot respawn yet
if (m_respawnTime > 0)
return false;
// If we're falling, were unable to respawn
if (!GetCharacterMovement()->IsMovingOnGround())
return false;
// We're at a shrine
if (shrinesInRange > 0)
return true;
// Check if the ally is within the radius, so we can respawn next to him
ADefaultPlayerState* state = Cast<ADefaultPlayerState>(PlayerState);
bool inAllyRange = false;
if (IsValid(state) && IsValid(state->teamMate) && IsValid(state->teamMate->character))
{
if (FVector::DistSquared(GetActorLocation(), state->teamMate->character->GetActorLocation()) <= (allyRespawnRange * allyRespawnRange))
return true;
}
return false;
}
float ANetworkGhost::RespawnTime() const
{
return m_respawnTime;
}
void ANetworkGhost::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
DOREPLIFETIME(ANetworkGhost, m_respawnTime);
}

View File

@@ -0,0 +1,44 @@
// Project Lab - NHTV Igad
#pragma once
#include "Creatures/NetworkPossessable.h"
#include "NetworkGhost.generated.h"
UCLASS()
class UNREALPROJECT_API ANetworkGhost : public ANetworkPossessable
{
GENERATED_BODY()
public:
ANetworkGhost();
virtual void BeginPlay() override;
virtual void Tick(float DeltaSeconds) override;
bool CanRespawn() const;
UPROPERTY(BlueprintReadonly, Category = "Respawn")
int32 shrinesInRange;
// Range to ally for respawn
UPROPERTY(EditAnywhere, Category = "Respawn")
float allyRespawnRange;
// Time it takes before the player is allowed to respawn
UPROPERTY(EditAnywhere, Category = "Respawn")
float respawnDuration;
// Get time it takes before respawning
UFUNCTION(BlueprintCallable, Category = "Respawn")
float RespawnTime() const;
UPROPERTY(EditAnywhere, Category = "PostProcess")
UPostProcessComponent* postProcess;
private:
UPROPERTY(Replicated)
float m_respawnTime;
};

View File

@@ -0,0 +1,474 @@
// Project Lab - NHTV Igad
#include "UnrealProject.h"
#include "NetworkPlayer.h"
#include "DefaultPlayerController.h"
#include "ItemBase.h"
#include "BaseSkillObject.h"
#include "AbilityInfo.h"
#include "NetworkSwitch.h"
#include "DefaultGameMode.h"
#include "DefaultPlayerState.h"
#include "IngameSkillTree.h"
#include "Modifier.h"
#include "SpawnerBase.h"
#include "TeamData.h"
static UTeamData* teamData;
ANetworkPlayer::ANetworkPlayer()
{
bReplicates = true;
m_SetupCamera();
m_initialised = false;
m_keyState = 0;
healthCurve = ConstructorHelpers::FObjectFinder<UCurveFloat>(TEXT("/Game/ScalingCurves/CF_PlayerHealth")).Object;
healthRegenCurve = ConstructorHelpers::FObjectFinder<UCurveFloat>(TEXT("/Game/ScalingCurves/CF_PlayerHealthRegen")).Object;
manaCurve = ConstructorHelpers::FObjectFinder<UCurveFloat>(TEXT("/Game/ScalingCurves/CF_PlayerMana")).Object;
manaRegenCurve = ConstructorHelpers::FObjectFinder<UCurveFloat>(TEXT("/Game/ScalingCurves/CF_PlayerManaRegen")).Object;
armorCurve = ConstructorHelpers::FObjectFinder<UCurveFloat>(TEXT("/Game/ScalingCurves/CF_PlayerArmor")).Object;
attackSpeedCurve = ConstructorHelpers::FObjectFinder<UCurveFloat>(TEXT("/Game/ScalingCurves/CF_PlayerAttackSpeed")).Object;
creatureDamageTakenCurve = ConstructorHelpers::FObjectFinder<UCurveFloat>(TEXT("/Game/ScalingCurves/CF_CreatureDamageTaken")).Object;
creatureDamageDealtCurve = ConstructorHelpers::FObjectFinder<UCurveFloat>(TEXT("/Game/ScalingCurves/CF_CreatureDamageDealt")).Object;
teamData = ConstructorHelpers::FObjectFinder<UTeamData>(TEXT("/Game/Assets/TeamData")).Object;
playerCircle = CreateDefaultSubobject<UStaticMeshComponent>("Player Circle");
playerCircle->AttachTo(RootComponent);
visionRadius = 2500;
}
void ANetworkPlayer::BeginPlay()
{
m_levelStatsInitialized = false;
Super::BeginPlay();
m_initialised = false;
}
void ANetworkPlayer::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
Super::EndPlay(EndPlayReason);
if (Role != ROLE_Authority)
return;
// Return the keys
ANetworkPlayer* const killedBy = Cast<ANetworkPlayer>(GetLastPlayerDamage());
if (m_health <= 0 && IsValid(killedBy) && killedBy->GetTeam() != GetTeam())
{
FText Source = FText::FromString(killedBy->playerName);
FText Target = FText::FromString(playerName);
onPlayerKilled.Broadcast(Source, Target, killedBy->GetTeam(), GetTeam());
// Assign keys to the player that killed us
for (auto iter = m_keyOrigins.CreateIterator(); iter; ++iter)
{
ASpawnerBase** find = killedBy->m_keyOrigins.Find(iter->Key);
if (!find)
killedBy->m_keyOrigins.Add(iter->Key, iter->Value);
else
iter->Value->hasDroppedKey = false;
}
killedBy->m_keyState |= m_keyState;
}
else
{
// Return the keys we have
for (auto iter = m_keyOrigins.CreateIterator(); iter; ++iter)
{
if (IsValid(iter->Value))
iter->Value->hasDroppedKey = false;
}
}
m_keyState = 0;
m_keyOrigins.Reset();
// Clean up screen effects and delegates.
m_filterTimelines.Empty();
for (int32 i = 0; i < m_delegates.Num(); i++)
{
GetWorldTimerManager().ClearTimer(m_delegates[i]);
}
m_delegates.Empty();
}
void ANetworkPlayer::Tick(float DeltaSeconds)
{
Super::Tick(DeltaSeconds);
for (auto& timeline : m_filterTimelines)
{
timeline.Value.TickTimeline(DeltaSeconds);
}
// Server only
if(Role == ROLE_Authority)
{
ADefaultPlayerState* state = Cast<ADefaultPlayerState>(PlayerState);
if(!m_levelStatsInitialized)
{
m_modifierManager->RecalculateCharacter();
CheckStatsOverflow();
if(!m_initialised)
{
m_health = m_maxHealth;
m_mana = m_maxMana;
m_initialised = true;
}
m_levelStatsInitialized = true;
}
}
}
void ANetworkPlayer::PossessedBy(AController* NewController)
{
Super::PossessedBy(NewController);
OnRep_PlayerState();
}
void ANetworkPlayer::OnRep_PlayerState()
{
Super::OnRep_PlayerState();
// Initialize player circle
UMaterialInstanceDynamic* mi = playerCircle->CreateDynamicMaterialInstance(0);
FLinearColor teamColor = teamData->GetTeamColor(Cast<ADefaultPlayerState>(PlayerState)->GetTeam());
mi->SetVectorParameterValue("Color", teamColor);
}
void ANetworkPlayer::ResetModifiers()
{
// Learn abilities
m_SetLevelStats();
Super::ResetModifiers();
}
void ANetworkPlayer::OnLevelUp_Server(int32 newLevel)
{
check(Role == ROLE_Authority);
// Learn abilities
//m_SetLevelStats();
// Recalculate modifiers for new level
if(m_modifierManager)
m_modifierManager->RecalculateCharacter();
CheckStatsOverflow();
// Call blueprint level up event (server-side)
OnLevelUp(newLevel);
}
class ANetworkPlayer* ANetworkPlayer::GetTeamMate() const
{
ADefaultPlayerState* state = Cast<ADefaultPlayerState>(PlayerState);
if (state && state->teamMate)
return state->teamMate->character;
return nullptr;
}
void ANetworkPlayer::m_SetLevelStats()
{
Super::m_SetLevelStats();
// Update stats
ADefaultPlayerState* state = Cast<ADefaultPlayerState>(PlayerState);
float level = 1;
if(IsValid(state))
level = (float)state->GetLevel();
float newHealth = SampleHealthCurve(level);
float newMana = SampleManaCurve(level);
float newArmor = SampleArmorCurve(level);
float newAttackSpeed = SampleAttackSpeedCurve(level);
//GWPRINT(L"Setting level bases stats for level " + level + L"(" + levelScale + L")");
//GWPRINT(L"Health = " + m_maxHealth + L"->" + newHealth);
//GWPRINT(L"Mana = " + m_maxMana + L"->" + newMana);
//GWPRINT(L"Armor = " + m_armor + L"->" + newArmor);
//GWPRINT(L"Attack Speed = " + m_attackSpeed + L"->" + newAs);
if(!m_levelStatsInitialized)
{
m_health = newHealth;
m_mana = newMana;
}
m_maxHealth = newHealth;
m_maxMana = newMana;
baseArmor = newArmor;
m_attackSpeed = newAttackSpeed;
if(Role == ROLE_Authority)
{
// Send level-up/learn skill command
ADefaultPlayerController* controller = Cast<ADefaultPlayerController>(GetController());
if(controller)
{
controller->LearnSkillsForLevel();
}
}
}
void ANetworkPlayer::OnLevelUp_Implementation(int32 newLevel)
{
m_levelStatsInitialized = false;
}
bool ANetworkPlayer::ToggleSwitch_Validate(ANetworkSwitch* networkSwitch)
{
return networkSwitch && FVector::Dist(GetActorLocation(), networkSwitch->GetActorLocation()) < 600;
}
void ANetworkPlayer::ToggleSwitch_Implementation(ANetworkSwitch* networkSwitch)
{
if(FVector::Dist(GetActorLocation(), networkSwitch->GetActorLocation()) < 300)
networkSwitch->Toggle();
}
float ANetworkPlayer::SampleHealthCurve(float in)
{
if(GetCharacterClassProperties().healthCurve)
{
return GetCharacterClassProperties().healthCurve->GetFloatValue(in);
}
return healthCurve->GetFloatValue(in);
}
float ANetworkPlayer::SampleManaCurve(float in)
{
if(GetCharacterClassProperties().manaCurve)
{
return GetCharacterClassProperties().manaCurve->GetFloatValue(in);
}
return manaCurve->GetFloatValue(in);
}
float ANetworkPlayer::SampleArmorCurve(float in)
{
if(GetCharacterClassProperties().armorCurve)
{
return GetCharacterClassProperties().armorCurve->GetFloatValue(in);
}
return armorCurve->GetFloatValue(in);
}
float ANetworkPlayer::SampleAttackSpeedCurve(float in)
{
if(GetCharacterClassProperties().attackSpeedCurve)
{
return GetCharacterClassProperties().attackSpeedCurve->GetFloatValue(in);
}
return attackSpeedCurve->GetFloatValue(in);
}
bool ANetworkPlayer::HasKey(PlayerKeyType keyType) const
{
if (keyType == PlayerKeyType::None)
return m_keyState == 0;
return ((1 << (int32)keyType) & m_keyState) != 0;
}
bool ANetworkPlayer::HasAnyKey() const
{
return m_keyState != 0;
}
bool ANetworkPlayer::AssignKey(PlayerKeyType keyType, ASpawnerBase* origin)
{
check(Role == ROLE_Authority);
if (HasKey(keyType))
return false;
origin->hasDroppedKey = true;
// Store the origin for later
m_keyOrigins.Add((uint8)keyType, origin);
m_keyState += (1 << (int32)keyType);
return true;
}
bool ANetworkPlayer::ClearKey(PlayerKeyType keyType)
{
check(Role == ROLE_Authority);
if (!HasKey(keyType))
return false;
// Allow the boss to drop keys again
ASpawnerBase** find = m_keyOrigins.Find((uint8)keyType);
if (find)
{
if(IsValid(*find)) (*find)->hasDroppedKey = false;
m_keyOrigins.Remove((uint8)keyType);
}
m_keyState -= (1 << (int32)keyType);
return true;
}
void ANetworkPlayer::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
DOREPLIFETIME(ANetworkPlayer, m_keyState);
}
FCharacterClassProperty ANetworkPlayer::GetCharacterClassProperties() const
{
static FCharacterClassProperty dummy;
if(!Controller)
return dummy;
return Cast<ADefaultPlayerController>(Controller)->GetCharacterClassProperties();
}
//Screen Filters
void ANetworkPlayer::SetFilterDuration(float duration, UPostProcessComponent* filter)
{
FTimerHandle uniqueHandle;
FTimerDelegate stopFilterDelegate = FTimerDelegate::CreateUObject(this, &ANetworkPlayer::StopFilter, filter, uniqueHandle);
GetWorldTimerManager().SetTimer(uniqueHandle, stopFilterDelegate, duration, false);
m_delegates.Add(uniqueHandle);
}
void ANetworkPlayer::SetTimelineDuration(float duration, UPostProcessComponent* filter)
{
FTimerHandle uniqueHandle;
FTimerDelegate stopFilterDelegate = FTimerDelegate::CreateUObject(this, &ANetworkPlayer::StopTimeline, filter, uniqueHandle);
GetWorldTimerManager().SetTimer(uniqueHandle, stopFilterDelegate, duration, false);
m_delegates.Add(uniqueHandle);
}
void ANetworkPlayer::StartFilter(float duration, UPostProcessComponent* filter, UCurveFloat* timelineCurve)
{
if ( m_filterTimelines.Contains(filter) ) return;
if (timelineCurve)
{
FTimeline timeLine;
FOnTimelineFloatStatic timelineDelegate;
timelineDelegate.BindUObject(this, &ANetworkPlayer::FilterUpdate, filter);
timeLine.AddInterpFloat(timelineCurve, timelineDelegate);
timeLine.SetPlayRate(1.0f / duration);
timeLine.PlayFromStart();
m_filterTimelines.Add(filter, timeLine);
SetFilterDuration(duration, filter);
}
filter->bEnabled = true;
}
void ANetworkPlayer::StartFilterWithDelegate(float duration, UPostProcessComponent* filter, UCurveFloat* timelineCurve, FPostAction action)
{
if ( m_filterTimelines.Contains(filter) ) return;
if (timelineCurve)
{
FTimeline timeLine;
FOnTimelineFloatStatic timelineDelegate;
timelineDelegate.BindUObject(this, &ANetworkPlayer::FilterUpdate, filter, action);
timeLine.AddInterpFloat(timelineCurve, timelineDelegate);
timeLine.SetPlayRate(1.0f / duration);
timeLine.PlayFromStart();
m_filterTimelines.Add(filter, timeLine);
SetFilterDuration(duration, filter);
}
filter->bEnabled = true;
}
void ANetworkPlayer::EnableFilter(float duration, UPostProcessComponent* filter, UCurveFloat* timelineCurve)
{
if (m_filterTimelines.Contains(filter)) return;
if (!timelineCurve)
{
YERROR("No timelineCurve given.");
return;
}
FTimeline timeLine;
FOnTimelineFloatStatic timelineDelegate;
timelineDelegate.BindUObject(this, &ANetworkPlayer::FilterUpdate, filter);
timeLine.AddInterpFloat(timelineCurve, timelineDelegate);
timeLine.SetPlayRate(1.0f / duration);
timeLine.PlayFromStart();
m_filterTimelines.Add(filter, timeLine);
SetTimelineDuration(duration, filter);
filter->bEnabled = true;
}
void ANetworkPlayer::DisableFilter(float duration, UPostProcessComponent* filter, UCurveFloat* timeline)
{
StartFilter(duration, filter, timeline);
}
void ANetworkPlayer::EnableFilterWithDelegate(float duration, UPostProcessComponent* filter, UCurveFloat* timelineCurve, FPostAction action)
{
if (m_filterTimelines.Contains(filter)) return;
if (!timelineCurve)
{
YERROR("No timelineCurve given.");
return;
}
FTimeline timeLine;
FOnTimelineFloatStatic timelineDelegate;
timelineDelegate.BindUObject(this, &ANetworkPlayer::FilterUpdate, filter, action);
timeLine.AddInterpFloat(timelineCurve, timelineDelegate);
timeLine.SetPlayRate(1.0f / duration);
timeLine.PlayFromStart();
m_filterTimelines.Add(filter, timeLine);
SetTimelineDuration(duration, filter);
filter->bEnabled = true;
}
void ANetworkPlayer::DisableFilterWithDelegate(float duration, UPostProcessComponent* filter, UCurveFloat* timeline, FPostAction action)
{
StartFilterWithDelegate(duration, filter, timeline, action);
}
void ANetworkPlayer::StopFilter(UPostProcessComponent* filter, FTimerHandle handle)
{
filter->bEnabled = false;
m_delegates.Remove(handle);
if (!m_filterTimelines.Contains(filter))
{
YERROR("Can't find filter in timeline.");
return;
}
m_filterTimelines.Remove(filter);
}
void ANetworkPlayer::StopTimeline( UPostProcessComponent* filter, FTimerHandle handle )
{
m_delegates.Remove(handle);
if (!m_filterTimelines.Contains(filter))
{
YERROR("Can't find filter in timeline.");
return;
}
m_filterTimelines.Remove(filter);
}
void ANetworkPlayer::FilterUpdate(float value, UPostProcessComponent* filter)
{
filter->BlendWeight = value;
}
void ANetworkPlayer::FilterUpdate(float value, UPostProcessComponent* filter, FPostAction action)
{
action.ExecuteIfBound(value, filter);
}
void ANetworkPlayer::AddThreatLevel_Client_Implementation(const float a_NewThreat)
{
threats.Add(a_NewThreat);
threatLevel = a_NewThreat > threatLevel ? a_NewThreat : threatLevel;
}
void ANetworkPlayer::RemoveThreatLevel_Client_Implementation(const float a_NewThreat)
{
threats.RemoveSingle(a_NewThreat);
if (a_NewThreat == threatLevel)
{
threatLevel = 0;
for (int32 i = 0; i < threats.Num(); i++)
{
if (threats[i] > threatLevel)
{
threatLevel = threats[i];
}
}
}
}

View File

@@ -0,0 +1,155 @@
// Project Lab - NHTV Igad
#pragma once
#include "Creatures/NetworkCharacter.h"
#include "IngameSkillTree.h"
#include "PlayerKeyType.h"
#include "NetworkPlayer.generated.h"
/**
*
*/
UCLASS()
class UNREALPROJECT_API ANetworkPlayer : public ANetworkCharacter
{
GENERATED_BODY()
public:
ANetworkPlayer();
virtual void BeginPlay() override;
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
virtual void Tick(float DeltaSeconds) override;
// For detecting when the player is possessed
virtual void PossessedBy(AController* NewController) override;
virtual void OnRep_PlayerState() override;
// Clears all the modifier stat modifications from this character
virtual void ResetModifiers();
UFUNCTION(Server, Reliable, WithValidation)
void ToggleSwitch(class ANetworkSwitch* networkSwitch);
// Server-Side level up event
UFUNCTION(BlueprintNativeEvent, Category = "LevelUp")
void OnLevelUp(int32 newLevel);
// Called server-side when a character levels up
void OnLevelUp_Server(int32 newLevel);
// Get the class properties of this player
UFUNCTION(BlueprintCallable, Category = "State")
FCharacterClassProperty GetCharacterClassProperties() const;
UFUNCTION(BlueprintCallable, Category = "Team")
class ANetworkPlayer* GetTeamMate() const;
DECLARE_DYNAMIC_MULTICAST_DELEGATE_FourParams(FOnPlayerKilled, FText, source, FText, target, int32, sourceNum, int32, targetNum);
UPROPERTY(BlueprintAssignable, Category = "Game")
FOnPlayerKilled onPlayerKilled;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Music")
float threatLevel;
TArray<float> threats;
UFUNCTION(Client, Reliable)
void AddThreatLevel_Client(const float a_NewThreat);
UFUNCTION(Client, Reliable)
void RemoveThreatLevel_Client(const float a_NewThreat);
// Base Stats for all characters
UPROPERTY(VisibleAnywhere, Category = "Stats")
UCurveFloat* healthCurve;
UPROPERTY(VisibleAnywhere, Category = "Stats")
UCurveFloat* healthRegenCurve;
UPROPERTY(VisibleAnywhere, Category = "Stats")
UCurveFloat* manaCurve;
UPROPERTY(VisibleAnywhere, Category = "Stats")
UCurveFloat* manaRegenCurve;
UPROPERTY(VisibleAnywhere, Category = "Stats")
UCurveFloat* armorCurve;
UPROPERTY(VisibleAnywhere, Category = "Stats")
UCurveFloat* attackSpeedCurve;
// Use these functions to sample the above curves, these functions also check class specific overrides
float SampleHealthCurve(float in);
float SampleManaCurve(float in);
float SampleArmorCurve(float in);
float SampleAttackSpeedCurve(float in);
// Creature level scaling logic
// Damage done to creatures
UPROPERTY(VisibleAnywhere, Category = "Stats")
UCurveFloat* creatureDamageTakenCurve;
// Damage dealt by creatures
UPROPERTY(VisibleAnywhere, Category = "Stats")
UCurveFloat* creatureDamageDealtCurve;
UFUNCTION(BlueprintCallable, Category = "Key")
bool HasKey(PlayerKeyType keyType) const;
UFUNCTION(BlueprintCallable, Category = "Key")
bool HasAnyKey() const;
bool AssignKey(PlayerKeyType keyType, class ASpawnerBase* origin);
bool ClearKey(PlayerKeyType keyType);
// Starts a filter for a duration with a timeline to control the blending.
UFUNCTION(BlueprintCallable, Category = "ScreenFilter")
void StartFilter(float duration, UPostProcessComponent* filter, UCurveFloat* timeline);
DECLARE_DYNAMIC_DELEGATE_TwoParams(FPostAction, float, value, UPostProcessComponent*, filter);
// Starts a filter for a duration with a timeline to control the blending.
UFUNCTION(BlueprintCallable, Category = "ScreenFilter")
void StartFilterWithDelegate(float duration, UPostProcessComponent* filter, UCurveFloat* timeline, FPostAction action);
// Starts a filter with a timeline to control the blending.
UFUNCTION(BlueprintCallable, Category = "ScreenFilter")
void EnableFilter(float duration, UPostProcessComponent* filter, UCurveFloat* timeline);
// Stops a filter after a duration with a timeline to control the blending.
UFUNCTION(BlueprintCallable, Category = "ScreenFilter")
void DisableFilter(float duration, UPostProcessComponent* filter, UCurveFloat* timeline);
// Starts a filter with a timeline to control the blending.
UFUNCTION(BlueprintCallable, Category = "ScreenFilter")
void EnableFilterWithDelegate(float duration, UPostProcessComponent* filter, UCurveFloat* timeline, FPostAction action);
// Stops a filter after a duration with a timeline to control the blending.
UFUNCTION(BlueprintCallable, Category = "ScreenFilter")
void DisableFilterWithDelegate(float duration, UPostProcessComponent* filter, UCurveFloat* timeline, FPostAction action);
// The ring below the player
UPROPERTY(BlueprintReadOnly, VisibleAnywhere)
UStaticMeshComponent* playerCircle;
protected:
void m_SetLevelStats() override;
private:
// Sets the duration of the filter.
// Creates a delagate for StopFilter.
void SetFilterDuration(float duration, UPostProcessComponent* filter);
// Sets the duration of the timeline.
// Creates a delagate for StopTimeline.
void SetTimelineDuration(float duration, UPostProcessComponent* filter);
// Disables the filter.
void StopFilter(UPostProcessComponent* filter, FTimerHandle handle);
// Clears the timeline.
void StopTimeline(UPostProcessComponent* filter, FTimerHandle handle);
// Updates the blending weight of the filter.
void FilterUpdate(float value, UPostProcessComponent* filter);
void FilterUpdate(float value, UPostProcessComponent* filter, FPostAction action);
// TODO: Add filter queue.
bool m_levelStatsInitialized;
UPROPERTY(Replicated)
uint8 m_keyState;
TMap<uint8, class ASpawnerBase*> m_keyOrigins;
TMap<UPostProcessComponent*, FTimeline> m_filterTimelines;
TArray<FTimerHandle> m_delegates;
};

View File

@@ -0,0 +1,106 @@
// Project Lab - NHTV Igad
#include "UnrealProject.h"
#include "NetworkPossessable.h"
#include "DefaultPlayerController.h"
// Sets default values
ANetworkPossessable::ANetworkPossessable()
{
}
// Called every frame
void ANetworkPossessable::Tick( float DeltaTime )
{
Super::Tick( DeltaTime );
m_UpdateCamera();
}
void ANetworkPossessable::AddMovementInput(FVector WorldDirection, float ScaleValue /*= 1.0f*/, bool bForce /*= false*/)
{
check(!WorldDirection.ContainsNaN());
check(!FMath::IsNaN(ScaleValue));
if(m_AllowedToMove())
Super::AddMovementInput(WorldDirection, ScaleValue, bForce);
}
void ANetworkPossessable::SetCharacterRotation(FRotator rotator)
{
if (m_AllowedToRotate())
SetActorRotation(rotator);
if(Role != ROLE_Authority)
{
m_SetCharacterRotation_Server(rotator.Yaw);
}
}
void ANetworkPossessable::AddControllerYawInput(float Val)
{
if(m_AllowedToRotate())
Super::AddControllerYawInput(Val);
}
bool ANetworkPossessable::m_SetCharacterRotation_Server_Validate(float rotation)
{
return true;
}
void ANetworkPossessable::m_SetCharacterRotation_Server_Implementation(float rotation)
{
SetActorRotation(FRotator(0.0f, rotation, 0.0f));
}
bool ANetworkPossessable::m_AllowedToMove()
{
return true;
}
bool ANetworkPossessable::m_AllowedToRotate()
{
return true;
}
void ANetworkPossessable::m_SetupCamera()
{
// Create a camera boom
CameraBoom = CreateDefaultSubobject<USpringArmComponent>(TEXT("CameraBoom"));
CameraBoom->AttachTo(RootComponent);
CameraBoom->bAbsoluteRotation = true;
CameraBoom->TargetArmLength = 1500.f;
CameraBoom->RelativeRotation = FRotator(-60.f, 45.f, 0.f);
CameraBoom->bDoCollisionTest = false;
CameraBoom->bInheritPitch = false;
CameraBoom->bInheritYaw = false;
CameraBoom->bInheritRoll = false;
// Create a camera
TopDownCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("TopDownCamera"));
TopDownCamera->AttachTo(CameraBoom, USpringArmComponent::SocketName);
TopDownCamera->bUsePawnControlRotation = false;
// Don't rotate character to camera direction
bUseControllerRotationPitch = false;
bUseControllerRotationYaw = false;
bUseControllerRotationRoll = false;
}
void ANetworkPossessable::m_UpdateCamera()
{
if (!IsValid(CameraBoom)) return;
ADefaultPlayerController* const controller = Cast<ADefaultPlayerController>(GetController());
if (IsValid(controller))
{
// Ensure the camera does not fall under the ground
const FVector playerCoord = GetActorLocation();
if (playerCoord.Z < 0)
CameraBoom->SetRelativeLocation(FVector(0, 0, -playerCoord.Z));
else if (CameraBoom->GetComponentLocation().Z < 0)
CameraBoom->SetRelativeLocation(FVector());
// Update last position
if (GetCharacterMovement()->IsMovingOnGround())
controller->UpdatePlayerPosition(GetActorLocation(), GetActorRotation());
}
}

View File

@@ -0,0 +1,35 @@
// Project Lab - NHTV Igad
#pragma once
#include "CharacterBase.h"
#include "NetworkPossessable.generated.h"
UCLASS(Abstract)
class UNREALPROJECT_API ANetworkPossessable : public ACharacterBase
{
GENERATED_BODY()
public:
ANetworkPossessable();
virtual void Tick( float DeltaSeconds ) override;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess = "true"))
class USpringArmComponent* CameraBoom;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess = "true"))
class UCameraComponent* TopDownCamera;
virtual void AddMovementInput(FVector WorldDirection, float ScaleValue = 1.0f, bool bForce = false) override;
virtual void SetCharacterRotation(FRotator rotator);
virtual void AddControllerYawInput(float Val) override;
protected:
UFUNCTION(Server, Reliable, WithValidation)
void m_SetCharacterRotation_Server(float rotation);
virtual bool m_AllowedToMove();
virtual bool m_AllowedToRotate();
void m_SetupCamera();
void m_UpdateCamera();
};

View File

@@ -0,0 +1,140 @@
// Project Lab - NHTV Igad
#include "UnrealProject.h"
#include "OffensiveEnemy.h"
#include "AbilityInfo.h"
#include "SpawnerBase.h"
#include "NetworkPlayer.h"
#include "MinionAnimInstance.h"
#include "BehaviorTree/EnemyAIController.h"
AOffensiveEnemy::AOffensiveEnemy()
{
PrimaryActorTick.bCanEverTick = true;
}
void AOffensiveEnemy::BeginPlay()
{
Super::BeginPlay();
if (Role != ROLE_Authority)
return;
}
void AOffensiveEnemy::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
Super::EndPlay(EndPlayReason);
if (Role != ROLE_Authority)
return;
}
void AOffensiveEnemy::Tick(float deltaTime)
{
Super::Tick(deltaTime);
if (Role != ROLE_Authority)
return;
if (IsValid(target))
{
if (hasGeneral)
{
GeneralBehavior();
}
else
{
if (m_confusionTimer > 0.0f)
{
ConfusionBehavior();
return;
}
BasicBehavior();
}
// Move to target
}
}
void AOffensiveEnemy::GeneralBehavior()
{
if (!meleeAbility || !specialAbility)
{
//RERROR("there is no abilities");
return;
}
const FVector2D actorLocation = FVector2D(GetActorLocation().X, GetActorLocation().Y);
const FVector2D targetLocation = FVector2D(target->GetActorLocation().X, target->GetActorLocation().Y);
const float targetDistSqr = FVector2D::DistSquared(targetLocation, actorLocation);
m_tempAbility = meleeAbility;
if (((m_tempAbility->AICastRange + 150)*(m_tempAbility->AICastRange + 150)) < targetDistSqr)
return;
if (GetAbilityState(m_tempAbility)->onCooldownTimer <= 0)
{
CastAbility(m_tempAbility);
UMinionAnimInstance* animInstance = Cast<UMinionAnimInstance>(GetMesh()->GetAnimInstance());
if (IsValid(animInstance))
{
animInstance->ChangeAnimationStateTo(EMinionAnimState::MAS_Attacking);
}
//m_rotateToPlayer = m_tempAbility->rotateTowardsPlayer;
}
}
void AOffensiveEnemy::BasicBehavior()
{
if (!IsValid(target))
return;
if (FVector::DistSquared(target->GetActorLocation(), GetActorLocation()) > 200 * 200)
{
MoveToPoint(target->GetActorLocation());
}
else
{
FVector addvec = GetActorLocation() - target->GetActorLocation();
addvec.Normalize();
MoveToPoint(target->GetActorLocation()+addvec*200.0f);
GetCharacterMovement()->Velocity = FVector::ZeroVector;
}
SetActorRotation(FVector(target->GetActorLocation() - GetActorLocation()).Rotation());
if (!meleeAbility || !specialAbility)
{
//RERROR("there is no abilities");
return;
}
const FVector2D actorLocation = FVector2D(GetActorLocation().X, GetActorLocation().Y);
const FVector2D targetLocation = FVector2D(target->GetActorLocation().X, target->GetActorLocation().Y);
const float targetDistSqr = FVector2D::DistSquared(targetLocation, actorLocation);
m_tempAbility = meleeAbility;
if ((rand() % 1000) > specialAbilityChance&&!m_isPulled)
{
m_tempAbility = specialAbility;
}
m_isPulled = true;
if (((m_tempAbility->AICastRange + 150)*(m_tempAbility->AICastRange + 150)) < targetDistSqr)
return;
if (GetAbilityState(m_tempAbility)->onCooldownTimer <= 0)
{
CastAbility(m_tempAbility);
UMinionAnimInstance* animInstance = Cast<UMinionAnimInstance>(GetMesh()->GetAnimInstance());
if (IsValid(animInstance))
{
animInstance->ChangeAnimationStateTo(EMinionAnimState::MAS_Attacking);
}
}
}
int32 AOffensiveEnemy::NativeDealDamage(class ANetworkCharacter* dealer, int32 damage, float armorPercentageIgnore, class UAbilityInfo* ability)
{
if (hasGeneral)
{
float damageMultiplier = FVector::DotProduct(dealer->GetActorForwardVector(), GetActorForwardVector());
damageMultiplier += 1.0f;
damageMultiplier *= 0.5f;
damageMultiplier += 0.5f;
return Super::NativeDealDamage(dealer, damage*damageMultiplier, armorPercentageIgnore, ability);
}
else return Super::NativeDealDamage(dealer, damage, armorPercentageIgnore, ability);
}

View File

@@ -0,0 +1,24 @@
// Project Lab - NHTV Igad
#pragma once
#include "Creatures/EnemyBase.h"
#include "OffensiveEnemy.generated.h"
/**
*
*/
UCLASS()
class UNREALPROJECT_API AOffensiveEnemy : public AEnemyBase
{
GENERATED_BODY()
public:
AOffensiveEnemy();
virtual void BeginPlay() override;
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
virtual void Tick(float deltaTime) override;
virtual int32 NativeDealDamage(class ANetworkCharacter* dealer, int32 damage, float armorPercentageIgnore, class UAbilityInfo* ability) override;
void BasicBehavior();
void GeneralBehavior();
};

View File

@@ -0,0 +1,16 @@
// Project Lab - NHTV Igad
#pragma once
UENUM(BlueprintType)
enum class PlayerKeyType : uint8
{
BossRoomKeyPart0 = 0,
BossRoomKeyPart1 = 1,
BossRoomKeyPart2 = 2,
TreasureRoomKey = 3,
None = 4,
};
constexpr int32 keyFragmentMin = (int32)PlayerKeyType::BossRoomKeyPart0;
constexpr int32 keyFragmentMax = (int32)PlayerKeyType::BossRoomKeyPart2;

View File

@@ -0,0 +1,136 @@
// Project Lab - NHTV Igad
#include "UnrealProject.h"
#include "RangedEnemy.h"
#include "AbilityInfo.h"
#include "SpawnerBase.h"
#include "NetworkPlayer.h"
#include "MinionAnimInstance.h"
ARangedEnemy::ARangedEnemy()
{
PrimaryActorTick.bCanEverTick = true;
}
void ARangedEnemy::BeginPlay()
{
Super::BeginPlay();
if (Role != ROLE_Authority)
return;
}
void ARangedEnemy::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
Super::EndPlay(EndPlayReason);
if (Role != ROLE_Authority)
return;
}
void ARangedEnemy::Tick(float deltaTime)
{
Super::Tick(deltaTime);
if (Role != ROLE_Authority)
return;
if (IsValid(target))
{
if (!hasGeneral)
{
if (m_confusionTimer > 0.0f)
{
ConfusionBehavior();
return;
}
BasicBehavior();
}
else
{
GeneralBehavior();
}
// Move to target
}
}
void ARangedEnemy::BasicBehavior()
{
if (!IsValid(target))
return;
const FVector2D actorLocation = FVector2D(GetActorLocation().X, GetActorLocation().Y);
const FVector2D targetLocation = FVector2D(target->GetActorLocation().X, target->GetActorLocation().Y);
const FVector2D spawnLocation = FVector2D(m_spawn->GetActorLocation());
const float targetDistSqr = FVector2D::DistSquared(targetLocation, actorLocation);
const float spawnTargetDistSqr = FVector2D::DistSquared(targetLocation, spawnLocation);
if (!meleeAbility || !specialAbility)
{
RERROR("there is no abilities");
return;
}
if (!rangedAbility)
{
RERROR("Ranged enemy does not have a ranged ability");
}
float castRange = rangedAbility->AICastRange;
// walking code
float testPercentage = (spawnTargetDistSqr) / ((m_spawn->aggroRadius + castRange)*(m_spawn->aggroRadius + castRange));
FVector newLocation = (target->GetActorLocation() - m_spawn->GetActorLocation());
newLocation.Normalize();
newLocation *= m_spawn->aggroRadius*testPercentage;
FVector walkLocation = newLocation + m_spawn->GetActorLocation();
if (m_lastPercentage < testPercentage)
MoveToPoint(walkLocation);
m_lastPercentage = testPercentage;
m_tempAbility = rangedAbility;
if (targetDistSqr < (200 * 200))
{
m_tempAbility = meleeAbility;
if ((rand() % 1000) > specialAbilityChance)
{
m_tempAbility = specialAbility;
}
}
if (((m_tempAbility->AICastRange + 100)*(m_tempAbility->AICastRange + 100)) < targetDistSqr)
return;
if (GetAbilityState(m_tempAbility)->onCooldownTimer <= 0)
{
ChangeNPCAnimation((uint8)EMinionAnimState::MAS_Casting);
CastAbility(m_tempAbility);
}
SetActorRotation(FVector(target->GetActorLocation() - GetActorLocation()).Rotation());
}
void ARangedEnemy::GeneralBehavior()
{
const FVector2D actorLocation = FVector2D(GetActorLocation().X, GetActorLocation().Y);
const FVector2D targetLocation = FVector2D(target->GetActorLocation().X, target->GetActorLocation().Y);
const FVector2D spawnLocation = FVector2D(m_spawn->GetActorLocation());
const float targetDistSqr = FVector2D::DistSquared(targetLocation, actorLocation);
const float spawnTargetDistSqr = FVector2D::DistSquared(targetLocation, spawnLocation);
if (!meleeAbility || !specialAbility)
{
RERROR("there is no abilities");
return;
}
if (!rangedAbility)
{
RERROR("Ranged enemy does not have a ranged ability");
}
float castRange = rangedAbility->AICastRange;
// walking code
m_tempAbility = rangedAbility;
if (targetDistSqr < (200 * 200))
{
m_tempAbility = meleeAbility;
}
if (((m_tempAbility->AICastRange + 100)*(m_tempAbility->AICastRange + 100)) < targetDistSqr)
return;
if (GetAbilityState(m_tempAbility)->onCooldownTimer <= 0)
{
ChangeNPCAnimation((uint8)EMinionAnimState::MAS_Casting);
CastAbility(m_tempAbility);
m_rotateToPlayer = m_tempAbility->rotateTowardsPlayer;
}
SetActorRotation(FVector(target->GetActorLocation() - GetActorLocation()).Rotation());
}

View File

@@ -0,0 +1,26 @@
// Project Lab - NHTV Igad
#pragma once
#include "Creatures/EnemyBase.h"
#include "RangedEnemy.generated.h"
/**
*
*/
UCLASS()
class UNREALPROJECT_API ARangedEnemy : public AEnemyBase
{
GENERATED_BODY()
public:
ARangedEnemy();
virtual void BeginPlay() override;
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
virtual void Tick(float deltaTime) override;
void BasicBehavior();
void GeneralBehavior();
private:
float m_lastPercentage;
class UAbilityInfo* m_tempAbility;
};

View File

@@ -0,0 +1,175 @@
// Project Lab - NHTV Igad
#include "UnrealProject.h"
#include "TouhouBoss.h"
#include "CreatureSpawn.h"
#include "AbilityEventGroup.h"
#include "AbilityInfo.h"
#include "Modifier.h"
#include "NativeModifiers.h"
#include "DefaultGameMode.h"
#include "NetworkPlayer.h"
ATouhouBoss::ATouhouBoss()
{
PrimaryActorTick.bCanEverTick = true;
/* AudioComp = CreateDefaultSubobject<UAudioComponent>(TEXT("Boss Audio"));
if (AudioComp)
{
AudioComp->bAutoActivate = false; // with this true the sounds play at spawn (game starts)
}
*/
outOfCombatRegen = 25.0f;
secondPhasePercentage = 0.5f;
rotationSpeed = 1;
cooldown = 2.5f;
}
void ATouhouBoss::BeginPlay()
{
Super::BeginPlay();
if (Role != ROLE_Authority)
return;
m_engaged = false;
}
void ATouhouBoss::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
Super::EndPlay(EndPlayReason);
if (Role != ROLE_Authority)
return;
m_walkTimer = 0.0f;
// Drop a key
if (m_health <= 0)
{
ANetworkPlayer* const killedBy = Cast<ANetworkPlayer>(GetLastPlayerDamage());
if (IsValid(killedBy) && IsValid(m_spawn))
{
killedBy->AssignKey(PlayerKeyType::TreasureRoomKey, m_spawn);
onBossKilled.Broadcast(killedBy->GetTeam());
}
}
}
void ATouhouBoss::m_Engaged()
{
Super::m_Engaged();
m_engaged = true;
ModifierManager* mod = GetModifierManager();
if (mod != nullptr && m_regenModifier != nullptr)
{
// Stop regenerating health.
m_regenModifier->ForceDestroy();
m_regenModifier = nullptr;
SetShield(false);
// Plays a sound indicating that the boss was engaged and start playing the boss music.
//PlayEngageSound();
}
}
void ATouhouBoss::m_Disengaged()
{
Super::m_Disengaged();
ModifierManager* mod = GetModifierManager();
if (mod != nullptr && m_regenModifier == nullptr)
{
m_engaged = false;
// Start regenerating health.
m_regenModifier = mod->AddModifier(ARegenModifier::StaticClass(), 0);
Cast<ARegenModifier>(m_regenModifier)->regenPerTick = outOfCombatRegen;
// Remove invincibility if it's active.
if (m_invincibilityModifier)
{
m_invincibilityModifier->ForceDestroy();
m_invincibilityModifier = nullptr;
SetShield(false);
}
}
}
void ATouhouBoss::Tick(float deltaTime)
{
Super::Tick(deltaTime);
// Only execute boss code on the server.
if (Role != ROLE_Authority)
return;
// Calculate health as percentage for deciding which phase the boss should be in.
float healthPerc = (float)m_health / (float)m_maxHealth;
// If the distance of the target to the spawn is greater than the aggro range of the spawner,
// then lose the target.
if (IsValid(target))
{
float targetDistSqr = FVector::DistSquared(target->GetActorLocation(), m_spawn->SpawnResetPosition());
float aggroSqr = m_spawn->deaggroRadius * m_spawn->deaggroRadius;
if (aggroSqr < targetDistSqr)
{
target = nullptr;
}
}
//disengage
if (!IsValid(target) && m_regenModifier == nullptr)
{
m_Disengaged();
}
//engage
else if (target && !m_engaged)
{
m_Engaged();
}
if (m_engaged)
{
if (m_invincibilityModifier)
{
m_invincibilityModifier->ForceDestroy();
m_invincibilityModifier = nullptr;
SetShield(false);
}
if (!IsValid(target))
return;
WalkPhase(deltaTime);
}
}
void ATouhouBoss::WalkPhase(float deltaTime)
{
MoveToPoint(target->GetActorLocation());
m_walkTimer += deltaTime;
// After 2.5 seconds, cast a random ability.
if (m_walkTimer > cooldown && abilities.Num() > 0 && target)
{
// Cast a random ability
UAbilityInfo* ability = abilities[FMath::Rand() % abilities.Num()];
if(IsValid(ability))
CastAbility(ability);
m_walkTimer = 0;
}
}
void ATouhouBoss::m_SpawnModifiers()
{
/*ModifierManager* mod = GetModifierManager();
if (mod != nullptr)
{
//m_regenModifier = mod->AddModifier(ARegenModifier::StaticClass(), 0);
}*/
}
void ATouhouBoss::SetShield_Implementation(bool on)
{
FWARNING("shield implemtentation not set in ATouHouBoss");
return;
}

View File

@@ -0,0 +1,60 @@
// Project Lab - NHTV Igad
#pragma once
#include "Creatures/BossBase.h"
#include "TouhouBoss.generated.h"
/**
*
*/
UCLASS()
class UNREALPROJECT_API ATouhouBoss : public ABossBase
{
GENERATED_BODY()
public:
ATouhouBoss();
virtual void BeginPlay() override;
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
virtual void Tick(float deltaTime) override;
void WalkPhase(float deltaTime);
virtual void m_SpawnModifiers() override;
//UFUNCTION(NetMulticast, Reliable)
//void PlayEngageSound();
//UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Audio Component")
//UAudioComponent* AudioComp;
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnBossKilled, int32, team);
UPROPERTY(BlueprintAssignable, Category = "Game")
FOnBossKilled onBossKilled;
UPROPERTY(EditDefaultsOnly, Category = "Shoot Phase")
class UAbilityInfo* ability;
UPROPERTY(EditDefaultsOnly, Category = "Shoot Phase")
class UAbilityInfo* abilityChannel;
UPROPERTY(EditDefaultsOnly, Category = "Shoot Phase")
float rotationSpeed;
UPROPERTY(EditDefaultsOnly, Category = "Shoot Phase")
float cooldown;
UPROPERTY(EditAnywhere, Category = "Modifiers")
float outOfCombatRegen;
UPROPERTY(EditAnywhere, Category = "State Transition", meta = (ClampMin = "0.0", ClampMax = "1.0", UIMin = "0.0", UIMax = "1.0"))
float secondPhasePercentage;
UFUNCTION(BlueprintNativeEvent)
void SetShield(bool on);
private:
virtual void m_Engaged();
virtual void m_Disengaged();
float m_walkTimer;
bool m_engaged;
UPROPERTY()
class AModifier* m_regenModifier;
UPROPERTY()
class AModifier* m_invincibilityModifier;
};

View File

@@ -0,0 +1,62 @@
// Project Lab - NHTV Igad
#include "UnrealProject.h"
#include "WiebertAnimation.h"
#include "NetworkCharacter.h"
#include "Animation/AnimNodeBase.h"
#include "AnimationProxy.h"
UWiebertAnimation::UWiebertAnimation(const FObjectInitializer& init)
: Super(init)
{
character = nullptr;
attacking = false;
charCustomization = FCharacterCustomization();
m_swingAnimationSequence = 0;
}
void UWiebertAnimation::NativeInitializeAnimation()
{
attacking = false;
Super::NativeInitializeAnimation();
character = Cast<ANetworkCharacter>(this->GetOwningActor());
if (character)
{
m_swingAnimationSequence = character->swingAnimationSequence;
}
}
void UWiebertAnimation::NativeUpdateAnimation(float DeltaSeconds)
{
if(character && character->swingAnimationSequence > m_swingAnimationSequence)
{
attacking = true;
m_swingAnimationSequence = character->swingAnimationSequence;
}
}
void UWiebertAnimation::SetCharacterCustomization(const FCharacterCustomization& characterCustomization)
{
charCustomization = characterCustomization;
}
FAnimInstanceProxy* UWiebertAnimation::CreateAnimInstanceProxy()
{
check(!m_mainAnimProxy);
m_mainAnimProxy = new FMainAnimProxy();
m_mainAnimProxy->boneNames[0] = "head";
m_mainAnimProxy->boneNames[1] = "thigh_l";
m_mainAnimProxy->boneNames[2] = "thigh_r";
m_mainAnimProxy->boneNames[3] = "upperarm_l";
m_mainAnimProxy->boneNames[4] = "upperarm_r";
m_mainAnimProxy->boneNames[5] = "spine_03";
m_mainAnimProxy->boneNames[6] = "root";
return m_mainAnimProxy;
}
void UWiebertAnimation::DestroyAnimInstanceProxy(FAnimInstanceProxy* InProxy)
{
check(InProxy == m_mainAnimProxy);
delete InProxy;
m_mainAnimProxy = nullptr;
}
void UWiebertAnimation::OnSwingAnimation_Implementation()
{
}

View File

@@ -0,0 +1,42 @@
// Project Lab - NHTV Igad
#pragma once
#include "Animation/AnimInstance.h"
#include "PlayerSetupState.h"
#include "WiebertAnimation.generated.h"
/**
*
*/
UCLASS()
class UNREALPROJECT_API UWiebertAnimation : public UAnimInstance
{
GENERATED_BODY()
public:
UWiebertAnimation(const FObjectInitializer& init);
virtual void NativeInitializeAnimation() override;
virtual void NativeUpdateAnimation(float DeltaSeconds) override;
virtual FAnimInstanceProxy* CreateAnimInstanceProxy();
virtual void DestroyAnimInstanceProxy(FAnimInstanceProxy* InProxy);
UFUNCTION(BlueprintNativeEvent, Category="Animation")
void OnSwingAnimation();
UFUNCTION(BlueprintCallable, Category = "Animation")
void SetCharacterCustomization(const FCharacterCustomization& characterCustomization);
UPROPERTY(BlueprintReadOnly, Category="Animation")
class ANetworkCharacter* character;
UPROPERTY(BlueprintReadWrite, Category = "Animation")
bool attacking;
FCharacterCustomization charCustomization;
private:
// Keeps track of how many times an animation was triggered
int32 m_swingAnimationSequence;
struct FMainAnimProxy* m_mainAnimProxy;
};