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:
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:
to this:
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.
Feedback
Please leave any feedback about this article here