Private members in the engine source

I’m looking at overriding some behaviours specifically on the CharacterMovementComponent, but I see in Character the CharacterMovement member is declared as private. This prevents all extensibility, which doesn’t make much sense to me.

In effect I’d like to use my own Movement component (extended from CharacterMovementComponent), and then override some behaviours. I can understand that the encapsulation principle dictates that it shouldn’t be possible for outside entities to change the internal state of this member, but surely it shouldn’t prevent the use of an extended version of the member class? I’m referring here to the fact that I extend both Character, and within its implementation I’d like to use the movement component I extended from CharacterMovementComponent.

The Character class’ movement was implemented against the “interface” of specifically CharacterMovementComponent, so using components derived from it would pose no issue (other than obvious bad usage) so what is the purpose of preventing this extensibility?

I would really appreciate an explanation regarding the logic behind making this member private (instead of protected). The same applies (to a lesser extent) to the collision component.

It’s very possible that my inexperience is at fault here and I’m missing something obvious, but I can’t understand why access is limited so severely in this case.

just fork from github master, make the change, submit a pull request, and use your own fork in the meantime. unreal with all its deps, is easy to recompile with just a couple commands (on linux). there is little stopping you from making small changes to the core engine like this.

Hi hartsantler,

Thanks very much for the response. I have in fact already made this change on my local repo, but I’d really like to know if anyone can provide any specific rationale behind this that I’m missing.

I’m going to keep this open for a while.

Thanks!

Thanks very much Benergy - I did see this approach as well (I think omnipresent Rama posted it somewhere) however, I don’t think this approach will work with passing in Blueprints.

Ideally I want my custom movement component which can then be Blueprinted and using a TSubclassOf member assign the class that must be used. An example of this is in GameModeBase’s “DefaultPawnClass”.

I think they made it private because there is need to make it protected. When you want to use your own movement component, simply do:

MyCharacter::MyCharacter(const FObjectInitializer& ObjectInitializer)
  : super(ObjectInitializer.SetDefaultSubobjectClass<MyMovementComponent>(CharacterMovementComponentName)
{
  // c'tor
}

You can do the same with a custom capsule component.

I see, but remember that TSubclassOf provides a UClass object which can be used for spawning pawns. But a member variable must be of real class and a UClass object wouldn’t be of any use.

Well, I’ve done the following after making “CharacterMovement” declared in “Character.h” protected:

PWNCharacter.h:

public:	
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Classes)
	TSubclassOf<UPWNCharacterMovementComponent> CharacterMovementComponentClass;

PWNCharacter.cpp:

// Sets default values
APWNCharacter::APWNCharacter()
{
    if (CharacterMovementComponentClass == nullptr)
		CharacterMovementComponentClass = UPWNCharacterMovementComponent::StaticClass();

	CharacterMovement = Cast<UCharacterMovementComponent>(CreateDefaultSubobject(TEXT("asdasd"), CharacterMovementComponentClass, UPWNCharacterMovementComponent::StaticClass(), false, false, false));
}

This compiles without issues, and I when I debug, it seems “CharacterMovement” is now indeed of class “UPWNCharacterMovementComponent”, however only during the constructor. I’m a bit confused as printing out the class name of “CharacterMovement” during BeginPlay shows it’s an instance of “UCharacterMovementComponent” again.

What kind of witchcraft is this?

Perhaps this has something to do with which constructor is overridden. Have you tried not overriding the no-parameter constructor, but the FObjectInitializer constructor? I can think of a scenario, in which first your no-parameter constructor is called, and then the FObjectInitializer constructor of the parent ACharacter which overrides your set CharacterMovement.

Ah ok - interesting. I’ll have a look.

In any case, I was overriding the parameterless constructor, but I think my whole plan is flawed as Blueprint values are only taken into account during OnConstruction (not sure if it’s available right before or right after though). So unless the object creation is done after the constructor has run, there’s really no way to implement this dynamic parameterisation.

I suppose the only other option is applying Blueprint values via an intermediate object, e.g. create a class “MyCharacterMovementValues”, create a blueprint with required values, then create a member of this type in my Character, and during OnConstruction apply those values to the MovementComponent (getting it via GetMovementComponent). Then to override behaviour, I’ll need to use the FObjectInitializer constructor override to use my custom MovementComponent class (whose effective settings I can expose via the intermediate blueprint).

Unfortunately this seems a bit brittle to me and will require duplicating members from the MovementComponent to this intermediate class, which would quite frankly be a terrible OOP transgression.

Oh well.

Ok, so finally to summarise:

I went ahead with the FObjectInitializer constructor approach. I don’t actually need to create a Blueprint of my movement component in order to expose its variables to designers. Adding a property with proper UPROPERTY() declarations takes care of this:

MyCharacterMovementComponent.h:

public:
	// Constructor
	UPWNCharacterMovementComponent();
	
	UPROPERTY(Category = "Character Movement: Walking", EditAnywhere, BlueprintReadWrite, meta = (ClampMin = "0", UIMin = "0"))
	float TestProp = 27.f;	

And then creating a Blueprint of my Character, this setting is exposed:

Pretty neat!