261 lines
8.7 KiB
C++
261 lines
8.7 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "SeagullGameCharacter.h"
|
|
|
|
#include "EnhancedInputComponent.h"
|
|
#include "EnhancedInputSubsystems.h"
|
|
#include "ItemActor.h"
|
|
#include "UObject/ConstructorHelpers.h"
|
|
#include "Camera/CameraComponent.h"
|
|
#include "Components/BoxComponent.h"
|
|
#include "Components/DecalComponent.h"
|
|
#include "Components/CapsuleComponent.h"
|
|
#include "GameFramework/CharacterMovementComponent.h"
|
|
#include "GameFramework/PlayerController.h"
|
|
#include "GameFramework/SpringArmComponent.h"
|
|
#include "Materials/Material.h"
|
|
#include "Engine/World.h"
|
|
|
|
ASeagullGameCharacter::ASeagullGameCharacter()
|
|
{
|
|
// Set size for player capsule
|
|
GetCapsuleComponent()->InitCapsuleSize(42.f, 96.0f);
|
|
|
|
// Don't rotate character to camera direction
|
|
bUseControllerRotationPitch = false;
|
|
bUseControllerRotationYaw = false;
|
|
bUseControllerRotationRoll = false;
|
|
|
|
// 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;
|
|
|
|
// Create a camera boom...
|
|
CameraBoom = CreateDefaultSubobject<USpringArmComponent>(TEXT("CameraBoom"));
|
|
CameraBoom->SetupAttachment(RootComponent);
|
|
CameraBoom->SetUsingAbsoluteRotation(true); // Don't want arm to rotate when character does
|
|
CameraBoom->TargetArmLength = 800.f;
|
|
CameraBoom->SetRelativeRotation(FRotator(-60.f, 0.f, 0.f));
|
|
CameraBoom->bDoCollisionTest = false; // Don't want to pull camera in when it collides with level
|
|
|
|
// Create a camera...
|
|
TopDownCameraComponent = CreateDefaultSubobject<UCameraComponent>(TEXT("TopDownCamera"));
|
|
TopDownCameraComponent->SetupAttachment(CameraBoom, USpringArmComponent::SocketName);
|
|
TopDownCameraComponent->bUsePawnControlRotation = false; // Camera does not rotate relative to arm
|
|
|
|
// Activate ticking in order to update the cursor every frame.
|
|
PrimaryActorTick.bCanEverTick = true;
|
|
PrimaryActorTick.bStartWithTickEnabled = true;
|
|
}
|
|
|
|
void ASeagullGameCharacter::Tick(float DeltaSeconds)
|
|
{
|
|
Super::Tick(DeltaSeconds);
|
|
|
|
if (JohnsCurrentHunger > 0)
|
|
{
|
|
JohnsCurrentHunger -= DeltaSeconds * JohnsHungerDeclineAmount;
|
|
}
|
|
else if (!bHasGameEnded)
|
|
{
|
|
JohnsCurrentHunger = 0;
|
|
OnGameEnd.Broadcast("You Lose!");
|
|
bHasGameEnded = true;
|
|
}
|
|
|
|
|
|
if (!IsValid(PickupBox)) return;
|
|
|
|
TArray<AActor*> OverlappingActors;
|
|
PickupBox->GetOverlappingActors(OverlappingActors, AItemActor::StaticClass());
|
|
float ClosestDistance = 0;
|
|
for (AActor* Actor : OverlappingActors)
|
|
{
|
|
if (Actor == this) continue;
|
|
float Distance = FVector::Dist(Actor->GetActorLocation(), GetActorLocation());
|
|
if (ClosestItemActor == nullptr || Distance < ClosestDistance)
|
|
{
|
|
if (IsValid(ClosestItemActor))
|
|
{
|
|
Cast<UMeshComponent>(ClosestItemActor->GetComponentByClass(UMeshComponent::StaticClass()))->SetRenderCustomDepth(false);
|
|
}
|
|
ClosestItemActor = Actor;
|
|
ClosestDistance = Distance;
|
|
}
|
|
}
|
|
if (!IsValid(ClosestItemActor)) return;
|
|
Cast<UMeshComponent>(ClosestItemActor->GetComponentByClass(UMeshComponent::StaticClass()))->SetRenderCustomDepth(true);
|
|
}
|
|
|
|
void ASeagullGameCharacter::BeginPlay()
|
|
{
|
|
Super::BeginPlay();
|
|
|
|
//Add Input Mapping Context
|
|
if (APlayerController* PlayerController = Cast<APlayerController>(Controller))
|
|
{
|
|
if (UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PlayerController->GetLocalPlayer()))
|
|
{
|
|
Subsystem->AddMappingContext(DefaultMappingContext, 0);
|
|
}
|
|
}
|
|
PickupBox = Cast<UBoxComponent>(GetComponentByClass(UBoxComponent::StaticClass()));
|
|
PickupBox->OnComponentBeginOverlap.AddDynamic(this, &ASeagullGameCharacter::OnPickupBoxBeginOverlap);
|
|
PickupBox->OnComponentEndOverlap.AddDynamic(this, &ASeagullGameCharacter::OnPickupBoxEndOverlap);
|
|
}
|
|
|
|
void ASeagullGameCharacter::DamagePlayer(float DamageAmount)
|
|
{
|
|
CurrentHealth -= DamageAmount;
|
|
OnPlayerDamage.Broadcast();
|
|
if (CurrentHealth <= 0)
|
|
{
|
|
CurrentHealth = 0;
|
|
OnPlayerDeath.Broadcast();
|
|
OnGameEnd.Broadcast("You Lose!");
|
|
bHasGameEnded = true;
|
|
}
|
|
}
|
|
|
|
void ASeagullGameCharacter::HealPlayer(float HealAmount)
|
|
{
|
|
CurrentHealth += HealAmount;
|
|
if (CurrentHealth > MaxHealth)
|
|
{
|
|
CurrentHealth = MaxHealth;
|
|
}
|
|
}
|
|
|
|
void ASeagullGameCharacter::StartGame()
|
|
{
|
|
JohnsCurrentHunger = JohnsDefaultHunger;
|
|
if (GetWorld()->GetTimerManager().IsTimerActive(GameTimerHandle))
|
|
{
|
|
GetWorld()->GetTimerManager().ClearTimer(GameTimerHandle);
|
|
}
|
|
GetWorld()->GetTimerManager().SetTimer(GameTimerHandle, this, &ASeagullGameCharacter::EndGame, GameTime, false);
|
|
|
|
FTimerHandle CravingTimerHandle;
|
|
GetWorld()->GetTimerManager().SetTimer(CravingTimerHandle, [this]()
|
|
{
|
|
TSubclassOf<AItemActor> ItemActor = ItemActors[FMath::RandRange(0, ItemActors.Num() - 1)];
|
|
if (IsValid(CravingItemActor)) CravingItemActor->Destroy();
|
|
CravingItemActor = GetWorld()->SpawnActor(ItemActor);
|
|
CurrentCraving = Cast<AItemActor>(CravingItemActor)->ItemType;
|
|
CravingItemActor->SetActorEnableCollision(false);
|
|
USkeletalMeshComponent* MeshComponent = GetMesh();
|
|
if (!MeshComponent->HasAnySockets()) return;
|
|
CravingItemActor->AttachToComponent(MeshComponent, FAttachmentTransformRules::SnapToTargetNotIncludingScale, "CravingSocket");
|
|
}, 30, true, 3);
|
|
}
|
|
|
|
void ASeagullGameCharacter::EndGame()
|
|
{
|
|
OnGameEnd.Broadcast("You Win!");
|
|
}
|
|
|
|
void ASeagullGameCharacter::PickupItem()
|
|
{
|
|
OnPlayerPickupItem.Broadcast();
|
|
if (IsValid(CurrentItem))
|
|
{
|
|
DropItem();
|
|
return;
|
|
}
|
|
USkeletalMeshComponent* MeshComponent = GetMesh();
|
|
if (!MeshComponent->HasAnySockets()) return;
|
|
if (!IsValid(ClosestItemActor)) return;
|
|
CurrentItem = GetWorld()->SpawnActor(Cast<AItemActor>(ClosestItemActor)->ItemNoPhysics);
|
|
CurrentItem->AttachToComponent(MeshComponent, FAttachmentTransformRules::SnapToTargetNotIncludingScale, "ItemSocket");
|
|
CurrentItem->SetActorEnableCollision(false);
|
|
ClosestItemActor->Destroy();
|
|
}
|
|
|
|
void ASeagullGameCharacter::DropItem()
|
|
{
|
|
if (!IsValid(CurrentItem)) return;
|
|
USkeletalMeshComponent* MeshComponent = GetMesh();
|
|
CurrentItem->DetachFromActor(FDetachmentTransformRules::KeepWorldTransform);
|
|
FVector DropLocation = MeshComponent->GetSocketLocation("ItemSocket");
|
|
DropLocation += GetActorForwardVector() * 100;
|
|
GetWorld()->SpawnActor(Cast<AItemActor>(CurrentItem)->ItemNoPhysics, &DropLocation);
|
|
CurrentItem->Destroy();
|
|
CurrentItem = nullptr;
|
|
}
|
|
|
|
void ASeagullGameCharacter::OnPickupBoxBeginOverlap(UPrimitiveComponent* OverlappedComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
|
|
{
|
|
}
|
|
|
|
void ASeagullGameCharacter::OnPickupBoxEndOverlap(UPrimitiveComponent* OverlappedComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex)
|
|
{
|
|
if (!Cast<AItemActor>(OtherActor)) return;
|
|
if (IsValid(OtherActor))
|
|
{
|
|
if (OtherActor == ClosestItemActor)
|
|
{
|
|
Cast<UMeshComponent>(OtherActor->GetComponentByClass(UMeshComponent::StaticClass()))->SetRenderCustomDepth(false);
|
|
ClosestItemActor = nullptr;
|
|
}
|
|
}
|
|
}
|
|
|
|
void ASeagullGameCharacter::IncreaseJohnsHunger(const float HungerAmount)
|
|
{
|
|
JohnsCurrentHunger += HungerAmount;
|
|
Score += HungerAmount * 10;
|
|
if (JohnsCurrentHunger > JohnsMaxHunger)
|
|
{
|
|
JohnsCurrentHunger = JohnsMaxHunger;
|
|
}
|
|
}
|
|
|
|
void ASeagullGameCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
|
|
{
|
|
// Set up action bindings
|
|
if (UEnhancedInputComponent* EnhancedInputComponent = CastChecked<UEnhancedInputComponent>(PlayerInputComponent))
|
|
{
|
|
//Jumping
|
|
EnhancedInputComponent->BindAction(JumpAction, ETriggerEvent::Triggered, this, &ACharacter::Jump);
|
|
EnhancedInputComponent->BindAction(JumpAction, ETriggerEvent::Completed, this, &ACharacter::StopJumping);
|
|
|
|
//Moving
|
|
EnhancedInputComponent->BindAction(MoveAction, ETriggerEvent::Triggered, this, &ASeagullGameCharacter::Move);
|
|
|
|
//Looking
|
|
// EnhancedInputComponent->BindAction(LookAction, ETriggerEvent::Triggered, this, &ATP_ThirdPersonCharacter::Look);
|
|
|
|
//Pickup
|
|
EnhancedInputComponent->BindAction(PickupAction, ETriggerEvent::Started, this, &ASeagullGameCharacter::PickupItem);
|
|
}
|
|
}
|
|
|
|
void ASeagullGameCharacter::Move(const FInputActionValue& Value)
|
|
{
|
|
// input is a Vector2D
|
|
FVector2D MovementVector = Value.Get<FVector2D>();
|
|
|
|
if (Controller != nullptr)
|
|
{
|
|
// find out which way is forward
|
|
const FRotator Rotation = Controller->GetControlRotation();
|
|
const FRotator YawRotation(0, Rotation.Yaw, 0);
|
|
|
|
// get forward vector
|
|
const FVector ForwardDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X);
|
|
|
|
// get right vector
|
|
const FVector RightDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y);
|
|
|
|
// add movement
|
|
AddMovementInput(ForwardDirection, MovementVector.Y);
|
|
AddMovementInput(RightDirection, MovementVector.X);
|
|
}
|
|
}
|
|
|
|
void ASeagullGameCharacter::Look(const FInputActionValue& Value)
|
|
{
|
|
}
|