How I get a widget button to trigger a function from my player script?

Maybe this doesn’t work simply the way I’m thinking it should but I’m struggling to figure out a solution.

I have a function on my player character called Jumpping, so I’m trying to basically do this:

#include "AndroidHUD.h"
#include "MainPlayer.h"
#include "Components/Button.h"

void UAndroidHUD::NativeConstruct()
{
	if (JumpButton) {
		JumpButton->OnClicked.AddDynamic(this, &AMainPlayer::Jumpping());
	}
}

I’ve tried setting the object as the player controller but that didn’t work either.

Any guidance would be appreciated.

Try without “()” in the end of fucntion as below

&AMainPlayer::Jumpping
&AMainPlayer::Jumpping()

void UAndroidHUD::NativeConstruct()
{
	if (JumpButton) {
		JumpButton->OnClicked.AddDynamic(this, &AMainPlayer::Jumpping);
	}
}

Doesn’t work, it’s looking for a function and of course would want variables passed in if it required any. If you do it natively for example it’d still want the (). I did try it just in case since you asked but no dice.

Can you share your related .h and .cpp files

That literally is the full cpp file.

This is the h:

#pragma once

include “CoreMinimal.h”
include “Blueprint/UserWidget.h”
include “AndroidHUD.generated.h”

/**
*
*/
UCLASS()
class MYPROJECT_API UAndroidHUD : public UUserWidget
{
GENERATED_BODY()

protected:
UPROPERTY(BlueprintReadWrite, meta = (BindWidget))
class UButton* JumpButton;

virtual void NativeConstruct() override;

};

I don’t believe the MainPlayer file is necessary for the solution to this. Just asking how to call a function from another script on a button widget press in c++.

I figured out a way to do it but I’m not sure it’s ideal.

This is the cpp:


#include "AndroidHUD.h"
#include "MainPlayer.h"
#include "Components/Button.h"

void UAndroidHUD::NativeConstruct()
{
	if (JumpButton) {
		JumpButton->OnClicked.AddDynamic(this, &UAndroidHUD::JumpButOnClick);

	}
}

void UAndroidHUD::JumpButOnClick()
{

	AMainPlayer* mainPlayerScript = Cast<AMainPlayer>(playerChar);
	mainPlayerScript->Jumpping();

}

This is the header:


#pragma once

#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "AndroidHUD.generated.h"

/**
 * 
 */
UCLASS()
class MYPROJECT_API UAndroidHUD : public UUserWidget
{
	GENERATED_BODY()
	
protected:
	UPROPERTY(BlueprintReadWrite, meta = (BindWidget))
		class UButton* JumpButton;


	virtual void NativeConstruct() override;

	UFUNCTION()
		void JumpButOnClick();

public:
	UPROPERTY(EditAnywhere)
		APawn* playerChar;



};

This is the code at the begin play of my character script that grabs and sets the player object:

playerChar = GetWorld()->GetFirstPlayerController()->GetPawn();

AndroidHUD = CreateWidget<UAndroidHUD>(playerController, androidHUDClass);
AndroidHUD->AddToViewport();
AndroidHUD->playerChar = playerChar;

Sorry if that part is a big confusing, it’s a pretty large file but I’m sure ya’ll can understand I have a playerChar that’s grabbed and being passed to a variable of the same name to the widget script.

I’m going to leave this open though because I feel like this might not be a good/proper solution.

It seems we had two problems in the beginning.

  • Need to use function reference as &AMainPlayer::Jumpping
  • Need to use AMainPlayer instead of “this”.

You don’t need additional function and character reference.
You could use “JumpButOnClick” function as a reference in your workaround because “this” refers to UAndroidHUD class and it contains JumpButOnClick function.

If you want to use a function in AMainPlayer class. You need to get a reference and give that instead of “this”. You can get as below:

AMainPlayer* MyPlayer = Cast<AMainPlayer>(GetWorld()->GetFirstPlayerController()->GetPawn());

Final version should be like this. (I hope there is no typo but you get the idea anyway)

Widget header file:

#pragma once

#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "AndroidHUD.generated.h"

/**
 * 
 */
UCLASS()
class MYPROJECT_API UAndroidHUD : public UUserWidget
{
	GENERATED_BODY()
	
protected:
	UPROPERTY(BlueprintReadWrite, meta = (BindWidget))
		class UButton* JumpButton;


	virtual void NativeConstruct() override;

};

Widget cpp file:

#include "AndroidHUD.h"
#include "MainPlayer.h"
#include "Components/Button.h"

void UAndroidHUD::NativeConstruct()
	{
		AMainPlayer* MyPlayer = Cast<AMainPlayer>(GetWorld()->GetFirstPlayerController()->GetPawn());
		if (JumpButton) {
			JumpButton->OnClicked.AddDynamic(MyPlayer, &AMainPlayer::Jumpping);
		}
	}
1 Like

That makes sense and is cleaner. There is a problem with this method though. It doesn’t work when you need passed values.

Like say the function is Jumpping(float jumpHeight), for whatever reason it won’t accept that. Won’t work with or without a passed value set. Of course, none of the functions I’m trying to trigger off buttons need them but something to think about.

I appreciate your assistance and solution. Glad I didn’t mark mine as a solution. Was bouncing between the kitchen and the problem, delaying food and being hungry the whole time. Finally committed to cooking once I had something working but knew it couldn’t have been correct/best.

Like say the function is Jumpping(float jumpHeight), for whatever reason it won’t accept that.

The reason is OnClicked is a delegate defined in UButton class as below.
In Visual Studio or Rider you can right click to OnClicked then Go To Decleration or Usage to check yourself. I recommend doing for all delegates you want to use.
It means it is a delegate which takes no parameter in callback function.
And it makes sense because clicking a button does not give any value to user (float in your case)

DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnButtonClickedEvent);
...
...
...
...
/** Called when the button is clicked */
	UPROPERTY(BlueprintAssignable, Category="Button|Event")
	FOnButtonClickedEvent OnClicked;

In order to handle your current issue;

You can define JumpButtonClicked() function in your AMainPlayer class and bind this function to OnClicked instead of Jumpping() function.
Then you can call Jumpping inside JumpButtonClicked. For example

AMainPlayer::JumpButtonClicked()
{
	// Call Jumpping function here as you want.
	Jumpping(jumpHeight);
}

Extra note:
If delegate defined using “DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam” you can use a callback function which takes one parameter. Of course parameter type should be defined (like float) and delegate should pass a value to be used in callback function.

1 Like

That explains it. Delegates kept coming up when I was trying to figure this out but I didn’t dive into them. Felt like a step further than should be necessary. Figured the function method would work or of course I can just do it like you did in the main script and call that instead.

I appreciate your help and insight into the matter!

You are welcome! I glad that it helps you understand.

I think delegates are essential if you keep using C++.
My suggestion is to search on internet to understand. Then you can find some examples to create your own delegates and use in your project.
Good luck mate!

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.