CodeHumanCpp

#include "UnrealProject.h"

#include "HumanActorUFO.h"

#include "UFOGameMode.h"

 

 

AHumanActorUFO::AHumanActorUFO(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer)

{

 

//components

Box1 = ObjectInitializer.CreateDefaultSubobject<UBoxComponent>(this, "Box1");

RootComponent = Box1;

 

SkeletalMesh1 = ObjectInitializer.CreateDefaultSubobject<USkeletalMeshComponent>(this, "SkeletalMesh1");

SkeletalMesh1->AttachParent = RootComponent;

 

 

//states

currentHumanState = EHumanState::walking;

 

//modifiers

crawling = false;

panic = false;

stunned = false;

attracted = false;

spawning = true;

 

//generic

maxHealth = 100.0f;

currentHealth = maxHealth;

 

//Spawn Mod

maxTimeSpawnMod = 1.0f;

currentTimeSpawnMod = maxTimeSpawnMod;

 

//Panic

maxTimePanicMod = 4.0f;

currentTimePanicMod = maxTimePanicMod;

 

//Stunned

maxTimeStunnedMod = 4.0f;

currentTimeStunnedMod = maxTimeStunnedMod;

 

//walking

checkWallStartOffset = 20.0f;

 

//falling

startFallingLocation = FVector(0.0f, 0.0f, 0.0f);

endFallingLocation = FVector(0.0f, 0.0f, 0.0f);

groundTraceOffset = -40.0f;

groundTraceOffsetForward = -20.0f;

distanceToTraceGround = 60.0f;

fallingSpeedStart = 300.0f;

currentFallingSpeed = fallingSpeedStart;

fallingSpeedMax = 2000.0f;

gravity = 50.0f;

 

//dying

maxTimeDying = 0.2f;

currentTimeDying = maxTimeDying;

 

//culling

isAnimationDisabled = false;

isRenderingDisabled = false;

 

//speed

walkingSpeed = 200.0f;

panicSpeed = 500.0f;

crawlingSpeed = 50.0f;

currentSpeed = walkingSpeed;

 

}

 

 

void AHumanActorUFO::BeginPlay()

{

TActorIterator<AUFOGameMode> ActorItr(GetWorld());

gameMode = *ActorItr;

 

if (gameMode)

{

gameMode->AddHuman(this);

}

 

Super::BeginPlay();

 

}

 

 

void AHumanActorUFO::UpdateLogic(float deltaTimeIn)

{

deltaTime = deltaTimeIn;

 

switch (currentHumanState)

{

case EHumanState::walking :

WalkingLogic();

break;

 

case EHumanState::falling :

FallingLogic();

break;

 

case EHumanState::inBeam :

InBeamLogic(); //Called In blueprint

break;

 

case EHumanState::dying :

DyingLogic();

break;

 

case EHumanState::idle :

 

break;

 

case EHumanState::attract :

AttractLogic();

break;

}

}

 

 

void FORCEINLINE AHumanActorUFO::WalkingLogic()

{

 

 

CheckAndUpdateSpeedModifiers();

 

if (!spawning)

{

 

if ( IsWallInFront( checkWallStartOffset ) )

{

RotateActorRandom(25.0f);

}

else

{

MoveActorForward();

}

 

}

else

{

//If spawning modifier dont care about checking for collision

MoveActorForward();

}

 

if (!IsStandingOnGround(groundTraceOffset, groundTraceOffsetForward))

{

TryChangeStateToFalling();

}

 

}

 

 

void FORCEINLINE AHumanActorUFO::FallingLogic()

{

 

CheckAndUpdateSpeedModifiers();

 

if (IsStandingOnGround( groundTraceOffset, groundTraceOffsetForward ))

{

 

if ( MoveActorDownToGround( 40.0f, 1000.0f, endFallingLocation ) )

{

 

float dmg = CalculateFallDamage( startFallingLocation, endFallingLocation );

RemoveHealth(dmg);

TrySetCrawlingMod();

TryChangeStateToWalking();

currentFallingSpeed = fallingSpeedStart;

}

 

}

else

{

MoveActorDown();

CalculateFallingSpeed();

}

 

}

 

 

void FORCEINLINE AHumanActorUFO::DyingLogic_Implementation()

{

if (currentTimeDying <= 0)

{

SpawnBlood();

Destroy();

}

else

{

currentTimeDying -= deltaTime;

}

}

 

 

void FORCEINLINE AHumanActorUFO::InBeamLogic_Implementation()

{

 

 

}

 

 

void FORCEINLINE AHumanActorUFO::AttractLogic_Implementation()

{

 

 

}

 

 

void FORCEINLINE AHumanActorUFO::SpawnBlood()

{

FActorSpawnParameters parameters;

UWorld* world = GetWorld();

FHitResult outHit;

 

FVector down = FVector(0.0f, 0.0f, -1.0f);

FVector start = GetActorLocation();

FVector end = start + (down * 500);

 

parameters.bNoCollisionFail = true;

parameters.Owner = nullptr;

parameters.Instigator = nullptr;

parameters.bDeferConstruction = false;

 

//invisible actor is spawned to predict when blood is hitting the floor

world->SpawnActor<AActor>( blood, GetActorLocation(), FRotator::ZeroRotator, parameters);

 

Trace(this, outHit, start, end, ECollisionChannel::ECC_Camera, false);

 

UGameplayStatics::SpawnDecalAtLocation(world, bloodMaterial, FVector(128.0f, 128.0f, 20.0f), outHit.Location, FRotator(-90.0f, 0.0f, 0.0f), 30.0f );

}

 

