Avant de commencer
Assurez-vous d'avoir terminé les objectifs suivants dans les sections précédentes de Coder un jeu d'aventure à la première personne :
Vous avez créé un personnage joueur à la première personne dans C++ dans Créer un personnage joueur avec des actions de commandes.
Vous avez configuré des éléments de jeu pilotés par les données pour gérer les données d'objet dans Gérer les éléments et les données.
Vous avez créé un objet à ramasser et l'avez ajouté à votre niveau dans Créer un objet à ramasser qui réapparaît.
Créer des objets de référence avec une nouvelle fonction CreateItemCopy
Avant de créer un nouvel objet à ramasser, vous devez modifier vos classes ItemDefinition et PickupBase pour permettre la capture d'un objet de référence parmi une plus grande variété de types d'objets.
Dans la fonction InitializePickup() de votre classe PickupBase, vous définissez un ReferenceItem de type UItemDefinition. Ceci est trop restrictif ; définir un objet de référence de cette manière n'inclut pas les propriétés supplémentaires que vous ajouterez à toute nouvelle classe d'objets spécialisés dérivée de UItemDefinition.
Pour résoudre ce problème, vous allez créer une nouvelle fonction virtuelle dans ItemDefinition qui crée et renvoie une copie de cet objet. Étant donné qu'il s'agit d'une fonction virtuelle, vous pouvez la remplacer dans toutes les classes qui héritent de la fonction UItemDefinition. Lorsque PickupBase appelle la fonction, le compilateur détermine la bonne fonction à appeler selon la classe à partir de laquelle elle a été appelée.
L'ajout de cette fonction à la classe parente ItemDefinition permet de s'assurer qu'elle est disponible si vous décidez de continuer à développer votre projet pour y inclure d'autres types d'objets héritant de la classe UItemDefinition.
Pour définir une nouvelle fonction CreateItemCopy() pour la création d'objets de référence, procédez comme suit :
Ouvrez
ItemDefinition.h. Dans la sectionpublic, déclarez une nouvelle fonction const virtuelle nomméeCreateItemCopy()qui renvoie un pointeurUItemDefinition.C++// Creates and returns a copy of the item. virtual UItemDefinition* CreateItemCopy() const;Dans
ItemDefinition.cpp, implémentez la fonctionCreateItemCopy(). À l'intérieur, créez un nouveau pointeur d'objetUItemDefinitionappeléItemCopyen utilisant la fonctionStaticClass().C++UItemDefinition* UItemDefinition::CreateItemCopy() const { UItemDefinition* ItemCopy = NewObject<UItemDefinition>(StaticClass()); }Visual Studio supprime l'ambiguïté de
UItemDefinition::StaticClass()versStaticClass().Assignez chaque champ de
ItemCopyaux champs de cette classe et renvoyezItemCopy:C++/** * Creates and returns a copy of this Item Definition. * @return a copy of the item. */ UItemDefinition* UItemDefinition::CreateItemCopy() const { UItemDefinition* ItemCopy = NewObject<UItemDefinition>(StaticClass()); ItemCopy->ID = this->ID; ItemCopy->ItemType = this->ItemType;
Ensuite, refactorisez votre fonction InitializePickup() en supprimant le code qui configure manuellement ReferenceItem et remplacez ce code par un appel CreateItemCopy().
Pour mettre à jour InitializePickup() avec votre nouvelle fonction CreateItemCopy(), procédez comme suit :
Ouvrez
PickupBase.cppet accédez àInitializePickup().Supprimez ces cinq lignes qui définissent et configurent
ReferenceItem:C++ReferenceItem = NewObject<UItemDefinition>(this, UItemDefinition::StaticClass()); ReferenceItem->ID = ItemDataRow->ID; ReferenceItem->ItemType = ItemDataRow->ItemType; ReferenceItem->ItemText = ItemDataRow->ItemText; ReferenceItem->WorldMesh = ItemDataRow->ItemBase->WorldMesh;dans
ReferenceItem, en appelantTempItemDefinition->CreateItemCopy():C++// Create a copy of the item with the class type ReferenceItem = TempItemDefinition->CreateItemCopy();
Enregistrez PickupBase.cpp. Votre fonction InitializePickup() doit maintenant ressembler à ce qui suit :
if (PickupDataTable && !PickupItemID.IsNone())
{
// Retrieve the item data associated with this pickup from the data table
const FItemData* ItemDataRow = PickupDataTable->FindRow<FItemData>(PickupItemID, PickupItemID.ToString());
UItemDefinition* TempItemDefinition = ItemDataRow->ItemBase.Get();
// Create a copy of the item with the class type
ReferenceItem = TempItemDefinition->CreateItemCopy();
}Définir les données d'outil à équiper
Dans la section précédente, vous avez appris à créer des objets interactifs à ramasser dans votre niveau, qui sont des représentations concrètes des données d'une table. Dans cette section, vous allez apprendre à créer des outils que votre personnage peut équiper.
Pour configurer un nouvel outil à équiper, vous devez créer les éléments suivants :
EquipableToolDefinition: classe de ressource de données dérivée deItemDefinition, qui stocke les données de l'outil.EquipableToolBase: classe d'acteur qui représente l'outil dans le jeu. Cette classe fournit les animations, les mappages d'entrée et le maillage au personnage pour qu'il puisse se saisir de l'outil et le faire fonctionner.
Pour que votre personnage puisse ramasser des outils et les équiper, vous allez spécifier :
Un emplacement où stocker des objets.
Un moyen de connaître le type de chaque élément de l'inventaire.
Une façon d'équiper les outils.
N'oubliez pas que l'acteur EquipableToolBase représente l'outil que tient votre personnage et qu'il utilise. L'acteur PickupBase représente l'objet à ramasser de votre niveau. Votre personnage doit entrer en collision avec l'objet à ramasser avant de pouvoir l'équiper. Vous allez donc également modifier PickupBase pour remettre l'objet au personnage après une collision réussie.
Ensuite, vous combinerez votre nouvelle classe d'outil avec les objets à ramasser et la table de données que vous avez déjà créés pour concevoir un lance-fléchettes personnalisé et l'associer à votre personnage.
Commencez par définir les données de votre outil dans une nouvelle classe ItemDefinition.
Pour créer une nouvelle classe EquippableToolDefinition, procédez comme suit :
Dans l'Unreal Editor, accédez à Outils > Nouvelle classe C++. Accédez à Toutes les classes, recherchez et sélectionnez la classe parente ItemDefinition, puis cliquez sur Suivant.
Nommez la classe
EquippableToolDefinition, puis cliquez sur Créer la classe.Dans Visual Studio, en haut de
EquippableToolDefinition.h, ajoutez une instruction include pour"ItemDefinition.h", puis ajoutez les déclarations avancées suivantes :class UInputMappingContext: chaque outil à équiper doit contenir une référence à un contexte de mappage d'entrée que vous appliquerez au personnage qui maniera cet outil.AEquippableToolBase: acteur qui représente vos outils dans le jeu. Vous créerez ces éléments à la prochaine étape.C++#pragma once #include "CoreMinimal.h" #include "ItemDefinition.h" #include "EquippableToolDefinition.generated.h" class AEquippableToolBase; class UInputMappingContext; UCLASS(BlueprintType, Blueprintable)
Dans la section
public, ajoutez une propriétéTSubclassOfde typeAEquippableToolBaseappeléeToolAsset. Attribuez-lui une macroUPROPERTY()avecEditDefaultsOnly.C++// The tool actor associated with this item UPROPERTY(EditDefaultsOnly) TSubclassOf<AEquippableToolBase> ToolAsset;TSubclassOf<AEquippableToolBase>est un wrapper de modèle autour deUClassqui vous permet de référencer les sous-classes de blueprint deAEquippableToolBasetout en assurant la sécurité du type. Cette fonction est utile dans les jeux où vous souhaitez faire apparaître différents types d'acteurs de façon dynamique.Vous allez utiliser
ToolAssetpour faire apparaître de façon dynamique un acteur d'outil lorsqu'il est équipé sur votre personnage.Déclarez un remplacement pour la fonction
CreateItemCopy()que vous avez déclarée dansUItemDefinition. Ce remplacement crée et renvoie une copie de la classeUEquipableToolDefinition.Votre fichier
EquippableToolDefinition.hcomplet doit ressembler à ce qui suit :C++// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "CoreMinimal.h" #include "ItemDefinition.h" #include "EquippableToolDefinition.generated.h" class AEquippableToolBase; class UInputMappingContext;Dans
EquippableToolDefinition.cpp, implémentez la fonctionCreateItemCopy(). Elle doit être similaire à la fonctionCreateItemCopy()dansItemDefinition.cpp, sauf que vous allez maintenant également copierToolAsset.C++// Copyright Epic Games, Inc. All Rights Reserved. #include "EquippableToolDefinition.h" UEquippableToolDefinition* UEquippableToolDefinition::CreateItemCopy() const { UEquippableToolDefinition* ItemCopy = NewObject<UEquippableToolDefinition>(StaticClass()); ItemCopy->ID = this->ID; ItemCopy->ItemType = this->ItemType;
Enregistrez les deux fichiers de classe EquipableToolDefinition.
Configurer un acteur d'outil à équiper
Dans cette étape, vous allez créer votre acteur d'outil à équiper. Il s'agit de la représentation dans le jeu qui ajoute les animations, les contrôles et le maillage de l'outil au personnage.
Pour créer et configurer un nouvel acteur d'outil à équiper de base, procédez comme suit :
Dans l'Unreal Editor, accédez à Outils > Nouvelle classe C++. Sélectionnez Acteur comme classe parente et nommez la classe EquippableToolBase.
Cliquez sur Créer une classe. L'Unreal Engine ouvre automatiquement les fichiers de votre nouvelle classe dans VS.
En haut de
EquippableToolBase.h, déclarez directement la classeAAdventureCharacteret la classeUInputAction. L'outil à équiper doit savoir à quel personnage il est associé afin de pouvoir lier les actions d'entrée propres à cet outil.Dans la macro
UCLASSde la déclaration de classe, ajoutez les spécificateursBlueprintTypeetBlueprintablepour exposer cette classe aux blueprints.C++UCLASS(BlueprintType, Blueprintable) class ADVENTUREGAME_API AEquippableToolBase : public AActor
Déclarer les animations d'outils
Dans EquipableToolBase.h, dans la section public, ajoutez deux propriétés TObjectPtr aux propriétés UAnimBlueprint nommées FirstPersonToolAnim et ThirdPersonToolAnim. Il s'agit des animations à la première personne et à la troisième personne que le personnage utilise lorsqu'il est équipé de cet outil.
Attribuez à ces propriétés une macro UPROPERTY() avec EditAnywhereet BlueprintReadOnly.
// First Person animations
UPROPERTY(EditAnywhere, BlueprintReadOnly)
TObjectPtr<UAnimBlueprint> FirstPersonToolAnim;
// Third Person animations
UPROPERTY(EditAnywhere, BlueprintReadOnly)
TObjectPtr<UAnimBlueprint> ThirdPersonToolAnim;Créer le maillage de l'outil
Dans EquippableToolBase.h, dans la section public, ajoutez un TObjectPtr à un USkeletalMeshComponent appelé ToolMeshComponent. Il s'agit du maillage squelettique de l'outil, que le personnage voit lorsqu'il est équipé. Attribuez-lui une macro UPROPERTY() avec EditAnywhere et BlueprintReadOnly.
// Tool Skeletal Mesh
UPROPERTY(EditAnywhere, BlueprintReadOnly)
TObjectPtr<USkeletalMeshComponent> ToolMeshComponent;Dans EquipableToolBase.cpp, modifiez la fonction de constructeur AEquippableToolBase() pour créer un USkeletalMeshComponent par défaut et l'assigner à ToolMeshComponent. Vérifiez ensuite si le ToolMeshComponent n'est pas nul pour vous assurer que votre outil dispose d'un modèle lorsqu'il est chargé.
AEquippableToolBase::AEquippableToolBase()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
// Create this tool's mesh component
ToolMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("ToolMesh"));
check(ToolMeshComponent != nullptr);
}
Déclarer le propriétaire de l'outil
Dans EquippableToolBase.h, dans la section public, créez un TObjectPtr sur une instance de votre classe de personnage appelée OwningCharacter. Attribuez-lui une macro UPROPERTY() avec EditAnywhere et BlueprintReadOnly.
Il s'agit du personnage auquel cet outil est actuellement équipé.
// The character holding this tool
UPROPERTY(EditAnywhere, BlueprintReadOnly)
TObjectPtr<AAdventureCharacter> OwningCharacter;Déclarer une entrée et une fonction Use-Tool
Votre outil est fourni avec un contexte de mappage d'entrées et une action d'entrée qu'il doit fournir au personnage.
Pour ajouter le contexte de mappage d'entrées, dans la section public, déclarez un TObjectPtr sur un UInputMappingContext nommé ToolMappingContext. Attribuez-lui une macro UPROPERTY() avec EditAnywhere et BlueprintReadOnly.
// The input mapping context associated with this tool
UPROPERTY(EditAnywhere, BlueprintReadOnly)
TObjectPtr<UInputMappingContext> ToolMappingContext;De la même manière que vous avez implémenté les contrôles de déplacement, vous allez ajouter une fonction qui implémente une action use-tool ainsi qu’une nouvelle fonction qui lie une action d'entrée à la fonction.
Dans EquippableToolBase.h, dans la section public, déclarez deux fonctions void virtuelles nommées Use() et BindInputAction().
Lorsque vous implémentez des contrôles de déplacement de personnage, vous utilisez la fonction BindAction() de InputComponent, qui vous demande de transmettre le nom exact de la fonction cible. Étant donné que vous ne connaissez pas encore le nom complet de la fonction, vous devez disposer d'une fonction personnalisée BindInputAction() que vous pouvez implémenter dans chaque sous-classe EquipableToolBase pour appeler BindAction en transmettant [ToolChildClass]::Use.
La fonction BindInputAction() prend un pointeur const UInputAction et associe l'action d'entrée donnée à la fonction Use() du personnage.
// Use the tool
UFUNCTION()
virtual void Use();
// Binds the Use function to the owning character
UFUNCTION()
virtual void BindInputAction(const UInputAction* ActionToBind);Dans EquipableToolBase.cpp, implémentez les fonctions Use() et BindInputAction(). Celles-ci n'ont aucun effet dans la classe parente ; vous pouvez donc les laisser vides pour l'instant. Vous y ajouterez une logique lors de la création des sous-classes de EquipableToolBase ; par exemple, la fonction Use() doit inclure des actions propres à un outil, notamment le lancement d'un projectile ou l'ouverture d'une porte.
void AEquippableToolBase::Use()
{
}
void AEquippableToolBase::BindInputAction(const UInputAction* ActionToBind)
{
}
Enregistrez votre code et compilez-le via VS.
Votre fichier EquippableToolBase.h doit maintenant ressembler à ce qui suit :
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "EquippableToolBase.generated.h"
class AAdventureCharacter;
class UInputAction;
EquippableToolBase.cpp doit maintenant ressembler à ce qui suit :
// Copyright Epic Games, Inc. All Rights Reserved.
#include "EquippableToolBase.h"
#include "AdventureCharacter.h"
AEquippableToolBase::AEquippableToolBase()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
Remettre des objets à un personnage
Bien que vous ayez défini les outils que votre personnage peut utiliser, il ne peut pas encore les équiper. Dans cette étape, vous allez ajouter un système d'inventaire pour permettre au personnage de stocker des objets et de les équiper lorsqu'il les ramasse.
Créer un composant d'inventaire
L’inventaire de votre personnage doit ajouter des fonctionnalités au personnage, mais ne doit pas exister dans le monde du jeu. Vous utiliserez donc une classe de composants d’acteur pour définir un inventaire qui détermine les objets que possède un personnage, et qui est capable de changer d’outil et d'empêcher le personnage d’obtenir plusieurs fois un même outil.
Dans l'Unreal Editor, accédez à Outils > Nouvelle classe C++. Sélectionnez le composant d'acteur comme classe parente et nommez la classe InventoryComponent.
Cliquez sur Créer une classe.
Dans VS, en haut de InventoryComponent.h, déclarez directement UEquippableToolDefinition. Il s'agit de la classe que vous pourrez stocker dans votre inventaire.
#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "InventoryComponent.generated.h"
class UEquippableToolDefinition;
UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class ADVENTUREGAME_API UInventoryComponent : public UActorComponent
{
GENERATED_BODY()
Dans la section public, déclarez une nouvelle TArray de pointeurs UEquippableToolDefinition appelée ToolInventory. Attribuez-lui la macro UPROPERTY() avec VisibleAnywhere, BlueprintReadOnly et Category = Tools.
public:
// Sets default values for this component's properties
UInventoryComponent();
// The array of tools stored in this inventory.
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Tools)
TArray<UEquippableToolDefinition*> ToolInventory;Cet inventaire ne contient que des outils, mais vous pouvez l'enrichir pour inclure n'importe quel type d'objet. Une implémentation plus générique pourrait stocker uniquement les valeurs UItemDefinition ou TSubclassOf<UItemDefinition> pour créer un inventaire plus complexe avec une IU, des icônes, des effets sonores, un coût et d'autres propriétés d'objet.
Votre fichier InventaireComponent.h complet doit maintenant ressembler à ce qui suit :
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "InventoryComponent.generated.h"
class UEquippableToolDefinition;
Ajouter des déclarations d'outil et d'inventaire pour le personnage
Maintenant que vous avez un défini un emplacement où stocker vos objets, vous pouvez mettre à niveau votre personnage avec une logique qui lui remet des objets.
Pour commencer, en haut du fichier .h, déclarez directement les classes AEquippableToolBase, UEquippableToolDefinition et UInventoryComponent.
#include "CoreMinimal.h"
#include "Camera/CameraComponent.h"
#include "EnhancedInputComponent.h"
#include "EnhancedInputSubsystems.h"
#include "GameFramework/Character.h"
#include "InputActionValue.h"
#include "AdventureCharacter.generated.h"
class AEquippableToolBase;
class UAnimBlueprint;
Dans la section protected, déclarez un TObjectPtr sur un UInputAction appelé UseAction. Il s'agit de l'action d'entrée "use tool" que vous allez lier à la fonction Use() de l'outil.
// Use Input Actions
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input)
TObjectPtr<UInputAction> UseAction;Créer le composant d’inventaire du personnage
Dans le fichier .h du personnage, dans la section public, déclarez un TObjectPtr sur un UInventoryComponent nommé InventoryComponent. Attribuez-lui une macro UPROPERTY() avec VisibleAnywhere et Category = Inventory.
// Inventory Component
UPROPERTY(VisibleAnywhere, Category = Inventory)
TObjectPtr<UInventoryComponent> InventoryComponent;Dans la fonction de constructeur de votre personnage, après avoir créé le sous-objet de composant de maillage, créez un sous-objet UInventoryComponent nommé InventoryComponent. Vous vous assurez ainsi que votre inventaire est correctement configuré lorsque le personnage apparaît.
// Create an inventory component for the owning player
InventoryComponent = CreateDefaultSubobject<UInventoryComponent>(TEXT("InventoryComponent"));Vérifier l’inventaire existant
Avant de lier l'outil, vérifiez si le joueur dispose déjà de cet outil afin de ne pas l'en équiper plusieurs fois.
Dans le fichier .h du personnage, dans la section public, déclarez une fonction nommée IsToolAlreadyOwned() qui prend un pointeur UEquippableToolDefinition et renvoie true si l’outil existe déjà dans l’inventaire du joueur.
// Returns whether or not the player already owns this tool
UFUNCTION()
bool IsToolAlreadyOwned(UEquippableToolDefinition* ToolDefinition);Dans le fichier .cpp de votre personnage, AdventureCharacter.cpp, implémentez la fonction IsToolAlreadyOwned(). À l'intérieur, dans une boucle for, obtenez chaque outil de l'inventaire du personnage en accédant à la matrice InventoryComponent->ToolInventory.
bool AAdventureCharacter::IsToolAlreadyOwned(UEquippableToolDefinition* ToolDefinition)
{
// Check that the character does not yet have this particular tool
for (UEquippableToolDefinition* InventoryItem : InventoryComponent->ToolInventory)
{
}
}
Ensuite, dans une instruction if, vérifiez si ToolDefinition->ID de l'outil transmis à cette fonction correspond à InventoryItem->ID. Si c'est le cas, la valeur true est renvoyée, car le personnage possède déjà cet outil. Dans le cas contraire, au terme de la boucle for, la valeur false est renvoyée, car la définition d'outil ne correspond à aucun objet d'inventaire existant ; il s'agit donc d'un nouvel objet.
bool AAdventureCharacter::IsToolAlreadyOwned(UEquippableToolDefinition* ToolDefinition)
{
// Check that the character does not yet have this particular tool
for (UEquippableToolDefinition* InventoryItem : InventoryComponent->ToolInventory)
{
if (ToolDefinition->ID == InventoryItem->ID)
{
return true;
}
}
Lier un outil
Dans le fichier .h de votre personnage, dans la section public, déclarez une fonction appelée AttachTool() qui prend un pointeur UEquippableToolDefinition. Cette fonction tente d'équiper l'outil dans la définition d'outil du joueur.
// Attaches and equips a tool to the player
UFUNCTION()
void AttachTool(UEquippableToolDefinition* ToolDefinition);Dans la section protected, déclarez un TObjectPtr sur un AEquippableToolBase nommé EquipTool. Attribuez-lui les spécificateurs VisibleAnywhere, BlueprintReadOnly et Category = Tools UPROPERTY().
// The currently-equipped tool
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Tools)
TObjectPtr<AEquippableToolBase> EquippedTool;Dans le fichier .cpp de votre personnage, implémentez AttachTool(). Tout d'abord, dans une instruction if, vérifiez si le personnage dispose déjà de l'outil en appelant IsToolAlreadyOwned().
void AAdventureCharacter::AttachTool(UEquippableToolDefinition* ToolDefinition)
{
// Only equip this tool if it isn't already owned
if (not IsToolAlreadyOwned(ToolDefinition))
{
}
}
Faire apparaître un objet
L'outil AEquippableToolBase stocké dans ToolDefinition est un acteur. Il est donc possible qu'il ne soit pas chargé lors de l'appel de AttachTool(). Pour gérer cela, vous allez générer une nouvelle instance de l'outil à l'aide de la fonction SpawnActor().
SpawnActor() fait partie de l'objet UWorld, c'est-à-dire l'objet principal qui représente la carte et les acteurs qui s'y trouvent. Accédez-y en appelant la fonction GetWorld() depuis n'importe quel acteur.
Dans l'instruction if, déclarez un nouveau pointeur AEquippableToolBase appelé ToolToEquip. Définissez cette valeur comme étant égale au résultat de l'appel de GetWorld()->SpawnActor(), en transmettant ToolDefinition->ToolAsset comme acteur à générer et this->GetActorTransform() comme emplacement où le générer.
// Only equip this tool if it isn't already owned
if (not IsToolAlreadyOwned(ToolDefinition))
{
// Spawn a new instance of the tool to equip
AEquippableToolBase* ToolToEquip = GetWorld()->SpawnActor<AEquippableToolBase>(ToolDefinition->ToolAsset, this->GetActorTransform());
}Lorsque vous transmettez ToolDefinition->ToolAsset à SpawnActor, l'UE sait qu'il doit rechercher le type de classe de ToolAsset et générer ce type d'acteur. (ToolAsset est l'acteur EquippableToolBase associé à cette définition d'outil.)
Joindre un objet au personnage
Pour joindre l'outil généré à votre personnage, déclarez un nouveau FAttachmentTransformRules appelé AttachmentRules.
La structure FAttachmentTransformRules définit la façon dont gérer la position, la rotation et l'échelle lors de la liaison. Elle prend en charge EAttachmentRules et un booléen InWeldSimulatedBodies à la fin pour indiquer à l'UE si la physique est impliquée. Si la valeur renvoyée est true, l'UE fusionne les deux corps pour qu'ils puissent interagir comme entité unique lorsqu’ils se déplacent. Les règles de liaison courantes incluent KeepRelative (maintien de la transformation relative au parent), KeepWorld (maintien de la transformation du monde) et SnapToTarget (fixation à la transformation du parent).
Dans votre définition AttachmentRoles, ajoutez EAttachmentRule::SnapToTarget et true.
// Attach the tool to the First Person Character
FAttachmentTransformRules AttachmentRules(EAttachmentRule::SnapToTarget, true);Appelez ensuite ToolToEquip->AttachToActor() pour joindre l'outil au personnage, puis ToolToEquip->AttachToComponent() pour joindre l'outil au connecteur de droite du composant de maillage à la première personne.
AttachToActor joint un acteur à un acteur parent cible, et AttachToComponent joint le composant racine d'un acteur au composant cible. Leur syntaxe est la suivante :
MyActor->AttachToActor(ParentActor, AttachmentRules, OptionalSocketName)
// Attach the tool to this character, and then the right hand of their first-person mesh
ToolToEquip->AttachToActor(this, AttachmentRules);
ToolToEquip->AttachToComponent(FirstPersonMeshComponent, AttachmentRules, FName(TEXT("HandGrip_R")));Ajouter les animations de l'objet au personnage
Définissez les animations des maillages à la première et à la troisième personne avec SetAnimInstanceClass(), en transmettant les animations à la première personne et à la troisième personne de l’outil.
// Set the animations on the character's meshes.
FirstPersonMeshComponent->SetAnimInstanceClass(ToolToEquip->FirstPersonToolAnim->GeneratedClass);
GetMesh()->SetAnimInstanceClass(ToolToEquip->ThirdPersonToolAnim->GeneratedClass);La fonction SetAnimInstanceClass modifie dynamiquement le blueprint d'animation au moment de l'exécution pour un maillage squelettique. Elle sert généralement à équiper des objets et des armes avec différents ensembles d’animations. GeneratedClass obtient la classe AnimInstance actuelle générée à partir du blueprint.
Ajouter l'objet à l’inventaire
Ajoutez l'outil à l'inventaire du personnage en utilisant ToolInventory.Add().
// Add the tool to this character's inventory
InventoryComponent->ToolInventory.Add(ToolDefinition);
Maintenant que l'outil est joint, définissez la fonction ToolToEquip->OwningCharacter sur ce personnage.
ToolToEquip->OwningCharacter = this;Vous venez d'ajouter le nouvel outil au personnage. Vous devez maintenant définir EquipTool sur ToolToEquip.
EquippedTool = ToolToEquip;Ajouter les contrôles d'un objet au personnage
Dans cette étape, vous allez ajouter l' action d'entrée et le contexte de mappage d'entrée de l'outil au personnage.
Vous les implémenterez de la même manière que vous avez configuré AAdventureCharacter::BeginPlay() dans la section Lier le mappage d'entrée au personnage de la page Configurer les déplacements du personnage, c'est-à-dire en obtenant le PlayerController, puis le sous-système local d'entrée amélioré, à l'aide d'instructions if pour vérifier les pointeurs nuls au fur et à mesure.
// Get the player controller for this character
if (APlayerController* PlayerController = Cast<APlayerController>(Controller))
{
if (UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PlayerController->GetLocalPlayer()))
{
Subsystem->AddMappingContext(ToolToEquip->ToolMappingContext, 1);
}
}
Cette fois, lorsque vous ajoutez le contexte de mappage d'entrée de l'outil au sous-système du joueur, définissez sa priorité sur 1. La priorité du contexte de mappage principal du joueur (FirstPersonContext) est inférieure (0). Ainsi, lorsque les deux contextes de mappage ont le même raccourci clavier, la liaison d'entrée dans ToolToEquip->ToolMappingContext a la priorité sur FirstPersonContext.
Après avoir ajouté le contexte de mappage, appelez ToolToEquip->BindInputAction() en transmettant UseAction pour lier l'action d'entrée du personnage à la fonction Use() de l'outil.
// Get the player controller for this character
if (APlayerController* PlayerController = Cast<APlayerController>(Controller))
{
if (UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PlayerController->GetLocalPlayer()))
{
Subsystem->AddMappingContext(ToolToEquip->ToolMappingContext, 1);
}
ToolToEquip->BindInputAction(UseAction);
}
Votre fonction AttachTool() doit ressembler à ce qui suit une fois terminée :
void AAdventureCharacter::AttachTool(UEquippableToolDefinition* ToolDefinition)
{
// Only equip this tool if it isn't already owned
if (not IsToolAlreadyOwned(ToolDefinition))
{
// Spawn a new instance of the tool to equip
AEquippableToolBase* ToolToEquip = GetWorld()->SpawnActor<AEquippableToolBase>(ToolDefinition->ToolAsset, this->GetActorTransform());
// Attach the tool to the First Person Character
Prendre en charge différents types d'objets avec GiveItem()
Bien que vous disposiez d'un moyen pour joindre des outils, étant donné que les objets à ramasser et leurs définitions d'objet peuvent contenir plus que de simples outils, vous devez trouver un moyen de savoir avec quel type d'objet votre personnage interagit avant d'appeler AttachTool().
Créez une fonction GiveItem() pour effectuer différentes actions selon le type de définition d'objet que vous fournissez. Vous avez déclaré différents types d'objets avec l'enum EItemType du fichier ItemData.h, et pouvez utiliser ces données pour différencier les définitions d'objets entre elles.
Dans AdventureCharacter.h, dans la section public, déclarez une fonction nommée DonItem() qui accepte un pointeur UItemDefinition(). D'autres classes appellent cette fonction lorsqu’elles tentent de remettre un objet au joueur.
// Public function that other classes can call to attempt to give an item to the player
UFUNCTION()
void GiveItem(UItemDefinition* ItemDefinition);Dans AdventureCharacter.cpp, implémentez GiveItem(). Commencez par déclarer une instruction switch dont les cas dépendent du type d'objet de l'objet transmis à cette fonction.
void AAdventureCharacter::GiveItem(UItemDefinition* ItemDefinition)
{
// Case based on the type of the item
switch (ItemDefinition->ItemType)
{
}
}
Dans l'instruction switch, déclarez des cas pour EItemType::Tool, EItemType::Consumable, et un cas par défaut. Dans ce tutoriel, vous implémentez uniquement l’objet Tool-type. Dans les cas Consumable et default, consignez le type de l’objet et quittez l'instruction de cas switch.
// Case based on the type of the item
switch (ItemDefinition->ItemType)
{
case EItemType::Tool:
{
}
case EItemType::Consumable:
{
// Not yet implemented
break;
Dans le cas de l'outil, projection ItemDefinition vers un pointeur UEquippableToolDefinition appelé ToolDefinition.
Ensuite, assurez-vous que la conversion s'est bien déroulée en vérifiant que ToolDefinition est définie sur null. Si elle n'est pas définie sur null, appelez AttachTool() pour joindre l'outil au personnage. Sinon, consignez l'erreur et exécutez une instruction break.
case EItemType::Tool:
{
// If the item is a tool, attempt to cast and attach it to the character
UEquippableToolDefinition* ToolDefinition = Cast<UEquippableToolDefinition>(ItemDefinition);
if (ToolDefinition != nullptr)
{
AttachTool(ToolDefinition);
}
Votre fonction GiveItem() doit ressembler à ce qui suit une fois terminée :
void AAdventureCharacter::GiveItem(UItemDefinition* ItemDefinition)
{
// Case based on the type of the item
switch (ItemDefinition->ItemType)
{
case EItemType::Tool:
{
// If the item is a tool, attempt to cast and attach it to the character
Enfin, vous devez disposer d'un déclencheur dans le jeu permettant de mettre en œuvre votre logique de remise d’objet. Lorsqu'un personnage entre en collision avec un objet à ramasser, celui-ci appelle la fonction GiveItem() du personnage pour remettre le ReferenceItem de l'objet à ramasser au personnage.
Pour ce faire, ouvrez PickupBase.cpp.
Dans OnSphereBeginOverlap(), après avoir vérifié si le personnage est valide, appelez Character->GiveItem(ReferenceItem) pour remettre l'objet à votre personnage.
// Checking if it is a First Person Character overlapping
AAdventureCharacter* Character = Cast<AAdventureCharacter>(OtherActor);
if (Character != nullptr)
{
// Give the item to the character
Character->GiveItem(ReferenceItem);
// Unregister from the Overlap Event so it is no longer triggered
SphereComponent->OnComponentBeginOverlap.RemoveAll(this);
Maintenant que vous avez configuré les données de votre outil et de votre acteur, vous pouvez les utiliser pour créer un véritable outil avec lequel votre personnage pourra utiliser dans le jeu.
Implémenter un lance-fléchettes
Pour votre premier outil à équiper, vous allez créer un lance-fléchettes capable de lancer des projectiles. Dans cette section, vous allez commencer par créer l’outil que votre personnage va utiliser. Dans la section suivante, vous implémenterez la logique des projectiles.
Configurer une nouvelle classe DartLauncher
Dans l'Unreal Editor, accédez à Outils > Nouvelle classe C++.
Accédez à Toutes les classes, recherchez et sélectionnez la classe parente EquippableToolBase, puis nommez la classe DartLauncher. Créez un dossier appelé Outils pour y stocker le code de vos outils. Cliquez sur Créer une classe.
Dans Visual Studio, en haut de DartLauncher.h :
Ajoutez une instruction include pour
"[NomProjet]/EquippableToolBase.h".Ajoutez les spécificateurs
BlueprintTypeetBlueprintableà la macroUCLASS().Dans la section
public, déclarez des remplacements pour les fonctionsUse()etBindInputAction()deAEquippableToolBase.
Votre classe DartLauncher.h complète doit ressembler à ce qui suit :
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "AdventureGame/EquippableToolBase.h"
#include "DartLauncher.generated.h"
UCLASS(BlueprintType, Blueprintable)
class ADVENTUREGAME_API ADartLauncher : public AEquippableToolBase
Dans DartLauncher.cpp, en haut du fichier, ajoutez une instruction include pour "[NomProjet]/AdventureCharacter.h". Vous aurez besoin de cet élément dans la fonction BindInputAction().
#include "DartLauncher.h"
#include "AdventureGame/AdventureCharacter.h"Implémenter les contrôles de l'outil
Maintenant que vous travaillez avec un outil spécifique et que vous savez quelle fonction vous liez, vous pouvez implémenter BindInputAction().
Commencez par implémenter la fonction Use(). Dans Use(), ajoutez un message de débogage qui signale le moment où le joueur déclenche la fonction.
#include "DartLauncher.h"
#include "AdventureGame/AdventureCharacter.h"
void ADartLauncher::Use()
{
GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Yellow, TEXT("Using the dart launcher!"));
}
Ensuite, implémentez la fonction BindInputAction(). Dans la fonction, dans une instruction if, obtenez le contrôleur de joueur pour le OwningCharacter en utilisant GetController() et convertissez-le en APlayerController. Cette procédure est similaire à la procédure d'ajout d'un contexte de mappage dans la fonction AAdventureCharacter::BeginPlay().
void ADartLauncher::BindInputAction(const UInputAction* InputToBind)
{
// Set up action bindings
if (APlayerController* PlayerController = Cast<APlayerController>(OwningCharacter->GetController()))
{
}
}
De la même manière que vous avez lié vos actions de déplacement dans la section Lier les actions de déplacementt de la page Configurer les déplacements du personnage : dans une autre instruction if, déclarez un nouveau pointeur UEnhancedInputComponent nommé EnhancedInputComponent. Définissez cette valeur comme étant égale au résultat de l'appel de Cast() sur le PlayerInputComponent transmis à cette fonction tout en le convertissant en UEnhancedInputComponent.
Enfin, utilisez BindAction pour lier l'action ADartLauncher::Use à l'action InputToBind qui est transmise à cette fonction via BindAction(). L'action InputAction est ainsi liée à Use(); de sorte que, lorsque l'action donnée se produit, Use() est appelé.
// Set up action bindings
if (APlayerController* PlayerController = Cast<APlayerController>(OwningCharacter->GetController()))
{
if (UEnhancedInputComponent* EnhancedInputComponent = Cast<UEnhancedInputComponent>(PlayerController->InputComponent))
{
// Fire
EnhancedInputComponent->BindAction(InputToBind, ETriggerEvent::Triggered, this, &ADartLauncher::Use);
}
}
Lorsque vous configurez le déplacement de votre personnage, vous utilisez CastChecked<>, qui entraîne le blocage du jeu en cas d'échec. Dans la mesure où vous ne souhaitez pas arrêter le jeu si les contrôles de ramassage ne sont pas initialisés correctement, utilisez simplement Cast<>. N'utilisez CastChecked<> que lorsqu'un échec de conversion indique un bogue sérieux.
Enregistrez votre code et compilez-le.
Votre fonction BindInputAction() et votre classe DartLauncher.cpp doivent maintenant ressembler à ce qui suit :
// Copyright Epic Games, Inc. All Rights Reserved.
#include "DartLauncher.h"
#include "AdventureGame/AdventureCharacter.h"
void ADartLauncher::Use()
{
GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Yellow, TEXT("Using the dart launcher!"));
}
Adapter un blueprint d’animation à votre personnage
Le modèle de jeu à la première personne comprend un échantillon de blueprint d’animation pour les objets de type arme, mais vous devez apporter certaines modifications au blueprint afin qu’il puisse fonctionner avec votre lance-fléchettes.
Pour adapter un blueprint d’animation existant à votre personnage, procédez comme suit :
Dans le navigateur de contenu, accédez au dossier Contenu > Variant_Shooter > Animation, faites un clic droit sur le blueprint d'animation
ABP_FP_Pistol, puis sélectionnez Dupliquer.Nommez cette copie ABP_FP_DartLauncher, faites glisser dans le dossier Contenu > FirstPerson > Animations et sélectionnez Déplacer ici.
ABP_TP_Pistoln'utilise pas de logique propre au personnageBP_FPShooter; vous n'avez pas besoin de la modifier pour votre personnage.À proximité de la partie supérieure du graphique d'événements, effectuez un zoom avant sur le groupe de nœuds qui commence par un nœud Event Blueprint Begin Play.
Ce blueprint obtient les variables Maillage à la première personne et Caméra à la première personne de
BP_FPShooter; vous allez donc les modifier pour utiliser votre blueprint de personnage à la place (dans ce tutoriel, nous utilisonsBP_AdventureCharacter).Cliquez sur chacun de ces nœuds et appuyez sur Suppr :
Cast To BP_FPShooter
First Person Mesh
First Person Camera
Faites un clic droit sur le graphique d'événements, puis recherchez et sélectionnez un nœud Cast To BP_AdventureCharacter.
Reliez les broches d’exécution entre le nœud Event Blueprint Begin Play et le nouveau nœud, puis au nœud Set First Person Mesh.
Reliez la broche Return Value du nœud Try Get Pawn Owner à la broche Cast To node’s Object.
Pour créer un nouveau nœud à partir de Cast To BP_AdventureCharacter, cliquez sur la broche As BP My Adventure Character et faites-la glisser vers un emplacement vide dans le graphique.
Recherchez Obtenir le maillage et sélectionnez-le sous Variables > Personnage. Reliez la broche Mesh du nouveau nœud au nœud Set First Person Mesh.
Pour la caméra, faites glisser un autre nœud depuis la broche As BP My First Person Character, puis recherchez et sélectionnez Get Component by Class.
Assurez-vous de créer un nœud Get Component by Class avec « by » en minuscules.
Sur le nouveau nœud, définissez Classe de composant sur Composant de caméra. Ensuite, reliez la broche Return Value au nœud Set First Person Camera.
Enregistrez votre blueprint ABP_FP_DartLauncher et compilez-le.
Définir les contrôles du lance-fléchettes
Votre lance-fléchettes doit disposer d’une action d'entrée et d’un contexte de mappage d'entrée pour que le personnage puisse lancer des projectiles depuis l’outil.
Pour créer des contrôles de joueur pour votre outil de lance-fléchettes, procédez comme suit :
Dans le navigateur de contenu, accédez au dossier Input > Actions.
Créez et configurez une action d'entrée de type « use tool » :
Cliquez sur Ajouter, accédez à Entrée, puis sélectionnez Action d'entrée. Nommez-la IA_UseTool.
Double-cliquez sur IA_UseTool pour l'ouvrir. Dans le panneau Détails, assurez-vous que son type est défini sur Numérique (booléen).
En regard de Déclencheurs, cliquez sur le bouton plus (+), puis sélectionnez Appui effectué dans la liste des déclencheurs.
Enregistrez et fermez l’action d’entrée.
Revenez au navigateur de contenu, puis accédez au dossier Input.
Créez et configurez un nouveau contexte de mappage d'entrée qui associe le bouton gauche de la souris et la gâchette droite de la manette à l'action Utiliser du lance-fléchettes :
Créez un nouveau contexte de mappage d'entrée appelé IMC_DartLauncher.
Ouvrez IMC_DartLauncher. Cliquez sur le bouton plus en regard de Mappages.
Dans la liste du menu déroulant, sélectionnez
IA_UseTool.Cliquez sur la flèche pour développer le mappage. Cliquez sur le bouton du clavier, puis appuyez sur le bouton gauche de la souris pour lier ce bouton à
IA_UseTool.En regard de IA_UseTool, cliquez sur le bouton plus pour ajouter une autre liaison. Dans la liste du menu déroulant, développez Manette et sélectionnez Axe de gâchette droite de la manette.
Enregistrez et fermez le contexte de mappage d'entrée.
Créer le blueprint DartLauncher
Revenez dans l'éditeur principal puis, dans l'arborescence des ressources du navigateur de contenu, accédez au dossier Classes C++, faites un clic droit sur la classe DartLauncher et créez une nouvelle classe de blueprint.
Nommez-la BP_DartLauncher. Dans le dossier FirstPerson > Blueprints, créez un dossier appelé Outils pour stocker vos objets à équiper, puis terminez la création du blueprint.
Dans le panneau Détails du blueprint, définissez les propriétés par défaut suivantes :
Définissez Animation d'outil à la première personne sur
ABP_FP_DartLauncher.Définissez Animation d'outil à la troisième personne sur
ABP_TP_Pistol.Définissez Contexte du mappage de l'outil sur
IMC_DartLauncher.
Dans l'onglet Composants, sélectionnez le composant de maillage de l'outil et définissez Ressource de maillage squelettique sur SKM_Pistol.
Créer la ressource de données du lance-fléchettes
Pour créer une ressource de données afin de stocker les données de ce blueprint, procédez comme suit :
Dans le navigateur de contenu, dans le dossier FirstPerson > Data, créez une ressource de données et sélectionnez Définition d’outil à équiper comme instance de ressource de données. Nommez cette ressource
DA_DartLauncher.Dans
DA_DartLauncher, dans le panneau Détails, définissez les propriétés suivantes :Définissez Ressource de l'outil sur
BP_DartLauncher.Définissez Identifiant sur Tool_001.
Définissez Type d'objet sur Outil.
Définissez Maillage de monde sur
SM_Pistol.
Saisissez un nom et une description.
Enregistrez votre ressource de données.
Créer une table de données pour les outils
Même si vous pouvez utiliser cet outil dans votre table DT_PickupData, nous vous recommandons d’organiser vos tables pour suivre des éléments spécifiques. Par exemple, vous pouvez disposer de différentes tables pour les objets que certaines classes peuvent équiper, ou des tables d'objets que différents ennemis déposent lorsqu'ils sont vaincus. Dans ce tutoriel, vous allez créer une table pour les objets à usage unique et une table pour les outils.
Pour créer une table de données afin de suivre les objets de votre outil, procédez comme suit :
Dans le navigateur de contenu, accédez au dossier FirstPerson > Data et créez une nouvelle table de données.
Sélectionnez ItemData comme structure de ligne.
Nommez la table DT_ToolData, puis double-cliquez dessus pour l'ouvrir.
Dans DT_ToolData, cliquez sur Ajouter pour créer une ligne pour votre lance-fléchettes.
Sélectionnez la nouvelle ligne, puis configurez les champs suivants :
Définissez Nom de la ligne et Identifiant sur tool_001.
Définissez Type d'objet sur Outil.
Définissez Base d'objet sur
DA_DartLauncher.
Enregistrez et fermez la table de données.
Tester un objet à ramasser de lance-fléchettes dans le jeu
Vous avez modifié votre classe de ramassage pour remettre un objet à l’utilisateur, créé une classe d’objet qui donne au joueur un nouveau maillage, des animations et de nouveaux contrôles, et configuré un outil de lance-fléchettes. Vous devez maintenant rassembler tous ces éléments et créer l'objet à ramasser dans le jeu qui déclenche toute la logique des objets à équiper que vous avez mise en place dans cette partie du tutoriel.
Dans le navigateur de contenu, accédez à Contenu > FirstPerson > Blueprints et faites glisser un nouveau BP_PickupBase dans le niveau. Définissez les champs Identifiant de l'objet à ramasser sur Tool_001 et Table de données de ramassage sur DT_ToolData.
Cliquez sur Jouer pour tester votre jeu. Lorsque le jeu commence, votre objet à ramasser doit s'initialiser sur le lance-fléchettes. Lorsque vous passez sur l'objet à ramasser, votre personnage doit commencer à se saisir de l'outil.
Suivant
Dans l'étape finale, vous allez implémenter la physique du projectile dans votre lance-fléchettes et faire en sorte qu'il projette des fléchettes en mousse.
Implémenter un projectile
Apprenez à utiliser C++ pour implémenter des projectiles et les faire apparaître pendant le jeu.
Code complet
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "ItemData.h"
#include "ItemDefinition.generated.h"
/**
* Defines a basic item with a static mesh that can be built from the editor.
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "ItemDefinition.h"
#include "EquippableToolDefinition.generated.h"
class AEquippableToolBase;
class UInputMappingContext;
// Copyright Epic Games, Inc. All Rights Reserved.
#include "EquippableToolDefinition.h"
UEquippableToolDefinition* UEquippableToolDefinition::CreateItemCopy() const
{
UEquippableToolDefinition* ItemCopy = NewObject<UEquippableToolDefinition>(StaticClass());
ItemCopy->ID = this->ID;
ItemCopy->ItemType = this->ItemType;
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "InventoryComponent.generated.h"
class UEquippableToolDefinition;
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "AdventureGame/EquippableToolBase.h"
#include "DartLauncher.generated.h"
UCLASS(BlueprintType, Blueprintable)
class ADVENTUREGAME_API ADartLauncher : public AEquippableToolBase
// Copyright Epic Games, Inc. All Rights Reserved.
#include "DartLauncher.h"
#include "AdventureGame/AdventureCharacter.h"
void ADartLauncher::Use()
{
GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Yellow, TEXT("Using the dart launcher!"));
}
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "EquippableToolBase.generated.h"
class AAdventureCharacter;
class UInputAction;
// Copyright Epic Games, Inc. All Rights Reserved.
#include "EquippableToolBase.h"
#include "AdventureCharacter.h"
AEquippableToolBase::AEquippableToolBase()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "Camera/CameraComponent.h"
#include "EnhancedInputComponent.h"
#include "EnhancedInputSubsystems.h"
#include "GameFramework/Character.h"
#include "InputActionValue.h"
// Copyright Epic Games, Inc. All Rights Reserved.
#include "AdventureCharacter.h"
#include "EquippableToolBase.h"
#include "EquippableToolDefinition.h"
#include "ItemDefinition.h"
#include "InventoryComponent.h"
// Sets default values
AAdventureCharacter::AAdventureCharacter()