【问题标题】:Unreal Engine crash with AddDynamic虚幻引擎使用 AddDynamic 崩溃
【发布时间】:2017-09-20 23:14:04
【问题描述】:

我在绑定 OnAudioFinished 委托时遇到问题。

搜索了一段时间,但还没有找到好的答案。我关注了这个answer

我的代码编译时完全没有任何错误,但是当我的项目加载时它会因以下错误而崩溃:

UE4Editor_!TBaseDynamicMulticastDelegate<FWeakObjectPtr,void>::__Internal_AddDynamic<UAudioController>() [d:\path\delegates\delegatesignatureimpl.inl:1140]
UE4Editor_Project!UAudioController::UAudioController() [d:\path\private\audiocontroller.cpp:17]
UE4Editor_Project!InternalConstructor<UAudioController>()

我所理解的是构造函数会破坏我的引擎,但我不知道为什么会这样。这是我负责此绑定的代码。

.h

static UAudioComponent* AudioComponent;

public:
    UAudioController();


void SoundFinished();

.cpp

UAudioController::UAudioController()
{
    AudioComponent->OnAudioFinished.AddDynamic(this, &UAudioController::SoundFinished);

}

void UAudioController::SoundFinished()
{
    GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Red, TEXT("Audio Finished trigger"));
}

【问题讨论】:

  • 您的调试器将成为此类问题的最佳朋友。也就是说,我的猜测是,当您调用 AddDynamic 时,AudioComponent 尚未初始化。
  • 还要确保你的SoundFinished函数是UFUNCTION。
  • 请检查我编辑的答案。使用NewObject&lt;...&gt;()(正如您在下面的评论中提到的)绝对不是使用组件的正确方法。

标签: c++ constructor delegates unreal-engine4


【解决方案1】:

在 UE 中,属性在构造函数运行期间未正确初始化。它们是在调用 PostInitProperties 时(从 CDO 加载之后)。

您还应该问自己是否需要静态类。如果您需要 Singleton,可以将其存储在 GameInstance 中。它更安全,尤其是在 UE 环境中(你不能有静态 UPROPERTY() 字段等)

我相信在BeginPlay 期间绑定这个事件就足够了。删除是一种很好的做法,尽管在使用 Dynamic 绑定时不是必需的

// AudioController.h
virtual void BeginPlay() override;
virtual void EndPlay(const EEndPlayReason::Type EndPlayReasonType) override;

// AudioController.cpp
void UAudioController::BeginPlay() {
    Super::BeginPlay();
     AudioComponent->OnAudioFinished.AddDynamic(this, &UAudioController::SoundFinished);
}

void UAudioController::EndPlay(const EEndPlayReason::Type EndPlayReasonType) {
     AudioComponent->OnAudioFinished.RemoveDynamic(this, &UAudioController::SoundFinished);  
    Super::EndPlay(EndPlayReasonType);
}

编辑:因为你用 Controller 后缀命名你的类,我想这将是这个角色在关卡中的一次出现。所以你不需要静态指针(它可能会被破坏 - 再次,这是 UE 的专长),只需将 AudioComponent 作为控制器中的 public 成员:

// AudioController.h
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "My Audio Conmponent", meta = (AllowPrivateAccess = "true"))
    UAudioComponent* AudioComponent;

然后在构造函数中正确初始化:

UAudioController::UAudioController()
    : Super()
{
    AudioComponent = CreateDefaultSubobject<UAudioComponent>(TEXT("MyAudioComponent"));
}

UAudioController::UAudioController(const class FObjectInitializer& ObjectInitializer)
    : Super(ObjectInitializer)
{
    AudioComponent = CreateDefaultSubobject<UAudioComponent>(TEXT("MyAudioComponent"));
}

您的组件将被正确创建,绑定的函数将按预期执行。

另外,正如@JKovalsky 提到的,在使用动态 委托时,您的SoundFinished 方法必须用UFUNCTION() 宏进行标记。

【讨论】:

  • 我现在要对其进行测试,并给您反馈它的运行情况! :3 谢谢你这么大的反应。
  • 您提供的虚拟功能似乎不起作用。它们产生以下错误:class "UObject" has no member "BeginPlay" member function with 'override' does not override a base class member. 我正在寻找导致我包含 Actor.h 的解决方案,但它没有任何改变。没有它们,我编译没有问题,但是即使在构造函数中绑定,我仍然没有让这个 SoundFinished 触发。我的基类继承了 UObject
  • @AdrianRozlach UAudioController 的基础对象是什么?我以为是AActor,但好像是直接继承自UObject...如果是后者,有什么原因吗?
  • 没有。我对 UE4 很陌生,所以我选择了 UObject 进行测试。我已经将基础对象更改为 AActor 并且一切都编译得很好。我的 SoundFinished 也是 UFUNCTION() ,但仍然无法从我的函数中获取输出。声音完成后,什么也没有发生。我正在从另一个这样的函数播放它:UAudioComponent* AAudioController::SoundPlaying() { if (AudioComponent) { AudioComponent-&gt;Play(); return AudioComponent; } return 0; } 我在蓝图中得到打印,它已经用节点 isPlaying 完成,但我的 SoundFinished 没有打印
  • @AdrianRozlach 你熟悉事件和代表的概念吗?这里完全一样。你调用函数命名让我们说PlayMySound。该实现类似于AudioComponent-&gt;PlaySound(...),它立即将执行返回给该函数的调用者。当 AudioComponent 具有 SoundFinished 事件绑定时,在当前播放 cue 结束后,它会异步调用该委托的处理程序,在您的情况下为 void UAudioController::SoundFinished()。声音完成后你需要做的所有事情,你都在那里定义。
猜你喜欢
  • 2020-07-24
  • 1970-01-01
  • 2017-09-10
  • 2019-06-18
  • 1970-01-01
  • 2020-03-24
  • 2020-06-02
  • 1970-01-01
  • 2017-07-18
相关资源
最近更新 更多