You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
awesome_game/Source/TurnBasedTutorial/Trooper.cpp

339 lines
11 KiB

#include "Trooper.h"
#include <Kismet/GameplayStatics.h>
#include "HealthBar.h"
#include "MyProjectile.h"
#include "Components/WidgetComponent.h"
#include "Net/UnrealNetwork.h"
// Sets default values
ATrooper::ATrooper()
: HitPoints(StartHitPoints), ActionPoints(StartActionPoints) {
bReplicates = true;
PrimaryActorTick.bCanEverTick = true;
Tags.Add(FName("Trooper"));
AttackAbility = CreateDefaultSubobject<UAbility>("AttackAbility");
SpecialAbility = CreateDefaultSubobject<UAbility>("SpecialAbility");
HealthWidgetComponent = CreateDefaultSubobject<UWidgetComponent>(
"HealthBar");
HealthWidgetComponent->AttachToComponent(RootComponent,
FAttachmentTransformRules::KeepRelativeTransform);
SelectionStaticMesh = CreateDefaultSubobject<UStaticMeshComponent>(
"SelectionMesh");
static ConstructorHelpers::FObjectFinder<UStaticMesh> MeshToUse(TEXT(
"StaticMesh'/Game/StarterContent/Shapes/Shape_Cylinder.Shape_Cylinder'"));
SelectionStaticMesh->AttachToComponent(RootComponent,
FAttachmentTransformRules::KeepRelativeTransform);
SelectionStaticMesh->SetWorldScale3D({2.0f, 2.0f, 0.01f});
SelectionStaticMesh->SetVisibility(false);
if (MeshToUse.Object) {
SelectionStaticMesh->SetStaticMesh(MeshToUse.Object);
}
// SelectionStaticMesh->SetRelativeTransform(FTransform({1000,1000,100}, {0, 0, 0}), false,
// nullptr, ETeleportType::TeleportPhysics);
// SelectionStaticMesh->
// MyStaticMesh = CreateDefaultSubobject<UStaticMeshComponent>("Mesh");
// RootComponent = MyStaticMesh;
// MeshPath = TEXT("StaticMesh'/Game/StarterContent/Props/SM_Chair.SM_Chair'");
// static ConstructorHelpers::FObjectFinder<UStaticMesh> MeshToUse(MeshPath);
// if (MeshToUse.Object) {
// MyStaticMesh->SetStaticMesh(MeshToUse.Object);
// }
}
// void ATrooper::SetStaticMesh() const {
// static ConstructorHelpers::FObjectFinder<UStaticMesh> MeshToUse(
// TEXT(
// "StaticMesh'/Game/CityofBrass_Enemies/Static/Wizard_StaticMesh.Wizard_StaticMesh'"
// )
// );
// if (MeshToUse.Object) {
// MyStaticMesh->SetStaticMesh(MeshToUse.Object);
// }
// }
// Called when the game starts or when spawned
void ATrooper::BeginPlay() {
Super::BeginPlay();
Cast<UHealthBar>(HealthWidgetComponent->GetUserWidgetObject())->
SetOwnerTrooper(this);
}
void ATrooper::Initialize(uint8 const NewPlayerIndex,
FVector const SpawnLocation,
uint8 const NewId) {
PlayerIndex = NewPlayerIndex;
bIsMoving = false;
AttackPlayedTime = 0.0f;
TakingDamagePlayedTime = 0.0f;
CurrentLocation = SpawnLocation;
Id = NewId;
}
void ATrooper::Tick(float const DeltaTime) {
if (bIsAttacking) {
AttackPlayedTime += DeltaTime;
if (bIsWaitingForFire && AttackPlayedTime >= FireAfterTime) {
FireProjectile();
CurrentAbilityIndex = -1;
CurrentAbilityDestination = {};
bIsWaitingForFire = false;
}
if (AttackPlayedTime >= AttackDuration) {
AttackPlayedTime = 0.0f;
bIsAttacking = false;
}
}
if (bIsTakingDamage) {
TakingDamagePlayedTime += DeltaTime;
if (TakingDamagePlayedTime >= TakingDamageDuration) {
TakingDamagePlayedTime = 0.0f;
bIsTakingDamage = false;
}
}
if (bIsMoving) {
FVector PositionVector = (TargetLocation - CurrentLocation);
PositionVector.Normalize();
PositionVector *= (Speed * DeltaTime);
if (PositionVector.Size() >= (TargetLocation - CurrentLocation).
Size()) {
CurrentLocation = TargetLocation;
bIsMoving = false;
} else {
CurrentLocation += PositionVector;
}
SetActorLocation(CurrentLocation);
}
}
// void ATrooper::OnRepNotify_PlayerIndex() {
// UE_LOG(LogTemp, Warning,
// TEXT("On rep notify, index: %d, id: %d, on server: %d, player state: %d"),
// PlayerIndex, Id, GetNetMode() == NM_DedicatedServer, GetPlayerState() != nullptr);
// // if (GetNetMode() != NM_DedicatedServer && GetPlayerState()) {
// // if (Cast<AMyPlayerState>(GetPlayerState())->GetPlayerIndex() !=
// // PlayerIndex) {
// // HighlightAsEnemy();
// // }
// // }
// }
void ATrooper::MoveTrooper(FVector const NewPos) {
TargetLocation = NewPos;
bIsMoving = true;
ActionPoints -= (NewPos - CurrentLocation).Size() * MoveCost;
}
uint8 ATrooper::GetId() const {
return Id;
}
void ATrooper::GetLifetimeReplicatedProps(
TArray<FLifetimeProperty> &OutLifetimeProps) const {
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
DOREPLIFETIME(ATrooper, PlayerIndex);
DOREPLIFETIME(ATrooper, CurrentLocation);
DOREPLIFETIME(ATrooper, TargetLocation);
DOREPLIFETIME(ATrooper, bIsMoving);
DOREPLIFETIME(ATrooper, Id);
DOREPLIFETIME(ATrooper, bIsAttacking);
DOREPLIFETIME(ATrooper, HitPoints);
DOREPLIFETIME(ATrooper, ActionPoints);
DOREPLIFETIME(ATrooper, HealthWidgetComponent);
DOREPLIFETIME(ATrooper, AttackPlayedTime);
DOREPLIFETIME(ATrooper, TakingDamagePlayedTime);
DOREPLIFETIME(ATrooper, bIsTakingDamage);
DOREPLIFETIME(ATrooper, bIsDead);
DOREPLIFETIME(ATrooper, CurrentAbilityIndex);
DOREPLIFETIME(ATrooper, CurrentAbilityDestination);
}
uint8 ATrooper::GetPlayerIndex() const {
return PlayerIndex;
}
//
// ATrooperWizard::ATrooperWizard() {
// MeshPath = TEXT(
// // "StaticMesh'/Game/CityofBrass_Enemies/Static/Wizard_StaticMesh.Wizard_StaticMesh'");
// "StaticMesh'/Game/CityofBrass_Enemies/Static/SkeletonMelee_StaticMesh.SkeletonMelee_StaticMesh'");
// SetStaticMesh();
// }
//
// ATrooperSkeletonMelee::ATrooperSkeletonMelee() {
// MeshPath = TEXT(
// "StaticMesh'/Game/CityofBrass_Enemies/Static/SkeletonMelee_StaticMesh.SkeletonMelee_StaticMesh'");
// SetStaticMesh();
// }
FVector ATrooper::GetLocation() const {
return CurrentLocation;
}
float ATrooper::GetActionRadius(int action) const {
switch (action) {
case 1:
return AttackAbility->ActionCost <= ActionPoints
? AttackAbility->ActionRadius
: 0;
case 2:
return SpecialAbility->ActionCost <= ActionPoints
? SpecialAbility->ActionRadius
: 0;
default:
return ActionPoints / MoveCost;
}
}
float ATrooper::GetHitPoints() const {
return HitPoints;
}
float ATrooper::GetMaxHitPoints() const {
return StartHitPoints;
}
void ATrooper::SetSelection(bool Selection, uint8 ActionType) const {
if (SelectionStaticMesh) {
if (SelectionStaticMesh->GetMaterial(0) != GreenMaterial) {
SelectionStaticMesh->SetMaterial(0, GreenMaterial);
SelectionStaticMesh->SetRelativeLocation({0, 0, 1});
}
if (Selection) {
UpdateSelectionRadius(ActionType);
} else {
SelectionStaticMesh->SetWorldScale3D({2.f, 2.f, 0.01f});
}
SelectionStaticMesh->SetVisibility(Selection);
}
}
void ATrooper::UpdateSelectionRadius(uint8 ActionType) const {
const float radiusScale =
GetActionRadius(ActionType) / PIXELS_IN_RADIUS;
SelectionStaticMesh->SetWorldScale3D(
{radiusScale, radiusScale, 0.01f});
}
void ATrooper::HighlightAsEnemy_Implementation() const {
SelectionStaticMesh->SetVisibility(true);
}
void ATrooper::ResetActionPoints() {
ActionPoints = StartActionPoints;
}
UAbility *ATrooper::GetAbility(int AbilityIndex) const {
switch (AbilityIndex) {
case 1:
return AttackAbility;
case 2:
return SpecialAbility;
default:
return nullptr;
}
}
bool ATrooper::TakeDamage(float Damage) {
HitPoints = FMath::Max<float>(0, HitPoints - Damage);
if (HitPoints == 0) {
bIsDead = true;
return true;
}
bIsTakingDamage = true;
return false;
}
TSubclassOf<AMyProjectile> ATrooper::GetProjectileClass(
uint8 AbilityIndex) const {
switch (AbilityIndex) {
case 1:
return AttackProjectileClass;
case 2:
return SpecialProjectileClass;
default:
return AMyProjectile::StaticClass();
}
}
void ATrooper::FireProjectile_Implementation() {
if (!this || !this->IsValidLowLevel())
return;
FTransform SpawnTransform(
(CurrentAbilityDestination - CurrentLocation).Rotation());
const FVector TransformedVector = SpawnTransform.TransformVector(
{GetAbility(CurrentAbilityIndex)->LinearWidth / 2 + 50.0f, 0.0f,
88.0f});
const FVector SpawnLocation = CurrentLocation + TransformedVector;
SpawnTransform.SetLocation(SpawnLocation);
FActorSpawnParameters SpawnParameters;
SpawnParameters.Owner = this;
SpawnParameters.Instigator = GetInstigator();
SpawnParameters.SpawnCollisionHandlingOverride =
ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
AMyProjectile *Projectile = GetWorld()->SpawnActor<AMyProjectile>(
GetProjectileClass(CurrentAbilityIndex), SpawnTransform,
SpawnParameters);
Projectile->Initialize(GetAbility(CurrentAbilityIndex), CurrentAbilityIndex,
(CurrentAbilityDestination - SpawnLocation).
Size());
Projectile->Shoot(SpawnLocation, CurrentAbilityDestination);
}
int ATrooper::GetAnimationValue() {
if (bIsDead) {
return 4;
}
if (bIsTakingDamage) {
return 3;
}
if (bIsAttacking) {
return 2;
}
if (bIsMoving) {
return 1;
}
return 0;
}
void ATrooper::Attack(int AbilityIndex, FVector ToLocation) {
bIsAttacking = true;
bIsWaitingForFire = true;
ActionPoints -= GetAbility(AbilityIndex)->ActionCost;
CurrentAbilityIndex = AbilityIndex;
ToLocation.Z = 88.0f;
CurrentAbilityDestination = ToLocation;
// FTransform SpawnTransform((ToLocation - CurrentLocation).Rotation());
// SpawnTransform.SetLocation(
// CurrentLocation + SpawnTransform.TransformVector(
// {GetAbility(AbilityIndex)->LinearWidth/2 + 50.0f, 0.0f, 0.0f})
// );
// FActorSpawnParameters SpawnParameters;
// SpawnParameters.Owner = this;
// SpawnParameters.Instigator = GetInstigator();
// SpawnParameters.SpawnCollisionHandlingOverride =
// ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
// AMyProjectile *Projectile = GetWorld()->SpawnActor<AMyProjectile>(
// GetProjectileClass(AbilityIndex), SpawnTransform, SpawnParameters);
// Projectile->Initialize(GetAbility(AbilityIndex));
// Projectile->Shoot(CurrentLocation, ToLocation);
}
bool ATrooper::CheckMoveCorrectness(const FVector newPos) const {
return (newPos - CurrentLocation).Size() * MoveCost <= ActionPoints;
// return (newPos - CurrentLocation).Size() <= MoveRadius;
}
bool ATrooper::CheckAttackCorrectness(const FVector attackLocation,
int abilityIndex) const {
return GetAbility(abilityIndex) != nullptr && (
attackLocation - CurrentLocation).Size() < GetActionRadius(
abilityIndex);
// return (attackLocation - CurrentLocation).Size() <= AttackRadius;
}