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.