How to do things like StartCoroutine in ue4?

Is there things in c++ or bp that can do things like StartCoroutine and yield like in unity?

Hi,

In C++/Blueprint you have the Timer,
in blueprint you have the node Delay/Retriggable delay
and C++ only you have latent action.

For example delay node is a latent action.

I see your id is Chinese so I’ll use Chinese to answer first and if you’re not please comment and I’ll translate to English

我想你说的应该是指“协程”机制,即比线程更加轻量的并行方案。但是很遗憾由于C++是一门非常底层的且非常重视效率的语言,因此并没有直接性的支持协程机制。你有以下选择:

  1. 使用线程或者TaskGraph作为并发方案。从而让任务可以并行化。具体可以参考:TaskGraph:https://docs.unrealengine.com/latest/INT/API/Developer/TaskGraph/index.html;线程:https://wiki.unrealengine.com/Multi-Threading:_How_to_Create_Threads_in_UE4

  2. 自己实现线程机制。

I see your id is Chinese so I’ll use Chinese to answer first and if you’re not please comment and I’ll translate to English

我想你说的应该是指“协程”机制,即比线程更加轻量的并行方案。但是很遗憾由于C++是一门非常底层的且非常重视效率的语言,因此并没有直接性的支持协程机制。你有以下选择:

使用线程或者TaskGraph作为并发方案。从而让任务可以并行化。具体可以参考:TaskGraph:https://docs.unrealengine.com/latest/INT/API/Developer/TaskGraph/index.html;线程:https://wiki.unrealengine.com/Multi-Threading:_How_to_Create_Threads_in_UE4

自己实现协程机制。这也有多种方法。一种简单的方法,是通过某些方式,将任务分配到每一个Tick中执行。这也是我很多时候在不希望延缓主线程的情况下,将任务后台执行的选择。虚幻引擎的地图载入也采用了类似的机制。

另外,你也可以参考Boost::Asio库,也提供了一个基于宏的协程实现。类似这样:

    class talk_to_svr : public boost::enable_shared_from_this<talk_to_svr>, public coroutine, boost::noncopyable {
        ...
        void step(const error_code & err = error_code(), size_t bytes = 0) {
            reenter(this) 
            { 
                for (;;) {
                    yield async_write(sock_, write_buffer_, MEM_FN2(step,_1,_2) );
                    yield async_read_until( sock_, read_buffer_,"\n", MEM_FN2(step,_1,_2));
                    yield service.post( MEM_FN(on_answer_from_server));
                }
            } 
        }
    };

很遗憾我自己没有研究Boost::Asio的协程实现。所以无法给出更多建议。

谢了,我不需要并行机制,只是希望用协程的特性来写状态机。ue这里有没有啥好的实现方式呢?

thx, i will go see latent action fit my need.
what i want is do a FSM and i like the yield staff in unity which you can pause in middle of some action, go do other staff and come back and continue such like. there is a FSM in animationBlueprint but not bp, but i think it can by done via bp or c++ somehow.

多谢,我去研究下 Asio。 之前看过一些开源的 c++协程库,不过我刚接触c++所以不是很清楚应该怎么集成进来,周围用c++的朋友都说没用过协程 Orz

是的,但是我不喜欢基于switch的状态机,感觉不够简单和干净,并且需要维护大量的私有变量。协程可以帮你把这些东西藏起来。而且协程状态机配合闭包可以很简单的实现一些重复性很高的复杂逻辑,switch状态机做这个也很吃力。

事实上在古老的UE3中,UnrealScript是带有状态state这个关键词的。UE4中没有提供原生的状态机系统。但是对于C++11来说,书写一个状态机应该并不需要依赖协程机制吧?我的状态机更新代码是依附于Tick函数中执行的。

由于C++十分底层,协程的实现需要有一个保护当前堆栈的过程。这对于C++这样的语言来说,要实现起来相对于C#/Mono平台的Unity来说,要困难很多。我这个也是从其他C++程序员那里获得的信息,据说Asio的基于宏的Stack-full 协程是性能与易用性上最好的协程实现。

但是虚幻引擎引入第三方库十分困难,我刚刚拆分了一下Boost::Coroutine2,发现里面还是包含了大量的.lib的。如果要引入第三方库,你可能需要有一些配置,包括把库文件放入ThirdParty之类的。不能够直接引入虚幻的编译机制。

我自己的状态机实现是没有使用协程的。事实上设计模式中状态机模式并没有说必须要协程完成。你是可以在不用协程的情况下,借助Tick完成的。

我的实现不是基于switch的。每个状态是一个对象,有一个状态机管理器。然后是在有事件发生的时候,通过调用状态机管理器的GotoState的方式来跳转。由于状态机是对象因此私有变量放入状态机类内部进行管理。

I think you can do that with the latent action in C++
you can inherit to FPendingLatentAction (FPendingLatentAction | Unreal Engine Documentation)
override the “UpdateOperation” method and return true when your own condition is complete.

An other example with the delay node the condition of the “UpdateOperation” is complete when the time parameter is elapsed

https://msdn.microsoft.com/en-us/magazine/mt573711.aspx

http://theboostcpplibraries.com/boost.coroutine