x

Search in
Sort by:

Question Status:

Search help

  • Simple searches use one or more words. Separate the words with spaces (cat dog) to search cat,dog or both. Separate the words with plus signs (cat +dog) to search for items that may contain cat but must contain dog.
  • You can further refine your search on the search results page, where you can search by keywords, author, topic. These can be combined with each other. Examples
    • cat dog --matches anything with cat,dog or both
    • cat +dog --searches for cat +dog where dog is a mandatory term
    • cat -dog -- searches for cat excluding any result containing dog
    • [cats] —will restrict your search to results with topic named "cats"
    • [cats] [dogs] —will restrict your search to results with both topics, "cats", and "dogs"

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.

Product Version: UE 4.15
Tags:
more ▼

asked Apr 24 '17 at 11:56 AM in C++ Programming

avatar image

staticvoidlol
2.6k 95 41 111

avatar image staticvoidlol Apr 29 '17 at 10:10 AM

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:

![alt text][1]

Pretty neat! [1]: /storage/temp/136063-capture.png

capture.png (77.7 kB)
(comments are locked)
10|2000 characters needed characters left
Viewable by all users

2 answers: sort voted first

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.

more ▼

answered Apr 24 '17 at 04:28 PM

avatar image

Benergy
831 21 4 29

avatar image staticvoidlol Apr 24 '17 at 04:46 PM

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".

avatar image Benergy Apr 24 '17 at 05:01 PM

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.

avatar image staticvoidlol Apr 24 '17 at 08:34 PM

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.

avatar image staticvoidlol Apr 24 '17 at 08:38 PM

What kind of witchcraft is this?

alt text

alt text

1.png (51.9 kB)
2.png (60.6 kB)
avatar image Benergy Apr 25 '17 at 07:20 AM

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.

avatar image staticvoidlol Apr 25 '17 at 09:44 AM

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.

avatar image staticvoidlol Apr 25 '17 at 09:50 AM

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.

(comments are locked)
10|2000 characters needed characters left
Viewable by all users

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.

more ▼

answered Apr 24 '17 at 03:55 PM

avatar image

hartsantler
31 2 4 5

avatar image staticvoidlol Apr 24 '17 at 04:13 PM

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!

(comments are locked)
10|2000 characters needed characters left
Viewable by all users
Your answer
toggle preview:

Up to 5 attachments (including images) can be used with a maximum of 5.2 MB each and 5.2 MB total.

Follow this question

Once you sign in you will be able to subscribe for any updates here

Answers to this question