Can't connect Character with Widget

Hi, I’m trying to make the HUD show my character’s HP. Since the PlayerController has both assigned to it, my idea is to declare a Widget in the Character, and have the Controller assign its Widget to said Character, and then the Character updates the Widget with its HP in every tick. After a lot of tinkering and research I managed to make the whole thing compile, but the moment I hit play, Unreal crashes. Any clues? I’ll post the codes of all cpps and hs involved. This is a lot of code, I include it here in case you want to see any detail, but you should just focus on “widg”, “mainCharacter” “hitPoints”, “life”, “menu”, “widgetMenu”. Also I removed some spanish or useless comments so if you find a syntax error it’s most likely just that.

Custom PlayerController.h

  #pragma once

#include "Engine.h"
#include "MyCharacterPlayer.h" //esto lo revolee a ver que pasaba y no funca
#include "OurUserWidget.h" //ahora ambos no hacen nada
#include "GameFramework/PlayerController.h"
#include "OurPlayerController.generated.h"

// AMyCharacterPlayer * mainCharacter;
// UOurUserWidget * menu;

/**
 * 
 */
UCLASS()
class PROGMOTPARCIAL1_API AOurPlayerController : public APlayerController
{
	GENERATED_BODY()
	
public:
	UPROPERTY(EditAnywhere, BlueprintReadWrite)
		TSubclassOf<class UUserWidget> widgetMenu;

	UPROPERTY(EditAnywhere, BlueprintReadWrite)
		TSubclassOf<class ACharacter> characterBase;

	//UPROPERTY(EditAnywhere, BlueprintReadWrite)
		AMyCharacterPlayer * mainCharacter;

		UOurUserWidget * menu;

	virtual void BeginPlay() override;
	
	
};

custom PlayerController. cpp

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


void AOurPlayerController::BeginPlay()
{
	Super::BeginPlay();
	if (widgetMenu)
	{

		menu = CreateWidget<UOurUserWidget>(this, widgetMenu);
		if (menu)
		{
			menu->AddToViewport();
	    		//stuff used to happen here	
		}

		if (characterBase)
		{
			UE_LOG(LogTemp, Warning, TEXT("Hay Character Base"));
			mainCharacter = Cast<AMyCharacterPlayer>(characterBase); 
			if (menu) mainCharacter->widg = menu;
		}
		bShowMouseCursor = true;
	}
}

custom CharacterPlayer.h

#pragma once

#include "Engine.h"
#include "MyActorBullet.h"
#include "GameFramework/Character.h"
#include "MyCharacterPlayer.generated.h"

class UOurUserWidget;

UCLASS()
class PROGMOTPARCIAL1_API AMyCharacterPlayer : public ACharacter
{
	GENERATED_BODY()

public:
	AMyCharacterPlayer();

protected:
	virtual void BeginPlay() override;

public:	
	virtual void Tick(float DeltaTime) override;

	virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;

	void MoveHorizontal(float moveH);

	void MoveVertical(float moveV);

	void Shoot();

	void Death();

	UPROPERTY(EditAnywhere)
	float speed;
	UPROPERTY(EditAnywhere)
	float life;
	UPROPERTY(EditAnywhere)
	TSubclassOf<class AMyActorBullet> bullet;
	UOurUserWidget * widg;
	
};

custom Character.cpp

#include "MyCharacterPlayer.h"
#include "OurUserWidget.h"


// Sets default values
AMyCharacterPlayer::AMyCharacterPlayer()
{
 	// Set this character to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

}

// Called when the game starts or when spawned
void AMyCharacterPlayer::BeginPlay()
{
	Super::BeginPlay();
	
}

// Called every frame
void AMyCharacterPlayer::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);
	if (widg) //UE_LOG(LogTemp, Warning, TEXT("character widget"));  //
	widg->hitPoints = life;

}

// Called to bind functionality to input
void AMyCharacterPlayer::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	Super::SetupPlayerInputComponent(PlayerInputComponent);

	PlayerInputComponent->BindAxis("Horizontal", this, &AMyCharacterPlayer::MoveHorizontal);
	PlayerInputComponent->BindAxis("Vertical", this, &AMyCharacterPlayer::MoveVertical);
	PlayerInputComponent->BindAxis("MouseX", this, &AMyCharacterPlayer::AddControllerYawInput);
	PlayerInputComponent->BindAxis("MouseY", this, &AMyCharacterPlayer::AddControllerPitchInput);

	PlayerInputComponent->BindAction("Shoot", EInputEvent::IE_Pressed, this, &AMyCharacterPlayer::Shoot);
}

void AMyCharacterPlayer::MoveHorizontal(float moveH)
{
	FRotator rotation = Controller->GetControlRotation();
	FVector direction = FRotationMatrix(rotation).GetScaledAxis(EAxis::Y);
	AddMovementInput(direction, moveH);
}

void AMyCharacterPlayer::MoveVertical(float moveV)
{
	FRotator rotation = Controller->GetControlRotation();
	FVector direction = FRotationMatrix(rotation).GetScaledAxis(EAxis::X);
	AddMovementInput(direction, moveV);
}

void AMyCharacterPlayer::Shoot()
{
	if (bullet)
	{
		UWorld * world = GetWorld();
		if (world)
		{
			FActorSpawnParameters params;
			FVector location = GetActorLocation() + GetActorForwardVector() * 50;
			FRotator rotator = GetActorRotation();
			world->SpawnActor<AMyActorBullet>(bullet, location, rotator, params);
		}
	}
}

void AMyCharacterPlayer::Death()
{
	life = life - 1;
	if (life <= 0) 
	{
		UE_LOG(LogTemp, Warning, TEXT("I died"));
		//Destroy();
	}
}

custom widget.h

#pragma once

#include "Engine.h"
#include "Blueprint/UserWidget.h"
#include "OurUserWidget.generated.h"

/**
 * 
 */
UCLASS()
class PROGMOTPARCIAL1_API UOurUserWidget : public UUserWidget
{
	GENERATED_BODY()
	
public:
	UPROPERTY(EditAnywhere, BlueprintReadWrite)
		FString myText;

	UFUNCTION(BlueprintCallable)
		void ClickButtonForLoadScene();
	virtual void NativeTick(const FGeometry& MyGeometry, float InDeltaTime) override;

	float hitPoints;

	FString currentLevel;

	FString nextLevel;
	
}

custom widget.cpp;

#include "OurUserWidget.h"


void UOurUserWidget::NativeTick(const FGeometry & MyGeometry, float InDeltaTime)
{
	//myText = FString::SanitizeFloat(GetWorld()->TimeSeconds);
	myText = FString::SanitizeFloat(hitPoints);
}

void UOurUserWidget::ClickButtonForLoadScene()
{
	currentLevel = GetWorld()->GetMapName();
	if (currentLevel == "TitleScreen") nextLevel = "OurLevel01";
	else if (currentLevel == "OurLevel01") nextLevel = "VictoryScreen"; //Esto es de prueba, victoria no cambia por boton
	else if (currentLevel == "VictoryScreen") nextLevel = "TitleScreen"; 
	FName convertedLevel = FName(*nextLevel);
	UGameplayStatics::OpenLevel(GetWorld(), convertedLevel);
}

Hope this is a clear display of my issue, and that you may help me. Thanks in advance.

Hello KTVX,

The UWidgetComponent will handle most of this for you. Here is a tutorial properly explaining how to use this component. Widget Components in Unreal Engine | Unreal Engine 5.1 Documentation

Thanks,