Files
ProjectEleri/Source/ProjectEleri/NPC/NpcBaseCharacter.h

115 lines
4.8 KiB
C++

// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameplayTagContainer.h"
#include "Components/InteractionWidgetComponent.h"
#include "GameFramework/Pawn.h"
#include "Interface/InteractableActorInterface.h"
#include "NpcBaseCharacter.generated.h"
class UCapsuleComponent;
class UEleriFlipbookComponent;
class UExtendedPawnMovement;
class UInventoryComponent;
class UNpcScheduleComponent;
class UNpcStateMachineComponent;
USTRUCT(BlueprintType)
struct FNpcCharacterData
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (Categories = "NpcTags"))
FGameplayTag NpcTag;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
FText NpcName;
};
/**
* A scheduled NPC: a plain APawn with a capsule, a flipbook and nothing else, so that a town full
* of them stays affordable next to the player's ACharacter.
*
* It deliberately has no skeletal mesh, no character movement and no physics. Movement comes from
* UExtendedPawnMovement, which is a UFloatingPawnMovement rather than a UCharacterMovementComponent,
* and the pawn is possessed by an ABaseAIController: the state machine hands a destination to the
* movement component, which hands it on to the controller, and the path across the navmesh, the route
* around whatever stands in the way and the walking of it are all the engine's default path
* following. What the movement component does itself is keep the pawn on the floor and turn it to
* face the way it is going.
*
* Everything else it owns is a component and each one stands on its own, so the pawn is usable with
* any of them removed. The schedule decides what it should be doing and freezes it while the player
* is far away, the state machine walks it there and keeps it there, the inventory holds whatever it
* carries, and the interaction widget shows its prompt.
*/
UCLASS(BlueprintType)
class PROJECTELERI_API ANpcBaseCharacter : public APawn, public IInteractableActorInterface
{
GENERATED_BODY()
protected:
ANpcBaseCharacter();
public:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Components")
UCapsuleComponent* GetCapsuleComponent() const { return Capsule; }
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Components")
UEleriFlipbookComponent* GetFlipbookComponent() const { return FlipbookComponent; }
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Components")
UInventoryComponent* GetInventoryComponent() const { return InventoryComponent; }
/** The schedule driving this NPC, null when it is not scheduled. The save layer walks this
* to store and restore where an NPC stood and what it was doing. */
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Schedule")
UNpcScheduleComponent* GetScheduleComponent() const { return ScheduleComponent; }
/** The state machine running this NPC's behaviour: where it walks to and what it does once it is
* there. Handed its assignment by the schedule component and driven by nothing else. */
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Components")
UNpcStateMachineComponent* GetNpcStateMachine() const { return StateMachineComponent; }
virtual void ToggleInteractableUI_Implementation(bool bActive) override;
protected:
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Components")
TObjectPtr<UCapsuleComponent> Capsule;
/** Everything this NPC is drawn with. No mesh is created at all, so there is no skeleton, no
* anim blueprint and no bone work to pay for. */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Components")
TObjectPtr<UEleriFlipbookComponent> FlipbookComponent;
/** Walks the NPC wherever its StateTree sends it. Configure the speed on the component or on the
* task that did the sending. */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Movement")
TObjectPtr<UExtendedPawnMovement> MovementComponent;
/** Drives this NPC from its schedule and freezes it while the player is far away. */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Components")
TObjectPtr<UNpcScheduleComponent> ScheduleComponent;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Components")
TObjectPtr<UInventoryComponent> InventoryComponent;
/** Runs this NPC's behaviour: walks it to whatever the schedule assigned and does the action
* once it is there. Nothing is assigned to it, because everything it needs arrives from the
* schedule component on this NPC's first unfreeze. */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Components")
TObjectPtr<UNpcStateMachineComponent> StateMachineComponent;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
TObjectPtr<UInteractionWidgetComponent> WidgetComponent;
UPROPERTY(EditAnywhere, BlueprintReadOnly)
FNpcCharacterData NpcCharacterData;
};