//used for time dependent states

void FORCEINLINE AHumanActorUFO::CheckAndUpdateSpeedModifiers()

{

 

if (spawning)

{

currentTimeSpawnMod -= deltaTime;

 

if (currentTimeSpawnMod <= 0.0f)

{

spawning = false;

currentTimeSpawnMod = maxTimeSpawnMod;

}

}

 

if (panic)

{

 

currentTimePanicMod -= deltaTime;

 

if (currentTimePanicMod <= 0.0f)

{

panic = false;

currentTimePanicMod = maxTimePanicMod;

currentSpeed = walkingSpeed;

}

 

}

 

if (crawling)

{

currentSpeed = crawlingSpeed;

}

 

if (stunned)

{

currentSpeed = 0.0f;

 

currentTimeStunnedMod -= deltaTime;

 

if (currentTimeStunnedMod <= 0.0f)

{

 

currentSpeed = walkingSpeed;

currentTimeStunnedMod = maxTimeStunnedMod;

stunned = false;

 

}

}

}

 

 

void AHumanActorUFO::TryChangeStateToFalling()

{

switch (currentHumanState)

{

case EHumanState::walking :

case EHumanState::idle :

case EHumanState::inBeam :

case EHumanState::attract :

case EHumanState::dying :

startFallingLocation = GetActorLocation();

currentHumanState = EHumanState::falling;

currentFallingSpeed = fallingSpeedStart;

break;

}

}

 

 

void AHumanActorUFO::TryChangeStateToWalking()

{

switch (currentHumanState)

{

case EHumanState::idle :

case EHumanState::attract :

case EHumanState::falling :

currentHumanState = EHumanState::walking;

break;

}

}

 

 

void AHumanActorUFO::TryChangeStateToDying()

{

switch (currentHumanState)

{

case EHumanState::walking :

case EHumanState::idle :

case EHumanState::inBeam :

case EHumanState::attract :

case EHumanState::falling :

currentHumanState = EHumanState::dying;

break;

}

}

 

 

void AHumanActorUFO::TryChangeStateToInBeam()

{

switch (currentHumanState)

{

case EHumanState::walking :

case EHumanState::idle :

case EHumanState::attract :

case EHumanState::falling :

currentHumanState = EHumanState::inBeam;

break;

}

}

 

 

void AHumanActorUFO::TryChangeStateToAttract()

{

switch (currentHumanState)

{

case EHumanState::walking :

case EHumanState::idle :

case EHumanState::attract :

case EHumanState::falling :

case EHumanState::inBeam :

currentHumanState = EHumanState::attract;

break;

}

}

 

 

void AHumanActorUFO::SetPanicMod( FVector impactLocation )

{

panic = true;

currentTimePanicMod = maxTimePanicMod;

currentSpeed = panicSpeed;

 

FRotator newRot = FRotationMatrix::MakeFromX(GetActorLocation() - impactLocation).Rotator();

newRot = FRotator(0.0f, newRot.Yaw , 0.0f);

SetActorRotation(newRot);

 

}

 

 

void AHumanActorUFO::SetStunnedMod( )

{

stunned = true;

currentTimeStunnedMod = maxTimeStunnedMod;

currentSpeed = 0.0f;

}

 

 

bool AHumanActorUFO::TrySetCrawlingMod()

{

if (currentHealth <= (0.4 * maxHealth))

{

 

crawling = true;

currentSpeed = crawlingSpeed;

 

return true;

}

else

{

return false;

}

}

 

//used to disable rendering when the actor is not within view of the player or to far away

void AHumanActorUFO::DisableRendering(bool disableRendering)

{

if (isRenderingDisabled != disableRendering)

{

AActor::SetActorHiddenInGame(disableRendering);

isRenderingDisabled = disableRendering;

}

}

 

//used to disable animations when the actor is not within view of the player or to far away

void AHumanActorUFO::DisableAnimation(bool DisableAnimation)

{

 

if (isAnimationDisabled != DisableAnimation)

{

SkeletalMesh1->SetActive(!DisableAnimation);

isAnimationDisabled = DisableAnimation;

}

}

 

//used when hitting a wall and turns 180 d (+-) maxRotDeviatio

void FORCEINLINE AHumanActorUFO::RotateActorRandom( float maxRotDeviation )

{

 

float randomAngle = 180.0f - FMath::FRandRange(maxRotDeviation, -maxRotDeviation);

FRotator newRotation = GetActorRotation().Add(0.0f, randomAngle, 0.0f);

AActor::SetActorRotation(newRotation);

 

}

 

 

bool FORCEINLINE AHumanActorUFO::IsWallInFront( float startOffsetForward )

