pull/6/head
m4xxx1m 2 years ago
parent f798fd22b1
commit 3e2f409f43

1
.gitignore vendored

@ -1,5 +1,6 @@
# Visual Studio 2015 user specific files # Visual Studio 2015 user specific files
.vs/ .vs/
.idea/
# Compiled Object files # Compiled Object files
*.slo *.slo

@ -1,7 +1,7 @@
[/Script/EngineSettings.GameMapsSettings] [/Script/EngineSettings.GameMapsSettings]
EditorStartupMap=/Game/BattleField/BattleFieldMap.BattleFieldMap EditorStartupMap=/Game/MainMenu/MainMenuLevel.MainMenuLevel
LocalMapOptions= LocalMapOptions=
TransitionMap=None TransitionMap=None
bUseSplitscreen=True bUseSplitscreen=True

Binary file not shown.

Binary file not shown.

Binary file not shown.

@ -0,0 +1,149 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "EnemyAIController.h"
#include "SinglePlayerGS.h"
#include "Kismet/GameplayStatics.h"
#include "GenericPlatform/GenericPlatformMath.h"
AEnemyAIController::AEnemyAIController()
: Super() {
PrimaryActorTick.bCanEverTick = true;
SetActorTickInterval(0.3f);
}
void AEnemyAIController::Tick(float DeltaSeconds) {
Super::Tick(DeltaSeconds);
if (bIsAITurn && !bIsActing) {
if (TroopersCursor >= PossessedTroopers.Num()) {
EndTurn();
} else {
MakeMove();
}
}
}
void AEnemyAIController::StartTurn() {
UE_LOG(LogTemp, Warning, TEXT("Enemy AI StartTurn"));
bIsAITurn = true;
bIsActing = false;
// MakeMove();
}
void AEnemyAIController::EndTurn() {
bIsAITurn = false;
TroopersCursor = 0;
bIsEnded = true;
}
void AEnemyAIController::ActionDone() {
bIsActing = false;
}
bool AEnemyAIController::IsAITurn() const {
return bIsAITurn;
}
void AEnemyAIController::MakeMove() {
while (TroopersCursor < PossessedTroopers.Num()) {
while (TroopersCursor < PossessedTroopers.Num() && (
!PossessedTroopers[TroopersCursor] ||
!PossessedTroopers[TroopersCursor]->IsValidLowLevel()
|| PossessedTroopers[TroopersCursor]->IsDead())) {
++TroopersCursor;
}
if (TroopersCursor >= PossessedTroopers.Num()) {
return;
}
const int Index = GetClosestTrooper();
bool failed;
if (!IsCloseEnough(Index)) {
failed = MoveTo(Index);
} else {
failed = TryAttack(Index);
}
if (failed) {
TroopersCursor++;
} else {
return;
}
}
}
bool AEnemyAIController::IsCloseEnough(int TrooperIndex) const {
const ATrooper *CurrentTrooper = PossessedTroopers[TroopersCursor];
const ATrooper *OtherTrooper = PlayerTroopers[TrooperIndex];
return (CurrentTrooper->GetLocation() - OtherTrooper->GetLocation()).Size()
<= CurrentTrooper->GetRealActionRadius(1);
}
bool AEnemyAIController::TryAttack(int TrooperIndex) {
ATrooper *Attacker = PossessedTroopers[TroopersCursor];
const auto Location = PlayerTroopers[TrooperIndex]->GetLocation();
constexpr int ActionIndex = 1;
if (Attacker->CheckAttackCorrectness(Location, ActionIndex)) {
bIsActing = true;
Attacker->Attack(ActionIndex, Location);
return false;
}
return true;
}
bool AEnemyAIController::MoveTo(int TrooperIndex) {
ATrooper *Trooper = PossessedTroopers[TroopersCursor];
const FVector CurrentLocation = Trooper->GetLocation();
const FVector Destination = PlayerTroopers[TrooperIndex]->GetLocation();
constexpr int ActionIndex = 1;
constexpr int MoveActionIndex = 0;
const float AttackRadius = Trooper->GetRealActionRadius(ActionIndex);
const FVector Vector = Destination - CurrentLocation;
const float MaxLength = Trooper->GetRealActionRadius(MoveActionIndex);
float PathLength = Vector.Size() - AttackRadius + 10.f;
PathLength = FMath::Min(PathLength, MaxLength);
FVector Location = CurrentLocation + Vector.GetSafeNormal2D() *
PathLength;
Location.Z = 0.0f;
if (PathLength > 1.0f && Trooper->CheckMoveCorrectness(Location)) {
bIsActing = true;
Trooper->MoveTrooper(Location);
return false;
}
return true;
}
int AEnemyAIController::GetClosestTrooper() const {
float minDistance = 1000000.0f;
int minIndex = 0;
const ATrooper *CurrentTrooper = PossessedTroopers[TroopersCursor];
for (int index = 0; index < PlayerTroopers.Num(); ++index) {
const ATrooper *OtherTrooper = PlayerTroopers[index];
if (OtherTrooper->IsValidLowLevel() && !OtherTrooper->IsDead()) {
const float distance = (
CurrentTrooper->GetLocation() - OtherTrooper->
GetLocation()).Size();
if (distance < minDistance) {
minDistance = distance;
minIndex = index;
}
}
}
return minIndex;
}
void AEnemyAIController::InitializeTroopers(
const TArray<ATrooper *> &Troopers) {
for (const auto Trooper : Troopers) {
if (Trooper != nullptr) {
if (Trooper->GetPlayerIndex() == AI_INDEX) {
Trooper->SetAIPossession(this);
PossessedTroopers.Add(Trooper);
} else {
PlayerTroopers.Add(Trooper);
}
}
}
}
void AEnemyAIController::BeginPlay() {
Super::BeginPlay();
}

