E4-Unreal / test-simple-game-framework

simpleFramework for UE 5.1.0
MIT License
0 stars 1 forks source link

장비 시스템 구현 #14

Closed Eu4ng closed 1 year ago

Eu4ng commented 1 year ago

목적

무기나 방어구와 같은 장비 아이템과 장비창 구현

작업 상세 내용

문서화

Wiki - *** 참고

Eu4ng commented 1 year ago

DA_EquipmentSlotTags 편집 편의성, EquipmentSlot과 EquipmentSocket 태그 매핑을 위해 아래와 같이 구조를 변경하고 싶다. 하지만, 현재 EquipmentComponent는 EquipmentSlot을 FGameplayTag와 1대1 대응으로 설계가 되어있는데 구조 변경 시 EquipmentSlot은 장비 카테고리(FGameplayTag)와 인덱스(int32)로 구분될 것이다. 결국 EquipmentComponent를 전부 뜯어 고쳐야하는데 그럴 가치가 과연 있는가?

장점

단점


기존

UCLASS(Blueprintable, BlueprintType, Const, Meta = (DisplayName = "Equipment Slot Tags", ShortTooltip = "Equipment SlotTags for Equipment Slots"))
class THIRDPERSON_API UEquipmentSlotTags : public UDataAsset
{
    GENERATED_BODY()

protected:
    // Todo C++이 아니라 에디터에서 설정할 수 있는 게임플레이 태그를 제한하는 방법은 없을까?

    // Todo 프로젝트에 설정된 GameplayTag에 따라 meta=(Categories="") 커스터마이징 필요
    // Todo FGameplayTagContainer로 변경?
    UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta=(Categories="EquipmentSlot"))
    TArray<FGameplayTag> All;

    // Todo 프로젝트에 설정된 GameplayTag에 따라 meta=(Categories="") 커스터마이징 필요
    UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta=(Categories="EquipmentSlot.Active.Main"))
    FGameplayTag Primary;

public:
    FORCEINLINE TArray<FGameplayTag> GetAll() const { return All; }
    FORCEINLINE FGameplayTag GetPrimary() const { return Primary; }
};

변경 후

//////////////////////////////////////////////////////////////////////
// Sub Equipment Category
USTRUCT(Atomic, BlueprintType, Meta = (DisplayName = "Sub Equipment Category"))
struct FSubEquipmentCategory
{
    GENERATED_USTRUCT_BODY()

    UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta=(Categories="EquipmentSlot.Active.Sub"))
    FGameplayTag Tag;

    FORCEINLINE bool operator== (const FSubEquipmentCategory& Other) const
    {
        return Tag == Other.Tag;
    }
    FORCEINLINE friend uint32 GetTypeHash (const FSubEquipmentCategory& Other)
    {
        return GetTypeHash(Other.Tag);
    }
};

//////////////////////////////////////////////////////////////////////
// Equipment Socket Tags
USTRUCT(Atomic, BlueprintType, Meta = (DisplayName = "Equipment Socket Tags"))
struct FEquipmentSocketTags
{
    GENERATED_USTRUCT_BODY()

    UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta=(Categories="EquipmentSocket"))
    TArray<FGameplayTag> Tags;
};

//////////////////////////////////////////////////////////////////////
// Equipment Slots

UCLASS(Blueprintable, BlueprintType, Const, Meta = (DisplayName = "Equipment Slot Tags", ShortTooltip = "Equipment SlotTags for Equipment Slots"))
class THIRDPERSON_API UEquipmentSlotTags : public UDataAsset
{
    GENERATED_BODY()

protected:

    UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="EquipmentSlot")
    FEquipmentSocketTags Main;

    UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="EquipmentSlot")
    TMap<FSubEquipmentCategory, FEquipmentSocketTags> Sub;

public:
    FORCEINLINE TArray<FGameplayTag> GetAll() const { return All; }
    FORCEINLINE FGameplayTag GetPrimary() const { return Primary; }
};