{

 

FHitResult hitResult;

FVector forwardVector = GetActorForwardVector();

FVector startOffset = forwardVector * startOffsetForward;

FVector start = GetActorLocation() + startOffset;

FVector movOffset = ( forwardVector * (currentSpeed * deltaTime));

FVector end = start + movOffset;

 

//check wall, return true if a wall is detected

if (Trace(this, hitResult, start, end, ECollisionChannel::ECC_Camera, false))

{

 

return true;

}

else

{

 

return false;

}

 

}

 

 

void FORCEINLINE AHumanActorUFO::MoveActorForward()

{

FVector movOffset = ( GetActorForwardVector() * (currentSpeed * deltaTime) );

 

RootComponent->MoveComponent(movOffset, GetActorRotation(), false);

}

 

 

void FORCEINLINE AHumanActorUFO::MoveActorDown( )

{

 

FVector downVector = FVector(0.0f, 0.0f, -1.0f);

FVector movOffset = (downVector * (currentFallingSpeed * deltaTime));

 

RootComponent->MoveComponent(movOffset, GetActorRotation(), false);

 

}

 

//used when human falls and lands on ground, not to move the human to far down

bool FORCEINLINE AHumanActorUFO::MoveActorDownToGround(float moveOffsetZ, float distanceToCheck, FVector& endPosition )

{

 

FHitResult hitResult;

FVector start = GetActorLocation();

FVector downVector = FVector(0.0f, 0.0f, -1.0f);

FVector end = start + ( downVector * distanceToCheck );

 

if (Trace(this, hitResult, start, end, ECollisionChannel::ECC_Camera, false))

{

 

endPosition = hitResult.Location;

 

FVector moveOffset = (endPosition - start);

moveOffset.Z += moveOffsetZ;

moveOffset.X = 0.0f;

moveOffset.Y = 0.0f;

 

RootComponent->MoveComponent( moveOffset, GetActorRotation(), false);

 

return true;

}

else

{

 

return false;

}

 

}

 

void FORCEINLINE AHumanActorUFO::CalculateFallingSpeed()

{

 

currentFallingSpeed += deltaTime * (gravity * gravity);

currentFallingSpeed = FMath::Clamp(currentFallingSpeed, 0.0f, fallingSpeedMax);

 

}

 

 

float FORCEINLINE AHumanActorUFO::CalculateFallDamage(const FVector& startLocation, const FVector& endLocation)

{

float dmgPerDistance = 0.05;

float distance = FVector::Dist(startLocation, endLocation);

float dmg = distance * dmgPerDistance;

 

//GEngine->AddOnScreenDebugMessage(-1, 1.0f, FColor::Green, FString("Fall Dmg: ") + FString::SanitizeFloat(dmg) );

 

return dmg;

}

 

//offsetForward can be used to check a bit behind humans so when falling not half the body is inside the building

bool FORCEINLINE AHumanActorUFO::IsStandingOnGround( float startOffsetZ, float offsetForward )

{

 

FHitResult hitResult;

FVector startOffset = FVector::ZeroVector;

startOffset.Z = startOffsetZ;

FVector start = GetActorLocation() + startOffset;

FVector downVector = FVector(0.0f, 0.0f, -1.0f);

FVector movOffset = (downVector * (currentFallingSpeed * deltaTime) + (GetActorForwardVector() * offsetForward ));

FVector end = start + movOffset;

 

if (Trace(this, hitResult, start, end, ECollisionChannel::ECC_Camera, false))

{

 

return true;

}

else

{

 

return false;

}

 

}

 

bool FORCEINLINE AHumanActorUFO::Trace(AActor* ActorToIgnore, FHitResult &OutHit, FVector &Start, FVector &End, ECollisionChannel CollisionChannel, bool Debug)

{

FCollisionQueryParams params = FCollisionQueryParams(FName(TEXT("TraceThings")));

 

params.bReturnPhysicalMaterial = false;

params.bTraceAsyncScene = false;

params.bTraceComplex = false;

params.AddIgnoredActor(ActorToIgnore);

 

GetWorld()->LineTraceSingle(OutHit, Start, End, CollisionChannel, params);

 

if (Debug)

{

DrawDebugLine(GetWorld(), Start, End, FColor::Red, false, -1, 0, 10.0f);

if (OutHit.bBlockingHit && OutHit.GetActor())

{

DrawDebugPoint(GetWorld(), OutHit.Location, 10.0f, FColor::Red, false, 0.03f);

GEngine->AddOnScreenDebugMessage(-1, 1.0f, FColor::Green, FString("Actor Hit: ") + (OutHit.GetActor()->GetName()));

}

else if (OutHit.bBlockingHit)

{

DrawDebugPoint(GetWorld(), OutHit.Location, 10.0f, FColor::Red, false, 0.03f);

GEngine->AddOnScreenDebugMessage(-1, 1.0f, FColor::Green, FString("Static Object Hit: ") );

}

}

 

return OutHit.bBlockingHit;

}

 

 

float AHumanActorUFO::RemoveHealth(float health)

{

currentHealth -= health;

 

if (currentHealth <= 0.0f)

{

TryChangeStateToDying();

}

 

return currentHealth;

}