@ -0,0 +1,68 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "EnemyAIController.generated.h"
/**
*
*/
UCLASS()
class TURNBASEDTUTORIAL_API AEnemyAIController : public AActor {
GENERATED_BODY()
public:
static constexpr int AI_INDEX = 1;
AEnemyAIController();
UFUNCTION()
void StartTurn();
UFUNCTION()
void EndTurn();
UFUNCTION()
void ActionDone();
UFUNCTION()
void InitializeTroopers(const TArray<ATrooper *> &Troopers);
virtual void BeginPlay() override;
virtual void Tick(float DeltaSeconds) override;
UPROPERTY()
bool bIsEnded = false;
UFUNCTION()
bool IsAITurn() const;
private:
UFUNCTION()
void MakeMove();
UPROPERTY()
int TroopersCursor = 0;
int GetClosestTrooper() const;
bool IsCloseEnough(int TrooperIndex) const;
bool TryAttack(int TrooperIndex);
bool MoveTo(int TrooperIndex);
UPROPERTY()
bool bIsAITurn = false;
UPROPERTY()
bool bIsActing = false;
UPROPERTY()
TArray<ATrooper *> PossessedTroopers;
UPROPERTY()
TArray<ATrooper *> PlayerTroopers;
};

@ -4,7 +4,6 @@
#include "MyExplosion.h" #include "MyExplosion.h"
#include "Trooper.h" #include "Trooper.h"
#include "Components/SphereComponent.h"
#include "Net/UnrealNetwork.h" #include "Net/UnrealNetwork.h"
#include "Particles/ParticleSystemComponent.h" #include "Particles/ParticleSystemComponent.h"
@ -51,7 +50,7 @@ void AMyExplosion::NotifyActorBeginOverlap(AActor *OtherActor) {
PlayerIndex); PlayerIndex);
if (PlayerIndex != -1 && PlayerIndex != OtherTrooper-> if (PlayerIndex != -1 && PlayerIndex != OtherTrooper->
GetPlayerIndex()) { GetPlayerIndex()) {
OtherTrooper->TakeDamage(Damage); OtherTrooper->TrooperTakeDamage(Damage);
} }
} else { } else {
UE_LOG(LogTemp, Warning, TEXT("Overlapped not a trooper")); UE_LOG(LogTemp, Warning, TEXT("Overlapped not a trooper"));

@ -2,7 +2,6 @@
#pragma once #pragma once
#include "Components/SphereComponent.h"
#include "CoreMinimal.h" #include "CoreMinimal.h"
#include "GameFramework/Actor.h" #include "GameFramework/Actor.h"
#include "MyExplosion.generated.h" #include "MyExplosion.generated.h"

@ -27,7 +27,7 @@ public:
// UFUNCTION(BlueprintCallable) // UFUNCTION(BlueprintCallable)
// void CycleTurns(); // void CycleTurns();
private: protected:
void InitializeSpawnPointsIfNeeded(AController *Player); void InitializeSpawnPointsIfNeeded(AController *Player);
UFUNCTION(Server, Reliable) UFUNCTION(Server, Reliable)

@ -10,20 +10,27 @@ auto AMyGameState::GetMyPlayerState(uint8 PlayerIndex) const {
return Cast<AMyPlayerState>(PlayerArray[PlayerIndex]); return Cast<AMyPlayerState>(PlayerArray[PlayerIndex]);
} }
AMyGameState::AMyGameState() : Super() {
}
void AMyGameState::BeginPlay() { void AMyGameState::BeginPlay() {
Super::BeginPlay(); Super::BeginPlay();
LivingTroopers.SetNum(2); LivingTroopersCount.SetNum(2);
} }
void AMyGameState::AddTrooper_Implementation(ATrooper *Trooper) { void AMyGameState::AddTrooper_Implementation(ATrooper *Trooper) {
if (Trooper->GetPlayerIndex() >= 0 && Trooper->GetPlayerIndex() <= LivingTroopers.Num()) { if (Trooper->GetPlayerIndex() >= 0 && Trooper->GetPlayerIndex() <=
LivingTroopers[Trooper->GetPlayerIndex()]++; LivingTroopersCount.Num()) {
if (LivingTroopersCount.Num() < 2) {
LivingTroopersCount.SetNum(2);
}
LivingTroopersCount[Trooper->GetPlayerIndex()]++;
} }
Troopers.Add(Trooper); Troopers.Add(Trooper);
} }
void AMyGameState::StartGame_Implementation() { void AMyGameState::StartGame_Implementation() {
PlayerNotInTurn()->SetEnemySelection(); // PlayerNotInTurn()->SetEnemySelection();
PlayerInTurn()->SetEnemySelection(); PlayerInTurn()->SetEnemySelection();
bGameStarted = true; bGameStarted = true;
PlayerInTurn()->StartTurn(); PlayerInTurn()->StartTurn();
@ -75,9 +82,9 @@ bool AMyGameState::IsGameStarted() const {
void AMyGameState::DecreaseLivingTroopers(int PlayerIndex) { void AMyGameState::DecreaseLivingTroopers(int PlayerIndex) {
if (bGameIsOver) if (bGameIsOver)
return; return;
LivingTroopers[PlayerIndex]--; LivingTroopersCount[PlayerIndex]--;
if (LivingTroopers[PlayerIndex] <= 0) { if (LivingTroopersCount[PlayerIndex] <= 0) {
UE_LOG(LogTemp, Warning, TEXT("Player %d lose!"), PlayerIndex); UE_LOG(LogTemp, Warning, TEXT("Player %d lose!"), PlayerIndex);
bGameIsOver = true; bGameIsOver = true;
} }

@ -15,16 +15,18 @@ class TURNBASEDTUTORIAL_API AMyGameState : public AGameState {
GENERATED_BODY() GENERATED_BODY()
public: public:
AMyGameState();
virtual void BeginPlay() override; virtual void BeginPlay() override;
UFUNCTION(Server, Reliable) UFUNCTION(Server, Reliable)
void AddTrooper(ATrooper *Trooper); virtual void AddTrooper(ATrooper *Trooper);
UFUNCTION(Server, Reliable) UFUNCTION(Server, Reliable)
void StartGame(); void StartGame();
UFUNCTION(BlueprintCallable, Server, Reliable) UFUNCTION(BlueprintCallable, Server, Reliable)
void CycleTurns(); virtual void CycleTurns();
UFUNCTION(BlueprintPure) UFUNCTION(BlueprintPure)
AMyPlayerState *PlayerInTurn() const; AMyPlayerState *PlayerInTurn() const;
@ -44,7 +46,10 @@ public:
UFUNCTION() UFUNCTION()
void DecreaseLivingTroopers(int PlayerIndex); void DecreaseLivingTroopers(int PlayerIndex);
private: protected:
UPROPERTY()
bool IsMultiplayer = true;
UPROPERTY(Replicated) UPROPERTY(Replicated)
bool bGameIsOver = false; bool bGameIsOver = false;
@ -52,7 +57,7 @@ private:
TArray<ATrooper *> Troopers; TArray<ATrooper *> Troopers;
UPROPERTY(Replicated) UPROPERTY(Replicated)
TArray<int> LivingTroopers; TArray<int> LivingTroopersCount;
UPROPERTY(Replicated) UPROPERTY(Replicated)
bool bGameStarted = false; bool bGameStarted = false;

@ -29,11 +29,6 @@ void AMyPawn::MoveForward(float Val) {
} }
} }
// Called every frame
void AMyPawn::Tick(float DeltaTime) {
Super::Tick(DeltaTime);
}
// Called to bind functionality to input // Called to bind functionality to input
void AMyPawn::SetupPlayerInputComponent(UInputComponent *PlayerInputComponent) { void AMyPawn::SetupPlayerInputComponent(UInputComponent *PlayerInputComponent) {
Super::SetupPlayerInputComponent(PlayerInputComponent); Super::SetupPlayerInputComponent(PlayerInputComponent);

@ -22,8 +22,6 @@ protected:
virtual void MoveForward(float Val) override; virtual void MoveForward(float Val) override;
public: public:
// Called every frame
virtual void Tick(float DeltaTime) override;
// Called to bind functionality to input // Called to bind functionality to input
virtual void SetupPlayerInputComponent( virtual void SetupPlayerInputComponent(

@ -12,6 +12,7 @@ AMyPlayerController::AMyPlayerController()
: Super()/*, bIsMyTurn(false), SelectedTrooper(nullptr)*/ { : Super()/*, bIsMyTurn(false), SelectedTrooper(nullptr)*/ {
UE_LOG(LogTemp, Warning, TEXT("Player controller created")); UE_LOG(LogTemp, Warning, TEXT("Player controller created"));
SetShowMouseCursor(true); SetShowMouseCursor(true);
PlayerIndex = 0;
} }
void AMyPlayerController::BeginPlay() { void AMyPlayerController::BeginPlay() {

@ -1,8 +1,6 @@
// Fill out your copyright notice in the Description page of Project Settings. // Fill out your copyright notice in the Description page of Project Settings.
#include "MyPlayerState.h" #include "MyPlayerState.h"
#include "MyGameState.h" #include "MyGameState.h"
#include "Kismet/GameplayStatics.h" #include "Kismet/GameplayStatics.h"
#include "Net/UnrealNetwork.h" #include "Net/UnrealNetwork.h"
@ -81,9 +79,7 @@ void AMyPlayerState::MoveTrooper_Implementation(ATrooper *Trooper,
void AMyPlayerState::Attack_Implementation(ATrooper *Attacker, void AMyPlayerState::Attack_Implementation(ATrooper *Attacker,
FVector Location, FVector Location,
int ActionIndex, int ActionIndex) {
const TArray<ATrooper *> &
Troopers) {
if (Attacker->CheckAttackCorrectness(Location, ActionIndex)) { if (Attacker->CheckAttackCorrectness(Location, ActionIndex)) {
Attacker->Attack(ActionIndex, Location); Attacker->Attack(ActionIndex, Location);
// for (const auto Trooper : Troopers) { // for (const auto Trooper : Troopers) {
@ -169,7 +165,7 @@ void AMyPlayerState::OnPlayerAction(const FHitResult &HitResult) {
// ATTACK! ATTACK! // ATTACK! ATTACK!
UE_LOG(LogTemp, Warning, TEXT("Do attack")); UE_LOG(LogTemp, Warning, TEXT("Do attack"));
Attack(SelectedTrooper, NewlySelectedLocation, Attack(SelectedTrooper, NewlySelectedLocation,
CurrentAction, GetMyGameState()->GetTroopers()); CurrentAction);
SelectedTrooper->SetSelection(false, CurrentAction); SelectedTrooper->SetSelection(false, CurrentAction);
SelectedTrooper = nullptr; SelectedTrooper = nullptr;
break; break;

@ -33,8 +33,7 @@ public:
UFUNCTION(Server, Reliable) UFUNCTION(Server, Reliable)
void Attack(ATrooper *Attacker, void Attack(ATrooper *Attacker,
FVector Location, FVector Location,
int ActionIndex, int ActionIndex);
const TArray<ATrooper *> &Troopers);
// UFUNCTION(Client, Reliable) // UFUNCTION(Client, Reliable)
// void CycleTurns() const; // void CycleTurns() const;

@ -71,7 +71,7 @@ void AMyProjectile::NotifyActorBeginOverlap(AActor *OtherActor) {
PlayerIndex); PlayerIndex);
if (PlayerIndex != -1 && PlayerIndex != OtherTrooper-> if (PlayerIndex != -1 && PlayerIndex != OtherTrooper->
GetPlayerIndex()) { GetPlayerIndex()) {
OtherTrooper->TakeDamage(Damage); OtherTrooper->TrooperTakeDamage(Damage);
} }
} else { } else {
UE_LOG(LogTemp, Warning, TEXT("Overlapped not a trooper")); UE_LOG(LogTemp, Warning, TEXT("Overlapped not a trooper"));

@ -0,0 +1,19 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "SinglePlayerGM.h"
#include "SinglePlayerGS.h"
ASinglePlayerGM::ASinglePlayerGM() : Super() {
GameStateClass = ASinglePlayerGS::StaticClass();
}
void ASinglePlayerGM::BeginPlay() {
Super::BeginPlay();
UE_LOG(LogTemp, Warning, TEXT("SinglePlayer GameMode BeginPlay"));
GameStateClass = ASinglePlayerGS::StaticClass();
StartGame();
}
void ASinglePlayerGM::PostLogin(APlayerController *NewPlayer) {
AGameMode::PostLogin(NewPlayer);
}

@ -0,0 +1,23 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "MyGameMode.h"
#include "SinglePlayerGM.generated.h"
/**
*
*/
UCLASS()
class TURNBASEDTUTORIAL_API ASinglePlayerGM : public AMyGameMode {
GENERATED_BODY()
public:
ASinglePlayerGM();
virtual void BeginPlay() override;
virtual void PostLogin(APlayerController *NewPlayer) override;
};

@ -0,0 +1,56 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "SinglePlayerGS.h"
#include "Net/UnrealNetwork.h"
ASinglePlayerGS::ASinglePlayerGS()
: Super() {
IsMultiplayer = false;
PrimaryActorTick.bCanEverTick = true;
SetActorTickInterval(0.5f);
}
void ASinglePlayerGS::BeginPlay() {
Super::BeginPlay();
UE_LOG(LogTemp, Warning, TEXT("SinglePlayer GameState BeginPlay"));
if (LivingTroopersCount.Num() < 2) {
LivingTroopersCount.SetNum(2);
}
EnemyAiManager = GetWorld()->SpawnActor<AEnemyAIController>(
AEnemyAIController::StaticClass(), FVector(0.0f, 0.0f, 1000.0f),
FRotator(0.0f, 0.0f, 0.0f), FActorSpawnParameters());
EnemyAiManager->InitializeTroopers(Troopers);
}
void ASinglePlayerGS::CycleTurns() {
if (CurrentPlayerTurn == 0) {
PlayerInTurn()->EndTurn();
}
for (const auto Trooper : Troopers) {
if (Trooper != nullptr) {
Trooper->ResetActionPoints();
}
}
CurrentPlayerTurn = !CurrentPlayerTurn;
if (CurrentPlayerTurn == 0) {
PlayerInTurn()->StartTurn();
} else {
EnemyAiManager->StartTurn();
}
}
void ASinglePlayerGS::Tick(float DeltaSeconds) {
Super::Tick(DeltaSeconds);
if (EnemyAiManager->bIsEnded) {
EnemyAiManager->bIsEnded = false;
CycleTurns();
} else if (CurrentPlayerTurn == 1 && !EnemyAiManager->IsAITurn()) {
CycleTurns();
}
}
void ASinglePlayerGS::GetLifetimeReplicatedProps(
TArray<FLifetimeProperty> &OutLifetimeProps) const {
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
DOREPLIFETIME(ASinglePlayerGS, EnemyAiManager);
}

@ -0,0 +1,29 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "EnemyAIController.h"
#include "MyGameState.h"
#include "SinglePlayerGS.generated.h"
/**
*
*/
UCLASS()
class TURNBASEDTUTORIAL_API ASinglePlayerGS : public AMyGameState {
GENERATED_BODY()
public:
ASinglePlayerGS();
virtual void BeginPlay() override;
virtual void CycleTurns() override;
virtual void Tick(float DeltaSeconds) override;
protected:
UPROPERTY(Replicated)
AEnemyAIController *EnemyAiManager = nullptr;
};

@ -3,8 +3,6 @@
#include "HealthBar.h" #include "HealthBar.h"
#include "MyGameState.h" #include "MyGameState.h"
#include "MyPlayerController.h"
#include "MyPlayerState.h"
#include "MyProjectile.h" #include "MyProjectile.h"
#include "Components/WidgetComponent.h" #include "Components/WidgetComponent.h"
#include "Net/UnrealNetwork.h" #include "Net/UnrealNetwork.h"
@ -89,14 +87,16 @@ void ATrooper::Tick(float const DeltaTime) {
} }
if (AttackPlayedTime >= AttackDuration) { if (AttackPlayedTime >= AttackDuration) {
AttackPlayedTime = 0.0f; AttackPlayedTime = 0.0f;
bIsAttacking = false; // bIsAttacking = false;
SetIsAttacking(false);
} }
} }
if (bIsTakingDamage) { if (bIsTakingDamage) {
TakingDamagePlayedTime += DeltaTime; TakingDamagePlayedTime += DeltaTime;
if (TakingDamagePlayedTime >= TakingDamageDuration) { if (TakingDamagePlayedTime >= TakingDamageDuration) {
TakingDamagePlayedTime = 0.0f; TakingDamagePlayedTime = 0.0f;
bIsTakingDamage = false; // bIsTakingDamage = false;
SetIsTakingDamage(false);
} }
} }
if (bIsMoving) { if (bIsMoving) {
@ -106,7 +106,8 @@ void ATrooper::Tick(float const DeltaTime) {
if (PositionVector.Size() >= (TargetLocation - CurrentLocation). if (PositionVector.Size() >= (TargetLocation - CurrentLocation).
Size()) { Size()) {
CurrentLocation = TargetLocation; CurrentLocation = TargetLocation;
bIsMoving = false; // bIsMoving = false;
SetIsMoving(false);
} else { } else {
CurrentLocation += PositionVector; CurrentLocation += PositionVector;
} }
@ -114,6 +115,42 @@ void ATrooper::Tick(float const DeltaTime) {
} }
} }
void ATrooper::SetIsAttacking(bool IsAttacking) {
bIsAttacking = IsAttacking;
if (IsAttacking) {
SetActorTickEnabled(true);
} else {
TryDisableTick();
}
}
void ATrooper::SetIsTakingDamage(bool IsTakingDamage) {
bIsTakingDamage = IsTakingDamage;
if (IsTakingDamage) {
SetActorTickEnabled(true);
} else {
TryDisableTick();
}
}
void ATrooper::SetIsMoving(bool IsMoving) {
bIsMoving = IsMoving;
if (IsMoving) {
SetActorTickEnabled(true);
} else {
TryDisableTick();
}
}
void ATrooper::TryDisableTick() {
if (!bIsAttacking && !bIsTakingDamage && !bIsMoving) {
SetActorTickEnabled(false);
if (AIController && AIController->IsValidLowLevel()) {
AIController->ActionDone();
}
}
}
// void ATrooper::OnRepNotify_PlayerIndex() const { // void ATrooper::OnRepNotify_PlayerIndex() const {
// const AMyPlayerState *player = Cast<AMyPlayerState>( // const AMyPlayerState *player = Cast<AMyPlayerState>(
// GetPlayerState()); // GetPlayerState());
@ -131,7 +168,8 @@ void ATrooper::Tick(float const DeltaTime) {
void ATrooper::MoveTrooper_Implementation(FVector const NewPos) { void ATrooper::MoveTrooper_Implementation(FVector const NewPos) {
TargetLocation = NewPos; TargetLocation = NewPos;
bIsMoving = true; // bIsMoving = true;
SetIsMoving(true);
ActionPoints -= (NewPos - CurrentLocation).Size() * MoveCost; ActionPoints -= (NewPos - CurrentLocation).Size() * MoveCost;
} }
@ -196,6 +234,17 @@ float ATrooper::GetActionRadius(int action) const {
} }
} }
float ATrooper::GetRealActionRadius(int action) const {
switch (action) {
case 1:
return AttackAbility->ActionRadius;
case 2:
return SpecialAbility->ActionRadius;
default:
return ActionPoints / MoveCost;
}
}
float ATrooper::GetHitPoints() const { float ATrooper::GetHitPoints() const {
return HitPoints; return HitPoints;
} }
@ -247,7 +296,15 @@ UAbility *ATrooper::GetAbility(int AbilityIndex) const {
} }
} }
void ATrooper::TakeDamage_Implementation(float Damage) { void ATrooper::SetAIPossession(AEnemyAIController *EnemyController) {
AIController = EnemyController;
}
bool ATrooper::IsDead() const {
return bIsDead;
}
void ATrooper::TrooperTakeDamage_Implementation(float Damage) {
if (bIsTakingDamage || bIsDead) { if (bIsTakingDamage || bIsDead) {
return; return;
} }
@ -257,7 +314,8 @@ void ATrooper::TakeDamage_Implementation(float Damage) {
SetLifeSpan(DyingAnimationDuration); SetLifeSpan(DyingAnimationDuration);
GetWorld()->GetGameState<AMyGameState>()->DecreaseLivingTroopers(PlayerIndex); GetWorld()->GetGameState<AMyGameState>()->DecreaseLivingTroopers(PlayerIndex);
} else { } else {
bIsTakingDamage = true; // bIsTakingDamage = true;
SetIsTakingDamage(true);
} }
} }
@ -315,7 +373,8 @@ int ATrooper::GetAnimationValue() {
} }
void ATrooper::Attack_Implementation(int AbilityIndex, FVector ToLocation) { void ATrooper::Attack_Implementation(int AbilityIndex, FVector ToLocation) {
bIsAttacking = true; // bIsAttacking = true;
SetIsAttacking(true);
bIsWaitingForFire = true; bIsWaitingForFire = true;
ActionPoints -= GetAbility(AbilityIndex)->ActionCost; ActionPoints -= GetAbility(AbilityIndex)->ActionCost;
CurrentAbilityIndex = AbilityIndex; CurrentAbilityIndex = AbilityIndex;

@ -2,6 +2,7 @@
#include "CoreMinimal.h" #include "CoreMinimal.h"
#include "Ability.h" #include "Ability.h"
#include "EnemyAIController.h"
#include "GameFramework/Character.h" #include "GameFramework/Character.h"
#include "Trooper.generated.h" #include "Trooper.generated.h"
@ -44,6 +45,9 @@ public:
UFUNCTION() UFUNCTION()
float GetActionRadius(int action) const; float GetActionRadius(int action) const;
UFUNCTION()
float GetRealActionRadius(int action) const;
UFUNCTION() UFUNCTION()
float GetHitPoints() const; float GetHitPoints() const;
@ -66,10 +70,19 @@ public:
UAbility *GetAbility(int AbilityIndex) const; UAbility *GetAbility(int AbilityIndex) const;
UFUNCTION(Server, Reliable) UFUNCTION(Server, Reliable)
void TakeDamage(float Damage); void TrooperTakeDamage(float Damage);
UFUNCTION()
void SetAIPossession(AEnemyAIController *EnemyController);
UFUNCTION()
bool IsDead() const;
protected: protected:
constexpr static float PIXELS_IN_RADIUS = 50; constexpr static float PIXELS_IN_RADIUS = 50;
UPROPERTY()
AEnemyAIController *AIController = nullptr;
UPROPERTY(EditAnywhere) UPROPERTY(EditAnywhere)
UMaterialInterface *GreenMaterial = nullptr; UMaterialInterface *GreenMaterial = nullptr;
@ -179,6 +192,14 @@ protected:
UPROPERTY(Replicated) UPROPERTY(Replicated)
bool bIsMoving = false; bool bIsMoving = false;
void SetIsAttacking(bool IsAttacking);
void SetIsTakingDamage(bool IsTakingDamage);
void SetIsMoving(bool IsMoving);
void TryDisableTick();
}; };
// UCLASS() // UCLASS()

Loading…
Cancel
Save