Меня зовут Дмитрий. Я занимаюсь созданием компьютерных игр на Unreal Engine в качестве хобби. Сегодня я хотел бы рассказать как в Unreal Engine создать свой тип ассета и как добавить дополнительный элемент на панель свойств ассета. Итак начнем.
Начнем с создания ассета. Во первых надо создать класс для своего ассета.
UCLASS()
class UICUSTOM_API UMyObject : public UObject
{
GENERATED_BODY()
public:
UPROPERTY(EditAnywhere, Category = "My Object Properties")
FString Name;
};
После этого нужно чтобы наш ассет отображался в контент браузере для этого создаем потомка для класса UFactory:
UCLASS()
class UICUSTOM_API UMyObjectFactory : public UFactory
{
GENERATED_UCLASS_BODY()
// UFactory interface
virtual UObject* FactoryCreateNew(UClass* Class, UObject* InParent, FName Name, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn) override;
// End of UFactory interface
virtual bool CanCreateNew() const override;
};
Здесь для нас наиболее важным методом является FactoryCreateNew который создает экземпляр нашего класса.
UObject* UMyObjectFactory::FactoryCreateNew(UClass* Class, UObject* InParent, FName Name, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn)
{
UMyObject* NewObjectAsset = NewObject<UMyObject>(InParent,Class, Name, Flags | RF_Transactional);
return NewObjectAsset;
}
Итак наш ассет уже можно создать в контент браузере но нельзя выбрать не название, не цвет иконки, не категорию в конце концов. Для всего этого необходимо создать ещё один класс, потомок FAssetTypeActions_Base.
class UICUSTOM_API FMyObjectAssetAction : public FAssetTypeActions_Base
{
public:
virtual FText GetName() const override;
virtual FColor GetTypeColor() const override;
virtual UClass* GetSupportedClass() const override;
virtual bool HasActions(const TArray<UObject*>& InObjects) const override { return false; }
virtual uint32 GetCategories() override;
static void RegistrateCustomPartAssetType();
};
В принцепе все понятно по названию методов кроме метода RegistrateCustomPartAssetType(). Этот метод нужен для регистрации данного класса. Итак откуда же его вызывать? Этот метод должен быть вызван один раз при загрузке редактора, поэтому наиболее подходящее место для его вызова это конструктор GameMode. Вот собственно и он:
AUICustomGameMode::AUICustomGameMode()
{
#if WITH_EDITORONLY_DATA
FMyClassDetails::RegestrateCostumization();
FMyObjectAssetAction::RegistrateCustomPartAssetType();
#endif //WITH_EDITORONLY_DATA
}
После этого можно компилировать проект и наслаждаться результатом:
Вы наверно спросите. А какой в этом смысл, я ведь могу точно также создать блюпринт который будет наследовать MyObject, получится тоже самое но без геморроя. Здесь надо уточнить что блюпринт является классом наследником MyObject а не им самим.
Например если разместить ссылку на MyObject в каком нибудь другом ассете то созданный таким образом ассет вы выбрать сможете, а блюпринт для которого этот ассет является базовым нет.
Как видете ассет есть, а блюпринта нет.
Теперь перейдем к добавлению элементов на панель свойств ассета. Для этого создадим подопытный класс:
UCLASS()
class UICUSTOM_API ATestAct : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
ATestAct();
// Called when the game starts or when spawned
virtual void BeginPlay() override;
// Called every frame
virtual void Tick( float DeltaSeconds ) override;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
UMyObject* MyObject;
};
Что бы кастомизировать его панель свойств нужно создать класс наследник IDetailCustomization:
class FMyClassDetails : public IDetailCustomization
{
public:
static FReply MClick(IDetailLayoutBuilder* DetailBuilder);
/** Makes a new instance of this detail layout class for a specific detail view requesting it */
static TSharedRef<IDetailCustomization> MakeInstance();
static void RegestrateCostumization();
/** IDetailCustomization interface */
virtual void CustomizeDetails(IDetailLayoutBuilder& DetailBuilder) override;
static void ShowNotification(FText Text, SNotificationItem::ECompletionState State = SNotificationItem::CS_None);
static ATestAct* GetObject(IDetailLayoutBuilder* DetailBuilder);
};
Итак разъясняю: MClick метод который сработает когда мы нажмем на добавленную кнопку (в качестве примера я выбрал кнопку, но это может быть любой элемент интерфейса).
CustomizeDetails метод в котором происходит добавление нового элемента на панель деталей:
void FMyClassDetails::CustomizeDetails(IDetailLayoutBuilder& DetailBuilder)
{
// Create a category so this is displayed early in the properties
ATestAct* TestAct = GetObject(&DetailBuilder);
IDetailCategoryBuilder& MyCategory = DetailBuilder.EditCategory("Button", FText::GetEmpty(), ECategoryPriority::Important);
//You can get properties using the detailbuilder
//MyProperty= DetailBuilder.GetProperty(GET_MEMBER_NAME_CHECKED(MyClass, MyClassPropertyName));
FText TestHUDText = FText::FromString("Your Text");
MyCategory.AddCustomRow(TestHUDText)
.ValueContent() //NameContent()
[
SNew(SButton)
.Text(FText::FromString("ShowMessage"))
.OnClicked(FOnClicked::CreateStatic(&FMyClassDetails::MClick, &DetailBuilder))
];
}
RegestrateCostumization Метод необходимый для регистрации данной кастомизации. (Вы наверно заметили его вызов из конструктора GameMode) хочется отметить что TestAct нужно вводить без префикса A:
void FMyClassDetails::RegestrateCostumization()
{
FPropertyEditorModule& PropertyModule = FModuleManager::LoadModuleChecked<FPropertyEditorModule>("PropertyEditor");
//Custom detail views
PropertyModule.RegisterCustomClassLayout("TestAct", FOnGetDetailCustomizationInstance::CreateStatic(&FMyClassDetails::MakeInstance));
}
ShowNotification Просто выводит сообщение на экран. GetObject Позволяет получить ссылку на кастомизируемый объект (ATestAct в данном случае).
Итак, вот что мы имеем в результате:
Спасибо за внимание, надеюсь, этот урок позволит вам создавать ещё более лучшие и интересные игры. Проект с исходными кодами можно скачать здесь.
Автор: deema35