목차

     

     


     

     
    Plugins
     
      Weapon
     
        Resource
     
          Icon128.png
    weapon_thumbnail_icon.png
     
        Source
     
          Weapon  
          SWeaponCheckBoxes.h .cpp
    SWeaponDetailsView
    .h .cpp
    SWeaponDoActionData.h .cpp
    SWeaponEquipmentData.h .cpp
    SWeaponLeftArea.h .cpp
    Weapon.Build.cs
    WeaponAssetEditor.h .cpp
    WeaponAssetFactory.h .cpp
    WeaponCommand.h .cpp 
    WeaponContextMenu.h .cpp
    WeaponModule.h .cpp
    WeaponStyle.h .cpp 
     
       

     

     
    Source
        Characters
        CAnimInstance.h .cpp
    CEnemy.h .cpp 
    CPlayer.h .cpp
    ICharacter.h .cpp
        Components
        CMontagesComponent.h .cpp 
    CMovementComponent.h .cpp 
    CStateComponent.h .cpp 
    CWeaponComponent.h .cpp 
        Notifies
        CAnimNotifyState_BeginAction.h .cpp 
    CAnimNotify_CameraShake.h .cpp
    CAnimNotifyState_EndAction.h .cpp
    CAnimNotify_EndState.h .cpp
    CAnimNotifyState_Collision.h .cpp 
    CAnimNotifyState_Combo.h .cpp
    CAnimNotifyState_Equip.h .cpp
        Utilities
        CHelper.h
    CLog.h .cpp
        Weapons
        CDoAction_Combo.h .cpp
    CAttachment.h .cpp
    CDoAction.h .cpp
    CEquipment.h .cpp
    CWeaponAsset.h .cpp
    CWeaponStructures.h .cpp
        Global.h
    CGameMode.h .cpp
    .Build.cs
        .uproject
     

     

     

     

     

    DoAction Data 연동하기 II

     

     


     

    'ProjectName'.Build.cs

     

    'ProjectName'.Build.cs

    더보기
    using UnrealBuildTool;
    
    public class U2212_06 : ModuleRules
    {
    	public U2212_06(ReadOnlyTargetRules Target) : base(Target)
    	{
            PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
    
    		PublicIncludePaths.Add(ModuleDirectory);
    
    
            PublicDependencyModuleNames.Add("Core");
    
            PrivateDependencyModuleNames.Add("CoreUObject");
            PrivateDependencyModuleNames.Add("Engine");
            PrivateDependencyModuleNames.Add("InputCore");
    
            PublicDependencyModuleNames.Add("Niagara");
        }
    }

    Dependency Module 접근 범위 변경

    • 게임 프로젝트 뿐만 아니라 Plugin쪽에서도 Niagara 접근을 할 수 있도록 private을 public으로 변경한다.
    • 변경 전: PrivateDependencyModuleNames.Add("Niagara");
    • 변경 후: PublicDependencyModuleNames.Add("Niagara");

     


     

    SWeaponDoActionData

     

    SWeaponDoActionData.h

    더보기
    #pragma once
    #include "CoreMinimal.h"
    #include "IPropertyTypeCustomization.h"
    
    class WEAPON_API SWeaponDoActionData
    	: public IPropertyTypeCustomization
    {
    public:
    	static TSharedRef<IPropertyTypeCustomization> MakeInstance();
    	static TSharedPtr<class SWeaponCheckBoxes> AddCheckBoxes();
    	static void EmptyCheckBoxes();//한번에 비워주는 역할의 함수
    
    	void CustomizeHeader(TSharedRef<IPropertyHandle> InPropertyHandle, FDetailWidgetRow& InHeaderRow, IPropertyTypeCustomizationUtils& InCustomizationUtils) override;
    	void CustomizeChildren(TSharedRef<IPropertyHandle> InPropertyHandle, IDetailChildrenBuilder& InChildBuilder, IPropertyTypeCustomizationUtils& InCustomizationUtils) override;
    	
    private:
    	static TArray<TSharedPtr<class SWeaponCheckBoxes>> CheckBoxes;
    };

    변동사항 없음.

     

     

     

    SWeaponDoActionData.cpp

    더보기
    #include "SWeaponDoActionData.h"
    #include "WeaponStyle.h"
    #include "IPropertyUtilities.h"
    #include "IDetailPropertyRow.h"
    #include "IDetailChildrenBuilder.h"
    #include "SWeaponCheckBoxes.h"
    #include "DetailWidgetRow.h"
    
    TArray<TSharedPtr<SWeaponCheckBoxes>> SWeaponDoActionData::CheckBoxes;
    
    TSharedRef<IPropertyTypeCustomization> SWeaponDoActionData::MakeInstance()
    {
    	//자신의 클래스 타입을 만들어서 return해준다.
    	return MakeShareable(new SWeaponDoActionData());
    }
    
    TSharedPtr<SWeaponCheckBoxes> SWeaponDoActionData::AddCheckBoxes()
    {
    	TSharedPtr<SWeaponCheckBoxes> checkBoxes = MakeShareable(new SWeaponCheckBoxes());
    	int32 index = CheckBoxes.Add(checkBoxes);
    
    	return CheckBoxes[index];
    }
    
    void SWeaponDoActionData::EmptyCheckBoxes()
    {
    	for (TSharedPtr<SWeaponCheckBoxes> ptr : CheckBoxes)
    	{
    		if (ptr.IsValid())
    			ptr.Reset();
    	}
    
    	CheckBoxes.Empty();
    }
    
    void SWeaponDoActionData::CustomizeHeader(TSharedRef<IPropertyHandle> InPropertyHandle, FDetailWidgetRow& InHeaderRow,
    	IPropertyTypeCustomizationUtils& InCustomizationUtils)
    {
    	if (SWeaponCheckBoxes::CanDraw(InPropertyHandle, CheckBoxes.Num()) == false)
    		return;//CanDraw가 false면 그리지 않고 리턴.
    
    	int32 index = InPropertyHandle->GetIndexInArray();//GetIndexInArray()는 Array 안에서의 번호를 리턴.
    	CheckBoxes[index]->SetUtilities(InCustomizationUtils.GetPropertyUtilities());//Header,Children,Header,Children..순서로 콜된다.
    
    	FString name = InPropertyHandle->GetPropertyDisplayName().ToString();//0,1,2..표시하는 name
    	name = "DoAction Data - " + name;
    
    	InHeaderRow
    	.NameContent()
    	[
    		SNew(SBorder)//SBorder는 한 줄을 출력할 때 사용.
    		.BorderImage(FWeaponStyle::Get()->Array_Image.Get())
    		[
    			InPropertyHandle->CreatePropertyNameWidget(FText::FromString(name))
    		]
    	]
    	.ValueContent()
    	.MinDesiredWidth(FWeaponStyle::Get()->DesiredWidth.X)
    	.MaxDesiredWidth(FWeaponStyle::Get()->DesiredWidth.Y)
    	[
    		CheckBoxes[index]->Draw(true)//CheckBoxes를 그려준다(=생성한다).bBackground에 true값을 넣어주어 alpha값이 0.1f인 흰색 이미지가 겹쳐저 해당 줄이 띠처럼 보이게 만들어준다.
    	];
    }
    
    void SWeaponDoActionData::CustomizeChildren(TSharedRef<IPropertyHandle> InPropertyHandle,
    	IDetailChildrenBuilder& InChildBuilder, IPropertyTypeCustomizationUtils& InCustomizationUtils)
    {
    	if (SWeaponCheckBoxes::CanDraw(InPropertyHandle, CheckBoxes.Num()) == false)
    		return;//CanDraw가 false면 그리지 않고 리턴.
    
    	int32 index = InPropertyHandle->GetIndexInArray();//GetIndexInArray()는 Array 안에서의 번호를 리턴.
    	CheckBoxes[index]->DrawProperties(InPropertyHandle, &InChildBuilder);
    }

    헤더 추가

    • #include "WeaponStyle.h"

     

    함수 정의

    • void SWeaponDoActionData::CustomizeHeader(TSharedRef<IPropertyHandle> InPropertyHandle, FDetailWidgetRow& InHeaderRow, IPropertyTypeCustomizationUtils& InCustomizationUtils)
      • int32 index = InPropertyHandle->GetIndexInArray();
        • GetIndexInArray()는 Array 안에서의 번호를 리턴.
      • CheckBoxes[index]->SetUtilities(InCustomizationUtils.GetPropertyUtilities());
        • //Header, Children, Header, Children...순서로 콜된다.

     

     


     

    SWeaponEquipmentData - 창의 너비와 폭의 최소 최대값 변경  

     

    마이너한 변경사항.

     

    SWeaponEquipmentData.h

    변동사항 없음.

     

     

    SWeaponEquipmentData.cpp

    더보기
    #include "SWeaponEquipmentData.h"
    #include "WeaponStyle.h"
    #include "IPropertyUtilities.h"
    #include "IDetailPropertyRow.h"
    #include "IDetailChildrenBuilder.h"
    #include "SWeaponCheckBoxes.h"
    #include "DetailWidgetRow.h"
    
    TSharedPtr<SWeaponCheckBoxes> SWeaponEquipmentData::CheckBoxes;//초기화
    
    TSharedRef<IPropertyTypeCustomization> SWeaponEquipmentData::MakeInstance()
    {
    	//자신의 클래스 타입을 만들어서 return해준다.
    	return MakeShareable(new SWeaponEquipmentData());
    }
    
    TSharedPtr<SWeaponCheckBoxes> SWeaponEquipmentData::CreateCheckBoxes()
    {
    	if (CheckBoxes.IsValid())
    	{
    		CheckBoxes.Reset();
    		CheckBoxes = nullptr;
    	}
    
    	return CheckBoxes = MakeShareable(new SWeaponCheckBoxes());
    }
    
    void SWeaponEquipmentData::CustomizeHeader(TSharedRef<IPropertyHandle> InPropertyHandle, FDetailWidgetRow& InHeaderRow, IPropertyTypeCustomizationUtils& InCustomizationUtils)
    {
    	CheckBoxes->SetUtilities(InCustomizationUtils.GetPropertyUtilities());
    
    	InHeaderRow
    	.NameContent()
    	[
    		InPropertyHandle->CreatePropertyNameWidget()
    	]
    	.ValueContent()
    	.MinDesiredWidth(FWeaponStyle::Get()->DesiredWidth.X)
    	.MaxDesiredWidth(FWeaponStyle::Get()->DesiredWidth.Y)
    	[
    		CheckBoxes->Draw()//CheckBoxes를 그려준다(=생성한다).
    	];
    }
    
    void SWeaponEquipmentData::CustomizeChildren(TSharedRef<IPropertyHandle> InPropertyHandle, IDetailChildrenBuilder& InChildBuilder, IPropertyTypeCustomizationUtils& InCustomizationUtils)
    {
    	CheckBoxes->DrawProperties(InPropertyHandle, &InChildBuilder);
    }

    헤더 추가

    • #include "WeaponStyle.h"

     

    함수 내용수정

    •  창의 너비와 폭의 최소, 최대값을 설정. FWeaponStyle 내의 변수 DesiredWidth를 사용.
      • 변경 전: .MinDesiredWidth(FEditorStyle::GetFloat("StandardDialog.MinDesiredSlotWidth"))
                     .MaxDesiredWidth(FEditorStyle::GetFloat("StandardDialog.MaxDesiredSlotWidth"))
            
      • 변경 후: .MinDesiredWidth(FWeaponStyle::Get()->DesiredWidth.X)
                     .MaxDesiredWidth(FWeaponStyle::Get()->DesiredWidth.Y)

     

     


     

    WeaponStyle

     

    WeaponStyle.h

    더보기
    #pragma once
    #include "CoreMinimal.h"
    
    class WEAPON_API FWeaponStyle
    {
    public:
    	static TSharedRef<FWeaponStyle> Get();
    	static void Shutdown();
    
    private:
    	static TSharedPtr<FWeaponStyle> Instance;
    
    public:
    	FWeaponStyle();
    	~FWeaponStyle();
    
    private:
    	void RegisterIcon(const FString& InName, const FString& InPath, const FVector2D& InIconSize, FSlateIcon& OutSlateIcon);
    
    private:
    	static const FName StyleSetName;
    
    private:
    	TSharedPtr<class FSlateStyleSet> StyleSet;
    
    public:
    	FSlateIcon ToolBar_Icon;
    
    	TSharedPtr<struct FSlateImageBrush> Array_Image;
    
    public:
    	const FVector2D DesiredWidth = FVector2D(250, 1000);
    };

    변수 추가

    • TSharedPtr<struct FSlateImageBrush> Array_Image;

     

     

     

    WeaponStyle.cpp

    더보기
    #include "WeaponStyle.h"
    #include "Styling/SlateStyle.h"
    #include "Styling/SlateStyleRegistry.h"
    
    const FName FWeaponStyle::StyleSetName = "WeaponStyle";
    
    TSharedPtr<FWeaponStyle> FWeaponStyle::Instance = nullptr;
    
    TSharedRef<FWeaponStyle> FWeaponStyle::Get()
    {
        if (Instance == nullptr)
            Instance = MakeShareable(new FWeaponStyle());
    
        return Instance.ToSharedRef();
    }
    
    void FWeaponStyle::Shutdown()
    {
        if (Instance.IsValid())
            Instance.Reset();
    }
    
    FWeaponStyle::FWeaponStyle()
    {
        StyleSet = MakeShareable(new FSlateStyleSet(StyleSetName));
    
    
        FString path = "";
    
        path = FPaths::ProjectPluginsDir() / "Weapon" / "Resources";
        RegisterIcon("ToolBar_Icon", path / "weapon_thumnail_icon.png", FVector2D(40, 40), ToolBar_Icon);
    
        FSlateStyleRegistry::RegisterSlateStyle(*StyleSet.Get());
    
    
        path = FPaths::EngineConfigDir() / "Editor" / "Slate" / "Common/Selection.png";//Engine이 설치된 Config 경로에 있는 해당 png 이미지의 파일 경로
        Array_Image = MakeShareable(new FSlateImageBrush(path, FVector2D(8, 8), FLinearColor(1, 1, 1, 0.1f)));//path 경로의 이미지를 (8, 8)사이즈로 해당 색과 alpha값으로 생성한다. 
    }
    
    FWeaponStyle::~FWeaponStyle()
    {
        if (Array_Image.IsValid())
            Array_Image.Reset();
    
        if (StyleSet.IsValid() == false) return;
    
        FSlateStyleRegistry::UnRegisterSlateStyle(StyleSetName);
        StyleSet.Reset();
    }
    
    void FWeaponStyle::RegisterIcon(const FString& InName, const FString& InPath, const FVector2D& InIconSize, FSlateIcon& OutSlateIcon)
    {
        FSlateImageBrush* brush = new FSlateImageBrush(InPath, InIconSize);
    
        FString name = StyleSetName.ToString() + "." + InName;
        StyleSet->Set(FName(name), brush);
    
        OutSlateIcon = FSlateIcon(FName(StyleSetName), FName(name));
    }

    함수 내용 추가

    • FWeaponStyle::FWeaponStyle()
      •  path = FPaths::EngineConfigDir() / "Editor" / "Slate" / "Common/Selection.png";
        • Engine이 설치된 Config 경로를 적어준다.
        • 아래의 이미지가 경로에 있는 이미지. 
      • Array_Image = MakeShareable(new FSlateImageBrush(path, FVector2D(8, 8), FLinearColor(1, 1, 1, 0.1f)));
        • 이미지를 생성하여 넣어준다.
        • path는 가져오는 이미지 경로.
        • Opacity를 떨어뜨리기 위해 (1, 1, 1, 0.1f)로 alpha값을 10%로 설정해준다.

     

     

    ※ 참고) Engine\UE4.26\Engine\Content\Editor\Slate\Common 내의 아이콘 이미지 파일들


     

    SWeaponCheckBoxes

     

    SWeaponCheckBoxes.h

    더보기
    #pragma once
    
    #include "CoreMinimal.h"
    
    class WEAPON_API SWeaponCheckBoxes
        : public TSharedFromThis<SWeaponCheckBoxes> // 직접적으로 상속받으면 주소가 일치하게된다.
    {
    public:
        //IPropertyHandle는 하나의 Property에 대한 식별자
        void AddProperties(TSharedPtr<IPropertyHandle> InHandle);
    
        //SNew에 최상의 부모가 SWidget이 된다. 레퍼런스를 사용하기 때문에 동일하게 쓰기위함
        TSharedRef<SWidget> Draw(bool bBackground = false);//디폴트 파라미터로 기본값을 false로 설정.
    
        //해당 Properties를 그릴지 말지 결정
        void DrawProperties(TSharedRef<IPropertyHandle> InPropertyHandle, IDetailChildrenBuilder* InChildrenBuilder);
    
        //객체를 외부에서 받기위해,
        void SetUtilities(TSharedPtr<class IPropertyUtilities> InUtilities);
    
    private:
        //체크가 완료되었는지 
        void OnCheckStateChanged(ECheckBoxState InState, int32 InIndex);
    
    public:
        static bool CanDraw(TSharedPtr<IPropertyHandle> InHandle, int InCount);//사용자가 체크한 InHandle이 들어와서 배열이 개수와 일치하는지 판단. 배열 범위를 벗어나면 그리지 않도록 false를 리턴.
    
    public:
        //InIndex에는 Property 번호가 InValue에는 값.
        void CheckDefaultObject(int32 InIndex, UObject* InValue);
        void CheckDefaultValue(int32 InIndex, float InValue);
        void CheckDefaultValue(int32 InIndex, bool InValue);
        void CheckDefaultValue(int32 InIndex, const FVector& InValue);
    
    private:
        //내부 구조체 생성, 관리를 위해 사용
        struct FInternalData
        {
            bool bChecked;//체크 되었는가
            FString Name;//이름
            TSharedPtr<IPropertyHandle> Handle;
    
            FInternalData(TSharedPtr<IPropertyHandle> InHandle)
            {
                bChecked = false;//기본값은 false로 설정.
                Handle = InHandle;
    
                Name = Handle->GetPropertyDisplayName().ToString();//핸들 내의 DisplayName을 출력이름으로 설정.
            }
        };
        TArray<FInternalData> InternalDatas;//구조체 Data 전부를 포괄한 배열변수
    
        TSharedPtr<class IPropertyUtilities> Utilities;//멤버 변수
    };

    변수 추가

    • TSharedRef<SWidget> Draw(bool bBackground = false);
      • 디폴트 파라미터로 기본값을 false로 설정.

     

    static 함수 추가

    • static bool CanDraw(TSharedPtr<IPropertyHandle> InHandle, int InCount);
      • 사용자가 체크한 InHandle이 들어와서 배열이 개수와 일치하는지 판단. 배열 범위를 벗어나면 그리지 않도록 false를 리턴.

     

     

    SWeaponCheckBoxes.cpp

    더보기
    #include "SWeaponCheckBoxes.h"
    #include "WeaponStyle.h"
    #include "SWeaponDetailsView.h"
    #include "Widgets/Layout/SUniformGridPanel.h"
    #include "IPropertyUtilities.h"
    #include "IDetailPropertyRow.h"
    #include "IDetailChildrenBuilder.h"
    #include "DetailWidgetRow.h"
    
    void SWeaponCheckBoxes::AddProperties(TSharedPtr<IPropertyHandle> InHandle)
    {
        uint32 number = 0;
        InHandle->GetNumChildren(number);//핸들 내의 자식 property가 몇 개 있는지 가져온다.
    
        for (uint32 i = 0; i < number; i++)
            InternalDatas.Add(FInternalData(InHandle->GetChildHandle(i)));
    }
    
    TSharedRef<SWidget> SWeaponCheckBoxes::Draw(bool bBackground)
    {
        TSharedPtr<SUniformGridPanel> panel;
        SAssignNew(panel, SUniformGridPanel);//SNew와 다르게 변수를 선언해 놓는 SAssignNew
        panel->SetMinDesiredSlotWidth(150);//최소폭 150으로 설정.
    
        for (int32 i = 0; i < InternalDatas.Num(); i++)
        {
            panel->AddSlot(i, 0)//한줄만 사용, 여러줄사용하려면 ex) i % 5
            [
                SNew(SCheckBox)//체크박스는 컨텐츠 영역을 가지고 있다.
                .IsChecked(InternalDatas[i].bChecked)//체크 여부 출력, 0과 1로만 판단
    	        .OnCheckStateChanged(this, &SWeaponCheckBoxes::OnCheckStateChanged, i)//체크 했는지 판단
    	        [
    	            SNew(STextBlock)
    	            .Text(FText::FromString(InternalDatas[i].Name))//InternalDatas의 이름들 출력
    	        ]
            ];
        }
    
        if(bBackground == false)
    		return panel.ToSharedRef();//추가를 하게되면, 추가된 그자체를 return
    
    
        TSharedPtr<SBorder> border = SNew(SBorder)//한 줄 생성.
        .BorderImage(FWeaponStyle::Get()->Array_Image.Get())
        [
            panel.ToSharedRef()//panel를 컨텐츠 영역으로 넣어준다.
        ];
    
        return border.ToSharedRef();//border를 리턴.
    }
    
    void SWeaponCheckBoxes::DrawProperties(TSharedRef<IPropertyHandle> InPropertyHandle, IDetailChildrenBuilder* InChildrenBuilder)
    {
        for (int32 i = 0; i < InternalDatas.Num(); i++)
        {
            // 체크박스에 체크를 바꾸게 되는지 확인, 바꾸지 안았다면 그릴 필요가 없다.
            if (InternalDatas[i].bChecked == false)//그릴 필요가 없는 경우
                continue;
            // 각 줄에 식별자
            TSharedPtr<IPropertyHandle> handle = InPropertyHandle->GetChildHandle(i);
            // 자식부분을 담당, 이 Handle이 기본모양을 추가해서 만들어준다. 커스텀 마이징도 가능하다
            IDetailPropertyRow& row = InChildrenBuilder->AddProperty(handle.ToSharedRef());
    
            FString name = FString("Name ") + FString::FromInt(i + 1);
    
            row.CustomWidget()
            .NameContent()
            [
                handle->CreatePropertyNameWidget()
            ]
            //줄이거나 늘렸을 때 Min 이하로는 고정. Max 이상으로는 고정.
            .ValueContent()
            .MinDesiredWidth(FWeaponStyle::Get()->DesiredWidth.X)
            .MaxDesiredWidth(FWeaponStyle::Get()->DesiredWidth.Y)
            [
                handle->CreatePropertyValueWidget()
            ];
        }
    }
    
    void SWeaponCheckBoxes::SetUtilities(TSharedPtr<IPropertyUtilities> InUtilities)
    {
        //외부 객체 받아오기
        Utilities = InUtilities;
    }
    
    void SWeaponCheckBoxes::OnCheckStateChanged(ECheckBoxState InState, int32 InIndex)
    {
        //상태를 바뀌는걸 확인했기때문에, 값을 뒤집어 줘서 다시 안그려지게 만들어준다.
        InternalDatas[InIndex].bChecked = !InternalDatas[InIndex].bChecked;
    
        SWeaponDetailsView::OnRefreshByCheckBoxes();
        {
            // ForceRefresh이 콜이되면 새로고침이 되면서 다시 그려진다.
            Utilities->ForceRefresh();
        }
        SWeaponDetailsView::OffRefreshByCheckBoxes();
    
    }
    
    bool SWeaponCheckBoxes::CanDraw(TSharedPtr<IPropertyHandle> InHandle, int InCount)
    {
        bool bCheck = true;
        bCheck &= InCount > 0;//배열의 개수 InCount가 0보다 큰지
    
        int32 index = InHandle->GetIndexInArray();//InHandle에서 배열 인덱스번호를 가져온다.
        bCheck &= index >= 0;
        bCheck &= index < InCount;//인덱스가 InCount 배열의 개수보다 작은지//크면 범위를 벗어나서 그릴 수 없다.
    
        return bCheck;
    }
    
    void SWeaponCheckBoxes::CheckDefaultObject(int32 InIndex, UObject* InValue)
    {
        UObject* val = nullptr;//기본값
        InternalDatas[InIndex].Handle->GetValue(val);//해당 Property에 선택한 값
    
        if (!!val && InValue != val)//nullptr이거나 선택한 값이랑 기본값이 다르다면
            InternalDatas[InIndex].bChecked = true;
    }
    
    void SWeaponCheckBoxes::CheckDefaultValue(int32 InIndex, float InValue)
    {
        float val = 0.0f;//기본값
        InternalDatas[InIndex].Handle->GetValue(val);//해당 Property에 선택한 값
    
        if (InValue != val)//선택한 값이랑 기본값이 다르다면
            InternalDatas[InIndex].bChecked = true;
    }
    
    void SWeaponCheckBoxes::CheckDefaultValue(int32 InIndex, bool InValue)
    {
        bool val = false;//기본값
        InternalDatas[InIndex].Handle->GetValue(val);//해당 Property에 선택한 값
    
        if (InValue != val)//선택한 값이랑 기본값이 다르다면
            InternalDatas[InIndex].bChecked = true;
    }
    
    void SWeaponCheckBoxes::CheckDefaultValue(int32 InIndex, const FVector& InValue)
    {
        FVector val = FVector::ZeroVector;//기본값
        InternalDatas[InIndex].Handle->GetValue(val);//해당 Property에 선택한 값
    
        if (InValue != val)//선택한 값이랑 기본값이 다르다면
            InternalDatas[InIndex].bChecked = true;
    }

    함수 정의

    • TSharedRef<SWidget> SWeaponCheckBoxes::Draw(bool bBackground)
    • bool SWeaponCheckBoxes::CanDraw(TSharedPtr<IPropertyHandle> InHandle, int InCount)

     

     


     

     

    실행화면

     

     

     


     

     

     

     

    Source 파일 수정

     

     


     

    WeaponAsset

     

    WeaponAsset.h

    더보기
    #pragma once
    #include "CoreMinimal.h"
    #include "Engine/DataAsset.h"
    #include "Weapons/CWeaponStructures.h"
    #include "CWeaponAsset.generated.h"
    
    UCLASS()
    class U2212_06_API UCWeaponAsset : public UDataAsset
    {
    	GENERATED_BODY()
    
    private:
    	UPROPERTY(EditAnywhere)
    		TSubclassOf<class ACAttachment> AttachmentClass;
    
    	UPROPERTY(EditAnywhere)
    		FEquipmentData EquipmentData;
    
    	UPROPERTY(EditAnywhere)
    		TSubclassOf<class UCEquipment> EquipmentClass;
    
    	UPROPERTY(EditAnywhere)
    		TSubclassOf<class UCDoAction> DoActionClass;
    
    	UPROPERTY(EditAnywhere)
    		TArray<FDoActionData> DoActionDatas; //CWeaopnStructure내의 FDoActionData
    
    	UPROPERTY(EditAnywhere)
    		TArray<FHitData> HitDatas; //CWeaopnStructure내의 FHitData
    
    public:
    	FORCEINLINE class ACAttachment* GetAttachment() { return Attachment; }//외부에 생성된 것을 리턴해줌. 
    	FORCEINLINE class UCEquipment* GetEquipment() { return Equipment; }//외부에 생성된 것을 리턴해줌.
    	FORCEINLINE class UCDoAction* GetDoAction() { return DoAction; }//외부에 생성된 것을 리턴해줌.
    
    public:
    	UCWeaponAsset();
    
    	void BeginPlay(class ACharacter* InOwner);
    
    private:
    	//UPROPERTY를 붙여 가비지 콜렉터가 제거하기 전까지 물고 있게 만든다.
    	//UWeaponAsset은 UObject로부터 상속받아 Actor의 생성주기에 영향을 받지 않아 가비지 콜렉터에 영향을 받는다.
    	UPROPERTY() 
    		class ACAttachment* Attachment;
    
    	UPROPERTY()
    		class UCEquipment* Equipment;
    
    	UPROPERTY()
    		class UCDoAction* DoAction;
    
    
    #if WITH_EDITOR //Editor 내에서만 수행
    	void PostEditChangeChainProperty(struct FPropertyChangedChainEvent& PropertyChangedEvent) override;
    #endif
    };

    함수 추가

    • void PostEditChangeChainProperty(struct FPropertyChangedChainEvent& PropertyChangedEvent) override;
      • UObject의 함수 오버라이드

     

    ※참고) Object.h의 void PostEditChangeProperty() 함수

    • property가 밖에서 바뀐 이후에 콜 된다.

     

     

     

    WeaponAsset.cpp

    더보기
    #include "Weapons/CWeaponAsset.h"
    #include "Global.h"
    #include "CAttachment.h"
    #include "CEquipment.h"
    #include "CDoAction.h"
    #include "GameFramework/Character.h"
    
    UCWeaponAsset::UCWeaponAsset()
    {
    	AttachmentClass = ACAttachment::StaticClass();//기본값
    	EquipmentClass = UCEquipment::StaticClass();//기본값
    	DoActionClass = UCDoAction::StaticClass();//기본값
    }
    
    void UCWeaponAsset::BeginPlay(ACharacter* InOwner)
    {
    	if (!!AttachmentClass)//AttachmentClass가 선택되어 있다면
    	{
    		FActorSpawnParameters params;
    		params.Owner = InOwner;
    
    		Attachment = InOwner->GetWorld()->SpawnActor<ACAttachment>(AttachmentClass, params);
    	}
    
    	if (!!EquipmentClass)//EquipmentClass가 선택되어 있다면
    	{
    		Equipment = NewObject<UCEquipment>(this, EquipmentClass);
    		Equipment->BeginPlay(InOwner, EquipmentData);
    
    		if (!!Attachment)//Attachment가 있다면
    		{
    			Equipment->OnEquipmentBeginEquip.AddDynamic(Attachment, &ACAttachment::OnBeginEquip);
    			Equipment->OnEquipmentUnequip.AddDynamic(Attachment, &ACAttachment::OnUnequip);
    		}
    	}
    	 
    	if(!!DoActionClass)
    	{
    		DoAction = NewObject<UCDoAction>(this, DoActionClass);
    		DoAction->BeginPlay(Attachment, Equipment, InOwner, DoActionDatas, HitDatas);
    
    		if (!!Attachment)
    		{
    			Attachment->OnAttachmentBeginCollision.AddDynamic(DoAction, &UCDoAction::OnAttachmentBeginCollision);
    			Attachment->OnAttachmentEndCollision.AddDynamic(DoAction, &UCDoAction::OnAttachmentEndCollision);
    
    			Attachment->OnAttachmentBeginOverlap.AddDynamic(DoAction, &UCDoAction::OnAttachmentBeginOverlap);
    			Attachment->OnAttachmentEndOverlap.AddDynamic(DoAction, &UCDoAction::OnAttachmentEndOverlap);
    		}
    	}
    }
    
    #if WITH_EDITOR //Editor 내에서만 수행
    void UCWeaponAsset::PostEditChangeChainProperty(FPropertyChangedChainEvent& PropertyChangedEvent)
    {
    	Super::PostEditChangeChainProperty(PropertyChangedEvent);
    
    	CLog::Log(PropertyChangedEvent.GetPropertyName().ToString());//어떤 변수가 바뀌었는지 
    	CLog::Log((int32)PropertyChangedEvent.ChangeType);//어떤 명령에 의해 바뀌었는지
    }
    #endif

    함수 정의

    • void UCWeaponAsset::PostEditChangeChainProperty(FPropertyChangedChainEvent& PropertyChangedEvent)

     

     


     

    __VTableCtorCaller

     

    Editor에서 Hot Reloading이 일어나면 __VTableCtorCaller이 콜 된다.

    UObject에 있는 함수다.

     

     


     

    CDO

     

    Hot Reload는 CDO를 다시 읽어주는 역할을 수행한다.