UE4 UserWidget Button 与 PlayerController 中的生成 actor 绑定
UE4 UserWidget Button bind with spawning actor in PlayerController
大家好我的程序员们-
我需要帮助解决这个问题
我有 MyPlayerController.c (.h)、MyGameHUD.c (.h) 和 MainUIWidget.c (.h)
MyGameHUD 是自定义的 class MyGameMode 中 MyPlayerController 的默认 HUD
MainUIWidget 是自定义的 class - 带有几个按钮的简单小部件
MyPlayerController 是自定义的 class
我想在按下 MainUIWidget 上的按钮时在 MyPlayerController 上生成 actor
直到现在我只收到访问冲突,因为似乎无法从 MainUIWidget 访问 UWorld
MainUIWidget.h
UCLASS()
class MY_API UMainUIWidge: public UUserWidget
{
GENERATED_BODY()
void ConstructBuilding(FString BuildingName);
MyPlayerController* PlayerControllerPtr;
UPROPERTY(EditDefaultsOnly, BluePrintReadWrite, Category = "Buttons", meta = (BindWidget))
class UButton* Button_1;
};
MainUIWidget.cpp
UMainUIWidget::UMainUIWidget(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer)
{
PlayerControllerPtr = Cast<AMyPlayerController>(GetOwningPlayer());
}
void UMainUIWidget::NativeConstruct()
{
Super::NativeConstruct();
// Bind delegates here
Button_1->OnClicked.AddDynamic(this, &UMainUIWidget::SendSignalBuildBuildingBP_Button1);
}
void UMainUIWidget::ConstructBuilding(FString BuildingName)
{
PlayerControllerPtr->ConstructBuilding(FString BuildingName);
}
void UMainUIWidget::SendSignalBuildBuildingBP_Button1()
{
GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Yellow, TEXT("Signal to build!"));
ConstructBuilding(FString("SmallHouse"));
}
MyGameHUD.h
class MY_API AMyGameHUD : public AHUD
{
GENERATED_BODY()
public:
AMyGameHUD ();
virtual void Tick(float DeltaSeconds) override;
virtual void BeginPlay() override;
virtual void DrawHUD() override;
void DrawUI();
UPROPERTY(EditAnywhere, BluePrintReadWrite, Category = "Widgets")
TSubclassOf<UUserWidget> UMainUIWidgetClass;
private:
UMainUIWidget* UMainUIWidget;
MyGameHUD.cpp
MyGameHUD::MyGameHUD()
{
PlayerControllerPtr = Cast<AMyPlayerController>(this->GetOwningPlayerController());
}
void MyGameHUD::BeginPlay()
{
Super::BeginPlay();
DrawUI();
}
void MyGameHUD::DrawUI()
{
if (UMainUIWidgetClass)
{
UMainUIWidget= CreateWidget<UMainUIWidget>(GetWorld(), UMainUIWidgetClass);
if (UMainUIWidget)
{
UMainUIWidget->AddToViewport();
}
}
}
void MyGameHUD::Tick(float DeltaSeconds)
{
Super::Tick(DeltaSeconds);
}
void MyGameHUD::DrawHUD()
{
Super::DrawHUD();
}
预期行为是:
- 单击小部件中的按钮 1
- 从 MyPlayerController 将 Actor 生成到世界中
现在的行为:
- 单击小部件中的按钮 1
- MyPlayerController中的触发函数
- MyPlayerController->GetWorld() 为空,SpawnActor 将因读取访问冲突而崩溃。
有什么想法吗?
编辑 -> 添加了 MyPlayerController
MyPlayerController.cpp
AMyPlayerController::AMyPlayerController()
{
DefaultMouseCursor = EMouseCursor::Crosshairs;
bShowMouseCursor = true;
bEnableClickEvents = true;
bEnableMouseOverEvents = true;
// pre-load class for SpawnActor
static ConstructorHelpers::FClassFinder<BuildingClass> SmallHouseBPClass(TEXT("Reference/To/Blueprint/Class/BP.BP_C"));
SmallHouseClass = SmallHouseBPClass.Class;
}
void AMyPlayerController::ConstructBuilding(FString BuildingName)
{
if (BuildingName.Compare("SmallHouse") == 0)
{
GetWorld()->SpawnActor<BuildingClass>(SmallHouseClass);
}
}
AMyPlayerController.h
UCLASS()
class AMyPlayerController : public APlayerController
{
GENERATED_BODY()
public:
AMyPlayerController ();
void ConstructBuilding(FString BuildingName);
UPROPERTY(EditAnywhere, BluePrintReadOnly, Category = "BuildingClasses")
TSubclassOf<class BuildingClass> SmallHouseClass;
请提供确切的崩溃详细信息。
对我来说,这看起来像是您尝试使用 GetOwningPlayer()
缓存在您的 Widget 的 PlayerControllerPtr
中,但是在 MyGameHUD::DrawUI()
中创建 Widget 时,您没有向 Widget 指定什么它的拥有者是。
请在将 Widget 添加到 Viewport 时在 Widget 上调用 SetOwningPlayer(PlayerControllerPtr)
,以便它知道哪个 Player 拥有它。这将导致 GetOwningPlayer()
函数实际上 return 一个值。
我怀疑你的崩溃实际上是在这个函数内部发生的
void UMainUIWidget::ConstructBuilding(FString BuildingName)
{
PlayerControllerPtr->ConstructBuilding(FString BuildingName);
}
在使用指针之前,您应该始终检查它们的有效性,当它没有按预期通过时,可以选择进行某种记录。
void UMainUIWidget::ConstructBuilding(FString BuildingName)
{
if(PlayerControllerPtr)
{
PlayerControllerPtr->ConstructBuilding(FString BuildingName);
}
}
GetWorld()
在 PlayerController 内部调用时始终有效,因为它是一个 AActor,没有世界就无法存在。
感谢大家的回答。
问题解决者:
移动
PlayerControllerPtr = Cast<AMyPlayerController>(this->GetOwningPlayer());
从小部件的构造函数到小部件的 BeginPlay() 事件。
大家好我的程序员们- 我需要帮助解决这个问题
我有 MyPlayerController.c (.h)、MyGameHUD.c (.h) 和 MainUIWidget.c (.h)
MyGameHUD 是自定义的 class MyGameMode 中 MyPlayerController 的默认 HUD MainUIWidget 是自定义的 class - 带有几个按钮的简单小部件 MyPlayerController 是自定义的 class
我想在按下 MainUIWidget 上的按钮时在 MyPlayerController 上生成 actor
直到现在我只收到访问冲突,因为似乎无法从 MainUIWidget 访问 UWorld
MainUIWidget.h
UCLASS()
class MY_API UMainUIWidge: public UUserWidget
{
GENERATED_BODY()
void ConstructBuilding(FString BuildingName);
MyPlayerController* PlayerControllerPtr;
UPROPERTY(EditDefaultsOnly, BluePrintReadWrite, Category = "Buttons", meta = (BindWidget))
class UButton* Button_1;
};
MainUIWidget.cpp
UMainUIWidget::UMainUIWidget(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer)
{
PlayerControllerPtr = Cast<AMyPlayerController>(GetOwningPlayer());
}
void UMainUIWidget::NativeConstruct()
{
Super::NativeConstruct();
// Bind delegates here
Button_1->OnClicked.AddDynamic(this, &UMainUIWidget::SendSignalBuildBuildingBP_Button1);
}
void UMainUIWidget::ConstructBuilding(FString BuildingName)
{
PlayerControllerPtr->ConstructBuilding(FString BuildingName);
}
void UMainUIWidget::SendSignalBuildBuildingBP_Button1()
{
GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Yellow, TEXT("Signal to build!"));
ConstructBuilding(FString("SmallHouse"));
}
MyGameHUD.h
class MY_API AMyGameHUD : public AHUD
{
GENERATED_BODY()
public:
AMyGameHUD ();
virtual void Tick(float DeltaSeconds) override;
virtual void BeginPlay() override;
virtual void DrawHUD() override;
void DrawUI();
UPROPERTY(EditAnywhere, BluePrintReadWrite, Category = "Widgets")
TSubclassOf<UUserWidget> UMainUIWidgetClass;
private:
UMainUIWidget* UMainUIWidget;
MyGameHUD.cpp
MyGameHUD::MyGameHUD()
{
PlayerControllerPtr = Cast<AMyPlayerController>(this->GetOwningPlayerController());
}
void MyGameHUD::BeginPlay()
{
Super::BeginPlay();
DrawUI();
}
void MyGameHUD::DrawUI()
{
if (UMainUIWidgetClass)
{
UMainUIWidget= CreateWidget<UMainUIWidget>(GetWorld(), UMainUIWidgetClass);
if (UMainUIWidget)
{
UMainUIWidget->AddToViewport();
}
}
}
void MyGameHUD::Tick(float DeltaSeconds)
{
Super::Tick(DeltaSeconds);
}
void MyGameHUD::DrawHUD()
{
Super::DrawHUD();
}
预期行为是:
- 单击小部件中的按钮 1
- 从 MyPlayerController 将 Actor 生成到世界中
现在的行为:
- 单击小部件中的按钮 1
- MyPlayerController中的触发函数
- MyPlayerController->GetWorld() 为空,SpawnActor 将因读取访问冲突而崩溃。
有什么想法吗?
编辑 -> 添加了 MyPlayerController
MyPlayerController.cpp
AMyPlayerController::AMyPlayerController()
{
DefaultMouseCursor = EMouseCursor::Crosshairs;
bShowMouseCursor = true;
bEnableClickEvents = true;
bEnableMouseOverEvents = true;
// pre-load class for SpawnActor
static ConstructorHelpers::FClassFinder<BuildingClass> SmallHouseBPClass(TEXT("Reference/To/Blueprint/Class/BP.BP_C"));
SmallHouseClass = SmallHouseBPClass.Class;
}
void AMyPlayerController::ConstructBuilding(FString BuildingName)
{
if (BuildingName.Compare("SmallHouse") == 0)
{
GetWorld()->SpawnActor<BuildingClass>(SmallHouseClass);
}
}
AMyPlayerController.h
UCLASS()
class AMyPlayerController : public APlayerController
{
GENERATED_BODY()
public:
AMyPlayerController ();
void ConstructBuilding(FString BuildingName);
UPROPERTY(EditAnywhere, BluePrintReadOnly, Category = "BuildingClasses")
TSubclassOf<class BuildingClass> SmallHouseClass;
请提供确切的崩溃详细信息。
对我来说,这看起来像是您尝试使用 GetOwningPlayer()
缓存在您的 Widget 的 PlayerControllerPtr
中,但是在 MyGameHUD::DrawUI()
中创建 Widget 时,您没有向 Widget 指定什么它的拥有者是。
请在将 Widget 添加到 Viewport 时在 Widget 上调用 SetOwningPlayer(PlayerControllerPtr)
,以便它知道哪个 Player 拥有它。这将导致 GetOwningPlayer()
函数实际上 return 一个值。
我怀疑你的崩溃实际上是在这个函数内部发生的
void UMainUIWidget::ConstructBuilding(FString BuildingName)
{
PlayerControllerPtr->ConstructBuilding(FString BuildingName);
}
在使用指针之前,您应该始终检查它们的有效性,当它没有按预期通过时,可以选择进行某种记录。
void UMainUIWidget::ConstructBuilding(FString BuildingName)
{
if(PlayerControllerPtr)
{
PlayerControllerPtr->ConstructBuilding(FString BuildingName);
}
}
GetWorld()
在 PlayerController 内部调用时始终有效,因为它是一个 AActor,没有世界就无法存在。
感谢大家的回答。
问题解决者:
移动
PlayerControllerPtr = Cast<AMyPlayerController>(this->GetOwningPlayer());
从小部件的构造函数到小部件的 BeginPlay() 事件。