[Data] Flexible DataΒΆ

We want to create a widget depending on the object data type we have. The default widget will be a W_Object UUserWidget, but we also want to create specific widgets like W_Planet

Our subsystem will create the widgets depending on the data type (used as a type tag to have multiple overloads)

The subsytem

UCLASS()
class UARKSubSystem : public UGameInstanceSubsystem
{
    GENERATED_BODY()

public:
    UUserWidget* GetWidget(UObject* Object, const UARKObjectData*)
    {
        // Create an object widget
        auto* Widget = CreateWidget<UARKObjectWidget>(GetWorld(), ObjectWidget);
        Widget->Object = Object; // Give our object to the widget
        return Widget;
    }
    UUserWidget* GetWidget(UObject* Object, const UARKPlanetData*)
    {
        // Create a planet widget
        auto* Widget = CreateWidget<UARKObjectWidget>(GetWorld(), PlanetWidget);
        Widget->Object = Object; // Give our object to the widget
        return Widget;
    }
};

Default widget for base data

GetWidget could be call from a base class or an interface passing the object containing the data (Data->GetWidget(this);)

UCLASS(BlueprintType, Blueprintable, EditInlineNew, DefaultToInstanced, CollapseCategories)
class UARKObjectData : public UObject
{
    GENERATED_BODY()

public:
    virtual UUserWidget* GetWidget(UObject* Object)
    {
        // Calling GetWidget with this will call the UARKObjectData overload
        return GetWorld()->GetGameInstance()->GetSubsystem<UARKSubSystem>()->GetWidget(Object, this);
    }
};

Specific widget for planet data

UCLASS(BlueprintType, Blueprintable)
class UARKPlanetData : public UARKObjectData
{
    GENERATED_BODY()

public:
    virtual UUserWidget* GetWidget(UObject* Object) override
    {
        // Calling GetWidget with this will call the UARKPlanetData overload
        return GetWorld()->GetGameInstance()->GetSubsystem<UARKSubSystem>()->GetWidget(Object, this);
    }

};

The base for our widgets

UCLASS()
class UARKObjectWidget : public UUserWidget
{
    GENERATED_BODY()

public:
    // Get the object from the widget
    UObject* GetObject() const;
    // Our objects store data so we can just get the datas from a base or an interface
    UNGObjectData* GetData() const
    {
        // Using an interface
        return Cast<IARKObject>(Object)->GetData();
    }

    UPROPERTY()
    UObject* Object;
};
So if we have a W_Planet widget inheriting from UARKObjectWidget, the object associated to our widget would be an AARKPlanet containing a UARKPlanetData.

We can now Get/Make a widget from a base object/interface and get the data from this widget with a hierarchy. YAY !