Need advice on code structure

Hi! Coming from C# Unity, I am still scraching my head in search for best practicies. Here is what I am struggling with now:

Inside my custom controller, I reference the UMG buttons:


startGameButton = (UButton*)MyMainMenu->GetWidgetFromName(TEXT("BStartGame"));
startGameButton->OnClicked.AddDynamic(this, &AMainMenuController::BStartGame_Click);

Now, if that was C# Unity, instead of swarming my character contrtoller class with many BStartGame_Click, BExitGame_Click and e.t.c functions, I would have created seperate class (component) ‘MenuButtonHandler’, attach it to the buttons, and inside that class, I would handle OnClick, OnTick, OnMouseEnter and e.t.c. for every button;

Here I have ‘UButton’ class - is there some C++ proper way to extend it in such a way I would do it in C#? Should I just wrap UButton is some super-class, and assign my Ubutton Widget as reference in there, and handle events from inside? Or there is some better way? I also want it to have animations. Maybe the best way here is to create some new widget ‘animated button’, based on UBUtton, and use it inside UMG Editor?

P.S. There is no mouse_over, mouse_out for buttons, only isHovering - which means - I should check isHovering check inside OnTick function every frame? But UButton does not have onTick implementation too

There is no reason not to take the same approach. You can create a new ActorComponent (a component without a transform, i.e. doesn’t exist in world space, as opposed to a SceneComponent) a plug your functionality in there, then just attach that component to your controller either via code or Blueprint (Take a look at Character.h and how it declares its Capsule Component, Mesh Component and CharacterMovementComponent).

Although, I haven’t ran into a case where I needed to do my button handling inside of a controller. Can you describe your context a bit more, you might be going the wrong route.

That being said, if you’re looking for best practices let me give you some additional advice (coming from Unity myself some time ago) - you DO NOT want to use C-style casts. Instead of doing (UButton*), either do static_cast<UButton*>(YourObject) (This one is the fastest, because it doesn’t do any checks to make sure your object is cast properly, can lead to some very nasty bugs if the object you’re passing in is not of the cast type), or Cast<UButton>(YourObject) (Note the lack of * in the template).

Furthermore, if you want to match Epic’s coding style (I recommend this as it will make understanding engine code easier, all of your variables are CamelCase, not pascalCase and functions only seldom use _ in their names.

You can find a ton of info here: Coding Standard | Unreal Engine Documentation

Thank you! Creating ActorComponent sounds like a proper way, but I had no idea how to hook up my events into it, so I went other route atm.

I want to somehow add mouseOver/mouseOut animation for my buttons, and OnClick event handler, but I want to have generic, reusable component, which will identify button by name and handle it then. So I decided to expand UBUtton class, create my new AnimatedButtons inside UMG, and redirect all their events to my fresh class.


// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "Components/Button.h"
#include "AnimatedButton.generated.h"

/**
 * 
 */
UCLASS()
class UNREALFANTASY_API UAnimatedButton : public UButton
{
	GENERATED_BODY()
	

public:
	
	UFUNCTION(BlueprintCallable, Category = "Buttons") 
	**void On_Click();**

};

Then I added my custom user Widget:


// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "Blueprint/UserWidget.h"
#include "AnimatedButton.h"

#include "WMainMenuUI.generated.h"


/**
 * 
 */
UCLASS()
class UNREALFANTASY_API UWMainMenuUI : public UUserWidget
{
	GENERATED_BODY()
	
public:



	virtual void NativeConstruct() override;
	virtual void NativeTick(const FGeometry & MyGeometry, float InDeltaTime) override;

	**UAnimatedButton* startGameButton;**
	
};

And now I want for every AnimatedButton I created inside UMG, to hook it up to my custom expanded class event, like:


void UWMainMenuUI::NativeConstruct()
{
	Super::NativeConstruct();

	startGameButton = (UAnimatedButton*)this->GetWidgetFromName(TEXT("BStartGame"));
	startGameButton->OnClicked.AddDynamic(this, **startGameButton->On_Click**);

	UE_LOG(DefaultLogCat, Warning, TEXT("Custom Main Menu UI Widget Reporting in!"));

}

But, I fail at this point:


startGameButton->OnClicked.AddDynamic(this, startGameButton->On_Click);

Function here expects reference, and I have no idea, what to do next.

I’ll make sure to stick to Unreal coding standards next time, and name variables/functions propelry, also I have taken a note on your casting advice.

Try this:


startGameButton->OnClicked.AddDynamic(startGameButton, &UAnimatedButton::On_Click);

But this is kinda hackish, because you can do that inside the UAnimatedButton, without any widgets around

Hmmm, but UButton does not have BeginPlay, and its Construct is not marked for override. I wanted to do it inside my UAnimatedButton class firstly, but did not find how to plug into initialization event.
PostInitProperties, PosLoad overrides simply crash the Engine on level load

Thank you, your function works! I forgot to change ‘this’ into ‘startGameButton’, now it all makes sense.

EDIT: Solved! I was able to subscribe to OnWidgetRebuilt