很多时候我们是通过代码写游戏逻辑,当逻辑执行到某个状态时,能够通过事件的方式触发另外一段逻辑,而触发的这段逻辑希望在蓝图中实现,这时候就存在一个代码和蓝图事件连接和调用的问题。实现此功能很简单,有两种方式,一种是通过代码定义事件接口,实现逻辑完全放在蓝图中,代码中没有默认实现逻辑;另外一种是在代码中有默认实现逻辑,但在蓝图中可以重写。
针对第一种方式,可以直接参考最常用的Actor类中的BeginPlay事件逻辑的实现方式,现在把相应的部分代码显示如下:
/** Event when play begins for this actor. */
UFUNCTION(BlueprintImplementableEvent, meta=(DisplayName = "BeginPlay"))
void ReceiveBeginPlay();
/** Event when play begins for this actor. */
virtual void BeginPlay();
上面的ReceiveBeginPlay就是要在蓝图中实现的事件逻辑,该函数在代码中没有函数体,这里很关键的就是BlueprintImplementableEvent函数属性,它定义了该函数需要在蓝图中实现,并且是事件形式。
事件本身其实也是函数调用,那这个事件是怎么触发的呢?也就是ReceiveBeginPlay函数怎么被调用呢?相比你也猜到了,看下BeginPlay函数的实现就明白了,ReceiveBeginPlay是在BeginPlay函数中调用的,
void AActor::BeginPlay()
{
......
ReceiveBeginPlay();
......
}
这下就真相大白了,实现方式可以总结一下就是:代码中声明事件函数但没有函数体,将函数属性设置为BlueprintImplementableEvent,在代码中相应地方调用该函数,我们暂且叫蓝图事件函数,或者直接称作在代码中触发事件吧。
上面的这种方式就是必须在蓝图中实现事件触发后的逻辑,否则不起任何作用,另外一种则是可以在代码中实现默认的逻辑,可以在蓝图中重写。
这种方式我们可以参考官方文档中的一个示例,这里我们摘录核心代码,
UFUNCTION(BlueprintNativeEvent)
void CountdownHasFinished();
virtual void CountdownHasFinished_Implementation();
事件函数的调用和第一种方式一样,直接在相应代码逻辑处调用即可,但要注意,调用的是事件函数声明时的函数名,不是实现函数名,即上面的CountdownHasFinished而不是CountdownHasFinished_Implementation。
以上两种方式在游戏开发中经常会使用,比如在做多人游戏时,当客户端与服务器的网络断开时,我们可能要通知玩家网络已断开连接,这时我们可以在响应服务器的连接处理的逻辑处调用一个蓝图事件函数,我们在蓝图中处理具体的网络连接断开提示等逻辑。
Unreal技术交流学习请加群:173090312 Unreal高级开发群