[UE4奇怪错误合集-01] UE4 蓝图BluePrint崩溃 原因分析

UE4 蓝图BluePrint崩溃 原因分析

先上图:

 

 

分析:

确实只给你个崩溃弹窗并不能提供有价值的信息,考虑到此蓝图的父类是 继承自UserWidget的自定义的一个子类。所以问题可能出现在这个类中。

这个类中我们重写了UserWidget的 Initialize()生命周期函数。而且在里面使用了

     RootCanvas = Cast<UCanvasPanel>(GetRootWidget());
  RootCanvas->SetVisibility(ESlateVisibility::SelfHitTestInvisible);

问题就出现在这里,RootCanvas获取到实际上是一个Null。

我们看 GetRootWidget() 定义

 if ( WidgetTree )
  {
  return WidgetTree->RootWidget;
  }
 return nullptr;

我们可以在UserWidget的Initialize()中找到WidgetTree的有着代码

 if ( WidgetTree == nullptr )
 {
     WidgetTree = NewObject<UWidgetTree>(this, TEXT("WidgetTree"), RF_Transient);
 }

所以我们只要在重写的 Initialize() 中先调用 Super::Initialize(),WidgetTree就已经存在了,问题在于WidgetTree->RootWidget;

Widget的根组件以及根组件的子组件也好,总是在调用Initialize()之后添加上去的。

例如我们可以在 RebuildWidget() 函数中找到相应代码块

 // In the event this widget is replaced in memory by the blueprint compiler update
 // the widget won't be properly initialized, so we ensure it's initialized and initialize
 // it if it hasn't been.
 ...
 if ( !bInitialized )
 {
     Initialize();
 }
 ...
 // Add the first component to the root of the widget surface.
  TSharedRef<SWidget> UserRootWidget = WidgetTree->RootWidget ? WidgetTree->RootWidget->TakeWidget() : TSharedRef<SWidget>(SNew(SSpacer));
 ...

由于并没有进一步看蓝图编辑器blueprint compiler 的源码,猜测当点击蓝图类时,会调用对应父类的Initialize()函数,而此时的WidgetTree是没有任何根组件的,所以在Initialize()中使用GetRootWidget()获取根组件返回的必然是空指针,使用空指针便会导致崩溃。

解决方案1:

获取以及使用根组件肯定不能放在Initialize()中,RootWidget具体是在哪个生命周期中被赋值的我没有找,理论上只要在此函数之后的生命周期中就可以获取RootWidget了。所以我们可以重载NativeConstruct()函数,在其中使用GetRootWidget()。这样你的蓝图不至于打不开。(当然打开之后还是要给它一个CanvasPanel才可以不出错)

 void UDDFrameWidget::NativeConstruct()
 {
  RootCanvas = Cast<UCanvasPanel>(GetRootWidget());
  RootCanvas->SetVisibility(ESlateVisibility::SelfHitTestInvisible);
 }

解决方案2:

我是直接基于那个自建类创建的蓝图,所以自建类有逻辑错误就可能导致蓝图打不开。可以先基于内置的UserWidget类创建一个蓝图,它是肯定不会进不去的,再在其中更改父类为那个自建类,这样也是可以的。

总结:

使用了空指针。

蓝图也是程序,对蓝图的任何操作包括打开蓝图都会有相应的代码执行,就比如说它可能会执行父类的构造函数,Initialize函数等等,如果它的父类是自定义的话,出错就极有可能是在这些代码中,所以并不是只有点击开始游戏才有可能执行到你自定义的代码,对蓝图的一些操作会实时调用到你的代码。找错的时候要注意这一点。

posted @ 2020-04-15 21:07  JFor  阅读(3271)  评论(0编辑  收藏  举报