image

Eu4ng commented 1 year ago

현재 상황

다른 작업을 우선하고 싶으므로 구조 변경은 보류

Eu4ng commented 1 year ago

주 무기 슬롯에는 총, 방패, 검, 지팡이 등 여러 무기들이 들어갈 수 있다. Equipment.Active.Main.Magician, Equipment.Active.Main.Warrior.... 처럼 직업에 따라 들 수 있는 장비를 나눌 수도 있지만 Equipment.Active.Main.Rifle, Equipment.Active.Main.Sword 처럼 장비의 종류에 따라 들 수 있는 장비를 나눌 수도 있을 것이다. 이 경우에는 장비 슬롯 별로 하나의 카테고리(태그)만 정해주면 구현이 가능하다.

하지만 게임에 따라 여러 장비를 들 수 있게 설정하거나 여러 직업을 동시에 사용할 수 있게 하고 싶을 수도 있다. 이 경우에는 장비 슬롯 별로 여러 개의 카테고리(태그)를 정해주면 구현이 가능한 대신, 데이터 애셋 설정 창이 지저분해 보일 수도 있다. 그리고 이 경우는 드물기 때문에 이 부분은 나중에 DynamicEquipmentComponent로 따로 구현하는 것이 좋을 것 같다.


EquipmentComponent 설정에 사용되는 DA_EquipmentSlots

image

DynamicEquipmentComponent 설정에 사용되는 DA_EquipmentSlots

image

DynamicEquipmentComponent.h

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "GameplayTagContainer.h"
#include "UObject/Object.h"
#include "EquipmentSlots.generated.h"

/**
 * 
 */

//////////////////////////////////////////////////////////////////////
// Equipment Socket Tags
USTRUCT(Atomic, BlueprintType, Meta = (DisplayName = "Main Equipment Slot"))
struct FMainEquipmentSlot
{
    GENERATED_USTRUCT_BODY()

    UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta=(Categories="EquipmentSlot.Active.Main"))
    FGameplayTagContainer CategoryTags;

    UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta=(Categories="EquipmentSocket"))
    FGameplayTagContainer SocketTags;
};

//////////////////////////////////////////////////////////////////////
// Equipment Socket Tags
USTRUCT(Atomic, BlueprintType, Meta = (DisplayName = "Sub Equipment Slot"))
struct FSubEquipmentSlot
{
    GENERATED_USTRUCT_BODY()

    UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta=(Categories="EquipmentSlot.Active.Sub"))
    FName DisplayName = "DisplayName";

    UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta=(Categories="EquipmentSlot.Active.Sub"))
    FGameplayTagContainer CategoryTags;

    UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta=(Categories="EquipmentSocket"))
    FGameplayTagContainer SocketTags;
};

//////////////////////////////////////////////////////////////////////
// Equipment Slots

UCLASS(Blueprintable, BlueprintType, Const, Meta = (DisplayName = "Equipment Slot Tags", ShortTooltip = "Equipment SlotTags for Equipment Slots"))
class THIRDPERSON_API UEquipmentSlots : public UDataAsset
{
    GENERATED_BODY()

protected:

    UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="EquipmentSlot | Main")
    FMainEquipmentSlot Slot;

    UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="EquipmentSlot | Sub", meta=(TitleProperty="{DisplayName}"))
    TArray<FSubEquipmentSlot> SlotList;

public:
    FORCEINLINE TArray<FGameplayTag> GetAll() const { return All; }
    FORCEINLINE FGameplayTag GetPrimary() const { return Primary; }
};

EquipmentComponentBase를 EquipmentComponent, DynamicEquipmentComponent에 상속시켜 DA_EquipmentSlots의 종류에 따라 자동으로 변환시키는 방법도 좋을 것 같다.

Eu4ng commented 1 year ago

FGameplayTagContainer 대신 TArray를 사용하면 에디터 편집 시 가시성이 더 나은 것 같다.

image