Download

How to swap components within PostEditChangeProperty

hi,

i’m new to unreal engine (coming from unity). just trying to create some simple item pickup system.
therefore i created a pickup base class with a UStaticMeshComponent as RootComponent and a UShapeComponent as the trigger.
now i want to accomplish that i can select what type of UShapeComponent i like to use.
so i defined an enum with my possible shape values. then in PostEditChangeProperty i check if the TriggerShape has been changed and if so
i create a new Trigger and attach it to my root component.

then i create a blueprint based on my pickup. when i change now the value in the blueprint editor… the unreal editor crashes.

what am i doing wrong? or how should i implement the behaviour i like to achieve?



// Header
UENUM(BlueprintType)
enum class ETriggerShape : uint8
{
	S_Box		UMETA(DisplayName = "Box"),
	S_Sphere	        UMETA(DisplayName = "Sphere"),
	S_Max		UMETA(Hidden)
};

UCLASS()
class APickup : public AActor
{
	GENERATED_BODY()
	
public:	
	APickup();

	UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "Pickup")
	ETriggerShape TriggerShape;

protected:
	UPROPERTY(VisibleDefaultsOnly, BlueprintReadOnly, Category = "Pickup")
	class  UShapeComponent* Trigger;

	UPROPERTY(VisibleDefaultsOnly, BlueprintReadOnly, Category = "Pickup")
	class  UStaticMeshComponent* Mesh;

private:
	virtual void PostEditChangeProperty(struct FPropertyChangedEvent& PropertyChangedEvent) override;
};

// Cpp
APickup::APickup()
{
	PrimaryActorTick.bCanEverTick = false;

    Mesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Mesh"));
    RootComponent = Mesh;

    Trigger = CreateDefaultSubobject<UBoxComponent>(TEXT("Trigger"));
    Trigger->AttachTo(RootComponent);
}

void APickup::PostEditChangeProperty(struct FPropertyChangedEvent& PropertyChangedEvent)
{
    FName propertyName = (PropertyChangedEvent.Property != nullptr) ? PropertyChangedEvent.Property->GetFName() : NAME_None;

    if (propertyName == GET_MEMBER_NAME_CHECKED(APickup, TriggerShape))
    {
        Trigger->DetachFromParent();
        Trigger->DestroyComponent();

        if (TriggerShape == ETriggerShape::S_Box)
            Trigger = NewObject<UBoxComponent>(this, TEXT("Trigger"));
        else
            Trigger = NewObject<USphereComponent>(this, TEXT("Trigger"));

        Trigger->AttachTo(RootComponent);
    }

    Super::PostEditChangeProperty(PropertyChangedEvent);
}


Also it´s an old Post: as your Trigger is of type UShapeComponent you first need to to Cast to the needed component type:
I tried to do exactly this and so I stumbled upon this post. I do something like this:



switch (CustomTriggerShape)
    {
        case ECustomTriggerShapes::none:
            UE_LOG(LogTemp, Log, TEXT("Do NONEThings"));
            break;
        case ECustomTriggerShapes::BoxTrigger:
            UE_LOG(LogTemp,Log, TEXT("Do BOXThings"));
            HazardTrigger = Cast<UBoxComponent>(NewObject<UBoxComponent>(this));
            break;
        case ECustomTriggerShapes::SphereTrigger:
            UE_LOG(LogTemp,Log, TEXT("Do SPHEREThings"));
            HazardTrigger = Cast<USphereComponent>(NewObject<USphereComponent>(this));
            break;
        case ECustomTriggerShapes::CapsuleTrigger:
            UE_LOG(LogTemp,Log, TEXT("Do CAPSULEThings"));
            HazardTrigger = Cast<UCapsuleComponent>(NewObject<UCapsuleComponent>(this));
            break;
    }


But the DetailsPanel itself does not Refresh this time. You need to to reselect the Object in the worldOutliner to refresh the state of the Object.

It probably crashes because the addition of a component calls posteditchangeproperty? just a guess.

I have also meet the same problem before. the reason why editor crashed probably is that you use the same name to new a object(Trigger = NewObject(this, TEXT(“Trigger”)):wink: