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"

Calling a method from Pawn inside of MovementComponent

Hello. I'm trying to call a function from my Pawn inside the Pawn's attached MovementComponent. Here's a simplified version of what I'm trying to do:

MyPawn.h

 #pragma once
 
 #include "CoreMinimal.h"
 #include "GameFramework/Pawn.h"
 #include "MyPawn.generated.h"
 
 class GAME_API AMyPawn : public APawn
 {
     GENERATED_BODY()
 
 public:
 
     float Get_MovementInputForward() const;
 
 protected:
 
     float MoveInputForward;
     void AddMoveForwardInput(float AxisValue);


Pawn.cpp

 #include "MyGame.h"
 #include "MyPawn.h"
 #include "MyPawnMovementComponent.h"
 
 AMyPawn::AMyPawn()
 {
     // Create an instance of our movement component, and tell it to update the root.
     OurMovementComponent = CreateDefaultSubobject<UMyPawnMovementComponent>(TEXT("MyPawnMovementComponent"));
     OurMovementComponent->UpdatedComponent = RootComponent;
 }
 
 void AMyPawn::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
 {
     InputComponent->BindAxis("MoveForward", this, &AMyPawn::AddMoveForwardInput)
 }
 
 void AMyPawn::AddMoveForwardInput(float AxisValue)
 {
     MoveInputForward = FMath::Clamp<float>(AxisValue, -1.0f, 1.0f);
 }
 
 float AMyPawn::Get_MovementInputForward() const
 {
     return MoveInputForward;
 }
 

MyPawnMovementComponent.h

 #include "GameFramework/PawnMovementComponent.h"
 #include "MyPawn.h"
 #include "MyPawnMovementComponent.generated.h"
 
 UCLASS(ClassGroup = Movement, meta = (BlueprintSpawnableComponent), ShowCategories = (Velocity))
 class MyGame UMyPawnMovementComponent : public UPawnMovementComponent
 {
     GENERATED_UCLASS_BODY()
         //GENERATED_BODY()
 
 public:
     virtual void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction) override;
 
 protected:
     float PlayerMoveInputForward
     virtual void GetPlayerInput() const;
     virtual void PreformMove(float playerInputForward) const;

MyPawnMovementComponent.cpp

 #include "MyGame.h"
 #include "MyPawnMovementComponent.h"
 
 void UMyPawnMovementComponent::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction)
 {
     GetPlayerInput();
     PreformMove(PlayerInputForward);
 }
 
 void UMyPawnMovementComponent::GetPlayerInput() const
 {
     PlayerMoveInputForward = // <-- This is the point where I don't know what to do.
 }

Does anyone know how I can call Get_MovementInputForward() from AMyPawn inside of UMyPawnMovementComponent? I've tried googling around trying to find the proper way to do this. But every method I've found results in a compile error.

Any help would be much appreciated!

-Headstub

Product Version: UE 4.16
Tags:
more ▼

asked Jun 05 '17 at 08:14 PM in C++ Programming

avatar image

Headstub
15 2 5 7

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

1 answer: sort voted first

Get your pawn by using GetOwner(), which will return it as an AActor, and then Cast it into an AMyPawn. Then you can call your function.

 PlayerMoveInputForward = Cast<AMyPawn>(GetOwner())->Get_MovementInputForward();

However, this isn't a great way of structuring your actor. You're essentially requiring that your movement component only be placed on a MyPawn, or it'll break, which defeats the purpose of a component since it's no longer modular, use-anywhere code. But for a simple project it's fine.

more ▼

answered Jun 05 '17 at 10:08 PM

avatar image

Teiwaz
629 26 29 55

avatar image Headstub Jun 05 '17 at 10:54 PM

Okay, thank you. What would be a better way of giving the movement component inputs? I don't want to use the AddInputVector and ConsumeInputVector as I wish to have more control over how inputs are sent from the player to the movement component.

avatar image Teiwaz Jun 05 '17 at 11:12 PM

