[{"data":1,"prerenderedAt":308},["ShallowReactive",2],{"\u002F2015-08-16-ue4-event-dispatcher-and-delegate":3},{"id":4,"title":5,"body":6,"date":284,"description":12,"extension":285,"meta":286,"navigation":289,"path":301,"seo":302,"stem":303,"tags":304,"__hash__":307},"blogs\u002F_legacy\u002F2015\u002F2015-08-16-ue4-event-dispatcher-and-delegate.md","事件调度器及C++中的使用",{"type":7,"value":8,"toc":277},"minimark",[9,13,16,19,23,26,29,32,39,42,47,50,54,57,60,63,66,69,72,162,165,201,204,239,242,250,253,259,262,267,270,273],[10,11,12],"p",{},"事件调度器非常的适合在各个蓝图之间实现通信功能。",[10,14,15],{},"当前UE4版本4.8.3。",[10,17,18],{},"在蓝图中，事件调度器的作用就像是事件的派发器。通过将事件预先的绑定在事件调度器上，可以让系统可以在需要时将事件派发给所有已经绑定的事件。",[20,21,22],"h2",{"id":22},"事件调度器的使用",[10,24,25],{},"一个比较常见的使用事件调度器的地方，就是关卡蓝图。",[10,27,28],{},"关卡蓝图中的很多物体的Actor及其逻辑，如果要脱离关卡蓝图的话会比较难于使用。因此，可以通过将关卡蓝图中实现好的功能绑定到某个类，例如GameMode的事件调度器上来方便调度。",[10,30,31],{},"如下图，在关卡蓝图的BeginPlay中将功能绑定到GameMode上：",[10,33,34],{},[35,36],"img",{"alt":37,"src":38},"image","\u002Fwp-content\u002Fuploads\u002F2015\u002F08\u002Fimage_thumb1.png",[10,40,41],{},"然后可以在GameMode的蓝图中，设定定时的调度关卡蓝图上的功能",[10,43,44],{},[35,45],{"alt":37,"src":46},"\u002Fwp-content\u002Fuploads\u002F2015\u002F08\u002Fimage_thumb2.png",[10,48,49],{},"事件调度器同时支持解绑和解绑全部，以方便对事件调度的逻辑进行进一步的控制。",[20,51,53],{"id":52},"delegate","Delegate",[10,55,56],{},"在C++和蓝图混合使用时，使用Blueprint Function Library可以方便的实现蓝图到C++的调用。如果要实现C++对蓝图的逻辑的话，事件调度机制就非常的方便。",[10,58,59],{},"在C++中，与事件调度器对应的是Delegate机制。事实上，Delegate机制的涵盖范围比事件调度器要大一些。",[10,61,62],{},"Delegate机制是一种常见的设计模式，相信做程序的童鞋都比较熟悉。这里不做多余的说明了。",[10,64,65],{},"UE4官方对Delegate的翻译名称唯代理。按照类型，分为单播代理和多播代理。其中，多播代理与事件调度器的功能类似，而单播代理更接近单纯的代理，也就是只能绑定一个执行函数。",[10,67,68],{},"要让多播代理像是事件调度器一样使用的话，需要将其定义为Dynamic。对于单播代理也是一样的。",[10,70,71],{},"在C++中使用UE4的代理功能，需要使用官方提供的宏进行定义。",[73,74,75,86],"table",{},[76,77,78],"thead",{},[79,80,81,84],"tr",{},[82,83],"th",{},[82,85],{},[87,88,89,98,106,114,122,130,138,146,154],"tbody",{},[79,90,91,95],{},[92,93,94],"td",{},"函数签名",[92,96,97],{},"声明宏",[79,99,100,103],{},[92,101,102],{},"void Function()",[92,104,105],{},"DECLARE_DELEGATE( DelegateName )",[79,107,108,111],{},[92,109,110],{},"void Function( Param1 )",[92,112,113],{},"DECLARE_DELEGATE_OneParam( DelegateName, Param1Type )",[79,115,116,119],{},[92,117,118],{},"void Function( Param1, Param2 )",[92,120,121],{},"DECLARE_DELEGATE_TwoParams( DelegateName, Param1Type, Param2Type )",[79,123,124,127],{},[92,125,126],{},"void Function( Param1, Param2, ... )",[92,128,129],{},"DECLARE_DELEGATE_NumParams( DelegateName, Param1Type, Param2Type, ... )",[79,131,132,135],{},[92,133,134],{},"RetVal Function()",[92,136,137],{},"DECLARE_DELEGATE_RetVal( RetValType, DelegateName )",[79,139,140,143],{},[92,141,142],{},"RetVal Function( Param1 )",[92,144,145],{},"DECLARE_DELEGATE_RetVal_OneParam( RetValType, DelegateName, Param1Type )",[79,147,148,151],{},[92,149,150],{},"RetVal Function( Param1, Param2 )",[92,152,153],{},"DECLARE_DELEGATE_RetVal_TwoParams( RetValType, DelegateName, Param1Type, Param2Type )",[79,155,156,159],{},[92,157,158],{},"RetVal Function( Param1, Param2, ... )",[92,160,161],{},"DECLARE_DELEGATE_RetVal_NumParams( RetValType, DelegateName, Param1Type, Param2Type, ... )",[10,163,164],{},"针对不同的代理类型，使用不同的宏前缀即可：",[73,166,167,175],{},[76,168,169],{},[79,170,171,173],{},[82,172],{},[82,174],{},[87,176,177,185,193],{},[79,178,179,182],{},[92,180,181],{},"多播代理",[92,183,184],{},"DECLARE_MULTICAST_DELEGATE...",[79,186,187,190],{},[92,188,189],{},"动态单播代理",[92,191,192],{},"DECLARE_DYNAMIC_DELEGATE...",[79,194,195,198],{},[92,196,197],{},"动态多播代理",[92,199,200],{},"DECLARE_DYNAMIC_MULTICAST_DELEGATE...",[10,202,203],{},"实际使用时，首先要对代理类型进行定义",[205,206,211],"pre",{"className":207,"code":208,"language":209,"meta":210,"style":210},"language-cpp shiki shiki-themes github-light-high-contrast github-dark monokai","DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FDspLRValDelegate, float, LVals, float, RVals);\n","cpp","",[212,213,214],"code",{"__ignoreMap":210},[215,216,219,223,227,231,234,236],"span",{"class":217,"line":218},"line",1,[215,220,222],{"class":221},"scAT4","DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams",[215,224,226],{"class":225},"s0idv","(FDspLRValDelegate, ",[215,228,230],{"class":229},"sGZGq","float",[215,232,233],{"class":225},", LVals, ",[215,235,230],{"class":229},[215,237,238],{"class":225},", RVals);\n",[10,240,241],{},"然后在具体的类，例如GameState中进行具体的声明",[205,243,248],{"className":244,"code":246,"language":247},[245],"language-text","UPROPERTY(BlueprintAssignable, Category = \"SoundFuncs\")\n    FDspLRValDelegate  DspLRVals;\n","text",[212,249,246],{"__ignoreMap":210},[10,251,252],{},"这样一来，就可以在需要调用这个代理的地方进行调用了，例如在某个数据生成的地方。",[205,254,257],{"className":255,"code":256,"language":247},[245],"AMyGameState* tags = Cast\u003CAMyGameState>(SL_Contex.LC_cGameState);\nif (tags)\n    tags->DspLRVals.Broadcast(tfLval, tfRval);\n",[212,258,256],{"__ignoreMap":210},[10,260,261],{},"之后，就可以在蓝图中向这个多播代理绑定事件来获得生成的数据了",[10,263,264],{},[35,265],{"alt":37,"src":266},"\u002Fwp-content\u002Fuploads\u002F2015\u002F08\u002Fimage_thumb3.png",[20,268,269],{"id":269},"总结",[10,271,272],{},"事件调度器的机制在逻辑实现中非常的方便，尤其是在关卡设计中，可能会比较经常用到。使用中也没有遇到什么特别需要注意的地方，逻辑很单纯。",[274,275,276],"style",{},"html pre.shiki code .scAT4, html code.shiki .scAT4{--shiki-default:#622CBC;--shiki-dark:#B392F0;--shiki-sepia:#A6E22E}html pre.shiki code .s0idv, html code.shiki .s0idv{--shiki-default:#0E1116;--shiki-dark:#E1E4E8;--shiki-sepia:#F8F8F2}html pre.shiki code .sGZGq, html code.shiki .sGZGq{--shiki-default:#A0111F;--shiki-default-font-style:inherit;--shiki-dark:#F97583;--shiki-dark-font-style:inherit;--shiki-sepia:#66D9EF;--shiki-sepia-font-style:italic}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .sepia .shiki span {color: var(--shiki-sepia);background: var(--shiki-sepia-bg);font-style: var(--shiki-sepia-font-style);font-weight: var(--shiki-sepia-font-weight);text-decoration: var(--shiki-sepia-text-decoration);}html.sepia .shiki span {color: var(--shiki-sepia);background: var(--shiki-sepia-bg);font-style: var(--shiki-sepia-font-style);font-weight: var(--shiki-sepia-font-weight);text-decoration: var(--shiki-sepia-text-decoration);}",{"title":210,"searchDepth":278,"depth":279,"links":280},2,3,[281,282,283],{"id":22,"depth":278,"text":22},{"id":52,"depth":278,"text":53},{"id":269,"depth":278,"text":269},"2015-08-16","md",{"layout":287,"status":288,"published":289,"author":290,"author_login":292,"author_email":293,"wordpress_id":294,"wordpress_url":295,"date_gmt":296,"excerpt":297},"post","publish",true,{"display_name":291,"login":292,"email":293,"url":210},"风铃","flinkor","flinkor@foxmail.com",1450,"\u002F\u002F?p=1450","2015-08-16 04:00:50 +0000",{"type":7,"value":298},[299],[10,300,12],{},"\u002F2015-08-16-ue4-event-dispatcher-and-delegate",{"title":5,"description":12},"_legacy\u002F2015\u002F2015-08-16-ue4-event-dispatcher-and-delegate",[305,306,53],"UE4","事件调度器","erOr00Vt93ckLDdi2Mv8NeMJyYp0YYoVyMZW1VTURTs",1788763180278]