Changing a Component in a Parent Object

The Idea

If we derive a C++ class from an existing Unreal class, and that existing class contains components, we can extend (subclass) those components without changing the source code of the base class.

An Example

The ACharacter class contains a number of different components, specifically these:

offset

Say for example we want to replace the UCharacterMovementComponent with an extended version - the UMyNewCharacterMovementComponent which we have created and which is derived from UCharacterMovementComponent.

We want to change from this:

classDiagram ACharacter --> UCharacterMovementComponent

to this:

classDiagram ACharacter <|-- AMyCharacter ACharacter --> UMyNewCharacterMovementComponent UCharacterMovementComponent <|-- UMyNewCharacterMovementComponent

The UMyNewCharacterMovementComponent is shown below; for the purposes of this article we have added a constructor which changes the GravityScale member of UCharacterMovementComponent to 0.5 from its default value of 1.0.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "MyNewCharacterMovementComponent.generated.h"

UCLASS()
class TEST_API UMyNewCharacterMovementComponent : public UCharacterMovementComponent
{
	GENERATED_BODY()
public:
	UMyNewCharacterMovementComponent();
};

The implementation of the constructor is:

#include "MyNewCharacterMovementComponent.h"
UMyNewCharacterMovementComponent::UMyNewCharacterMovementComponent()
{
	GravityScale = 0.5f;
}

If we create a C++ class called AMyCharacter derived from ACharacter the code looks like this:

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "MyCharacter.generated.h"

UCLASS()
class TEST_API AMyCharacter : public ACharacter
{
	GENERATED_BODY()

public:
	// Sets default values for this character's properties
	AMyCharacter();

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;

public:	
	// Called every frame
	virtual void Tick(float DeltaTime) override;

	// Called to bind functionality to input
	virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
};

What we want to do is replace the UCharacterMovementComponent created in the ACharacter base class with our new UMyNewCharacterMovementComponent. To do this we add a FObjectInitializer& parameter to the class constructor in MyCharacter.h:

AMyCharacter(const FObjectInitializer& OI);

and in MyCharacter.cpp we change the constructor to this:

AMyCharacter::AMyCharacter(const FObjectInitializer& OI)
	: Super( OI.SetDefaultSubobjectClass<UMyNewCharacterMovementComponent>(ACharacter::CharacterMovementComponentName))
{
	PrimaryActorTick.bCanEverTick = true;
}

The call to Super(OI.SetDefaultSubobjectClass) is what changes the component associated with the ACharacter::CharacterMovementComponentName name from the UCharacterMovementComponent to our UMyNewCharacterMovementComponent so that when the AMyCharacter object is created it now has a UMyNewCharacterMovementComponent component.

If you drop a MyCharacter actor into the world map an look at its components we can see that:

  • the Character Movement component is now a UMyNewCharacterMovementComponent object
  • the gravity scale property has a value of 0.5, showing our component constructor was executed:

Note that you can only change a component to one which is derived from the original component. If you try to change it to something unrelated the engine will log a message like this:

Error: Class /Script/Test.Unrelated is not a legal override for component CharMoveComp because it does not derive 
from Class /Script/Engine.CharacterMovementComponent.  Using Class /Script/Engine.CharacterMovementComponent to construct
component.