If your pawn is processing the input, what I'd do is expose various functions and values on the MovementComponent, and push the input data to the MovementComponent when needed. (Like, on the button up/down events, or sending current states on the Pawn's tick, as opposed to the movement component polling the pawn for data when it wants it, which is what you're doing now.)

That way, any actor can send data to your custom movement component. So later if you have an AI, the AI controller can send movement information to the component the same way the player does, rather than having the component always require that it be hooked up to the same actor type.

As a general philosophy, because actors know what components they include, but components can be placed on any actor type, you're better off assuming an actor has a component of a given type than requiring that a component belong to an actor of a given type. This makes your components more reusable, which is the whole point of components.

avatar image Headstub Jun 06 '17 at 09:02 AM

I see, thanks. I'm trying to implement that now but I've run into the following problem:

MyPawnMovementComponent.cpp

 void UMyPawnMovementComponent::SendControllerInputs(float movementInputForward)
     {
         PlayerInputForward = movementInputForward;
     }

MyPawn.cpp

 void AMyPawn::SendPlayerInputToMovement() const
     {
         OurMovementComponent->CallFunction->SendControllerInputs(MoveInputForward);
     }


With "OurMovementComponent->CallFunction->SendControllerInputs(MoveInputForward);" I get the error: "error C2227: left of '->SendControllerInputs' must point to class/struct/union/generic type"

I also tried doing "OurMovementComponent->CallFunction.SendControllerInputs(MoveInputForward);" but that just gives me this error instead: "error C2228: left of '.SendControllerInputs' must have class/struct/union"

I tried googling to find the solution, but all the answers just said to either use the -> or the . so I have no idea what I'm doing wrong.

Thanks for your help so far, I really appreciate it!

-Headstub

avatar image Teiwaz Jun 06 '17 at 02:45 PM

Get rid of "CallFunction," I don't know what that is. Just OurMovementComponent->SendControllerInputs(MoveInputForward);

In C++, there are two operators to access the members of an object: "->" and "."

"->" is used to access things in a pointer, whereas "." is used them to access members of a value.

So, if I have a variable UMovementComponent* OurMovementComponent I'd use OurMovementComponent->SendControllerInputs(MoveInputForward); But if I have something like FVector Location I'd use Location.X;

You may want to spend a bit of time with some basic C++ tutorials to learn some syntax before jumping too far into UE4 C++. C++ can be tricky enough without dealing with a huge code base and all the macro magic of UE4.

avatar image Headstub Jun 06 '17 at 03:51 PM

Yeah, true. I'm using SoloLearn's Learn C++ app to learn and I think I have yet to learn how to use the selection operators to access variables and functions between classes. Thank you for clearing up when to use the dot operator and the arrow operator. The app had a lesson on those, but I think your words made me understand them better.

Thanks so much for your help. The code works perfectly now. I would have spent hours on Google trying to figure this out myself.

One last question: is there any guarantee that SendControllerInputs in MyPawn.cpp will be executed before PreformMove in MyPawnMovementComponent.cpp? I don't want the game to execute last tick's inputs, but I'm guessing that MyPawn's Tick function will execute and finish before MyPawnMovementComponent's Tick function will be called since it's an attached component?

-Headstub

avatar image Teiwaz Jun 06 '17 at 04:38 PM

I don't think that's guaranteed, no.

However, in most cases, tick order won't be a problem. The point at which the tick occurs is essentially arbitrary - it makes no difference if input is read last in one tick and applied first in the next, or read first in a tick and applied later in that tick. The data's still there, and the time between it being input by the user and executed will be more or less the same.

If for some reason you need to guarantee tick order (usually when you have 3 or more actors all needing coordinated ticks, or if some object is clearing data, etc) there are functions on components and actors to add tick prerequisites, which will guarantee the specified component/actor ticks before they do. Note, however, that you need to specify the specific component you need to tick first, adding an actor as a tick prerequisite doesn't guarantee its components have also ticked first.

avatar image Headstub Jun 06 '17 at 08:53 PM

Okay, that makes sense. Thanks again for your help.

-Headstub

(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