[{"data":1,"prerenderedAt":182},["ShallowReactive",2],{"page-Tick-1":3,"page-count-Tick":181},[4],{"id":5,"title":6,"body":7,"date":157,"description":13,"extension":158,"meta":159,"navigation":162,"path":174,"seo":175,"stem":176,"tags":177,"__hash__":180},"blogs\u002F_legacy\u002F2018\u002F2018-07-28-ue4-tick-note.md","UE4中Tick使用小结",{"type":8,"value":9,"toc":144},"minimark",[10,14,17,21,24,27,30,33,37,40,43,46,49,53,56,59,64,67,70,73,77,80,83,94,97,101,104,108,111,114,117,123,126,132,135,141],[11,12,13],"p",{},"Tick在UE4的逻辑中是最基本的单元之一，不过也有些地方需要注意的。",[11,15,16],{},"当前使用的UE4版本为4.18。",[18,19,20],"h2",{"id":20},"并行",[11,22,23],{},"Tick是可以打开并行的，对于一些和主要逻辑没有耦合的逻辑，可以打开该Object的并行Tick：bRunOnAnyThread来进行运行优化。",[11,25,26],{},"实际并行的执行方式可以到FTickTaskSequencer::ReleaseTickGroup中去查看。",[11,28,29],{},"并行只在TickGroup内部执行，但是要小心多线程同步问题，考虑到加锁的成本，还是只对独立的逻辑进行异步比较好。",[11,31,32],{},"在优化上，还有一个bAllowTickOnDedicatedServer的选项，不过具体与使用_Server宏来屏蔽代码相比哪个更好些并没有测试过~",[18,34,36],{"id":35},"actualtickgroup","ActualTickGroup",[11,38,39],{},"每个TickFunc都可以指定TickGroup，但是这个TickGroup并不代表最终实际执行的TickGroup。",[11,41,42],{},"根据每个Tick注册的Prerequisite不同，Tick的执行Group会被延迟。",[11,44,45],{},"例如，如果TickFunc要求的Prerequisite是在PostPhiscs中的，那么即便它自己是注册为PrePhyiscs，也会被推迟到Post才能执行。",[11,47,48],{},"这个时候可以看到TickFunc的ActualStartTickGroup会变成实际的Tick执行组。",[18,50,52],{"id":51},"自定义tick","自定义Tick",[11,54,55],{},"可以通过自定义TickFunc来构建自己的Tick逻辑，相比TimerManager最大的优势就是这样可以在原有的Tick之外获得自己需要的逻辑执行时间。",[11,57,58],{},"引擎内部有一些额外定义的TickFunc，以前似乎是有SecondaryTick的，不过后来弃用了。",[60,61,63],"h3",{"id":62},"uworld","UWorld",[11,65,66],{},"作为PhsxScene的维护者，拥有额外的三个TickFunc：FStartPhysicsTickFunction、FEndPhysicsTickFunction、FStartAsyncSimulationFunction。",[11,68,69],{},"都是用于对物理世界进行操作的Tick，其中StartAsyncSimulation是用于cloth的模拟的，注册在EndPhysicsTickFunction之后。而StartPysics是用于启动物理模拟，EndPhysics则是物理模拟结束的。",[11,71,72],{},"所以如果要保证物理处理已经完成，最好是注册到PostPhysics。",[60,74,76],{"id":75},"uskeletalmeshcomponent","USkeletalMeshComponent",[11,78,79],{},"FSkeletalMeshComponentEndPhysicsTickFunction是注册在EndPhysics的，用于骨骼动画的状态同步等操作，没有仔细的看过，详情参考USkeletalMeshComponent::EndPhysicsTickComponent。",[11,81,82],{},"这个Tick是要求在关卡完成物理结算之后的：",[84,85,90],"pre",{"className":86,"code":88,"language":89},[87],"language-text","EndPhysicsTickFunction.AddPrerequisite(World, World->EndPhysicsTickFunction);\n","text",[91,92,88],"code",{"__ignoreMap":93},"",[11,95,96],{},"FSkeletalMeshComponentClothTickFunction则是负责对Cloth进行更新的，它被添加到了SkeletalMesh的EndPhysicsTickFunction之后，保证物理更新完成之后再进行衣服的演算更新。",[60,98,100],{"id":99},"ucharactermovmentcomponent","UCharacterMovmentComponent",[11,102,103],{},"FCharacterMovementComponentPostPhysicsTickFunction这个是在角色移动中，执行PostPhysicsTickComponent，当bDeferUpdateBasedMovement打开了的话，会在这里进行一次移动更新。",[60,105,107],{"id":106},"uprimitivecomponent","UPrimitiveComponent",[11,109,110],{},"FPrimitiveComponentPostPhysicsTickFunction，这个是用来执行每个Component的PostPhysicsTick的，按照官方注释已经弃用。",[60,112,113],{"id":113},"自定义",[11,115,116],{},"参照上面的TickFunc的用法，自定义比较简单",[84,118,121],{"className":119,"code":120,"language":89},[87],"USTRUCT()\nstruct FMyCustomTick : public FTickFunction\n{\n  GENERATED_USTRUCT_BODY()\n\n  class UVehicleSyncComponent*    Target;\n\n  FMyCustomTick();\n\n  virtual void ExecuteTick(float DeltaTime, ELevelTick TickType, ENamedThreads::Type CurrentThread, const FGraphEventRef& MyCompletionGraphEvent) override;\n  \u002F** Abstract function to describe this tick. Used to print messages about illegal cycles in the dependency graph **\u002F\n  virtual FString DiagnosticMessage() override;\n};\n\ntemplate\u003C>\nstruct TStructOpsTypeTraits\u003CFMyCustomTick> : public TStructOpsTypeTraitsBase2\u003CFMyCustomTick>\n{\n  enum\n  {\n    WithCopy = false\n  };\n};\n",[91,122,120],{"__ignoreMap":93},[11,124,125],{},"其中，下面的宏是必须的，否则会导致编译出错。因为TickFunc是不允许复制的。之后再对函数进行实现：",[84,127,130],{"className":128,"code":129,"language":89},[87],"FMyCustomTick::FMyCustomTick()\n{\n  TickGroup = ETickingGroup::TG_PostPhysics;\n  bCanEverTick = true;\n}\n\nvoid FMyCustomTick::ExecuteTick(float DeltaTime, ELevelTick TickType, ENamedThreads::Type CurrentThread, const FGraphEventRef& MyCompletionGraphEvent)\n{\n  FActorComponentTickFunction::ExecuteTickHelper(Target, \u002F*bTickInEditor=*\u002F false, DeltaTime, TickType, [this](float DilatedTime) { Target->PostPhysicsTick(*this); });\n}\n\nFString FMyCustomTick::DiagnosticMessage()\n{\n  return Target->GetFullName() + TEXT(\"[UMyComp::PostPhysxTick]\");\n}\n",[91,131,129],{"__ignoreMap":93},[11,133,134],{},"对于Component，定义了FMyCustomTick的变量PostPhysxComponentTick之后，在其Tick注册函数RegisterComponentTickFunctions中继续注册就可以了，可以使用的帮助函数SetupActorComponentTickFunction来进行注册，以及注意解注册：",[84,136,139],{"className":137,"code":138,"language":89},[87],"if (bRegister)\n{\n  if (SetupActorComponentTickFunction(&PostPhysxComponentTick))\n  {\n    PostPhysxComponentTick.Target = this;\n\n    UWorld* World = GetWorld();\n    if (World != nullptr)\n    {\n      PostPhysxComponentTick.AddPrerequisite(World, World->EndPhysicsTickFunction);\n    }\n  }\n}\nelse\n{\n  if (PostPhysxComponentTick.IsTickFunctionRegistered())\n  {\n    PostPhysxComponentTick.UnRegisterTickFunction();\n  }\n}\n",[91,140,138],{"__ignoreMap":93},[11,142,143],{},"TickFunc的自定义还是比较简单的 ，不明白的地方可以参考上面那些引擎内部用法。",{"title":93,"searchDepth":145,"depth":146,"links":147},2,3,[148,149,150],{"id":20,"depth":145,"text":20},{"id":35,"depth":145,"text":36},{"id":51,"depth":145,"text":52,"children":151},[152,153,154,155,156],{"id":62,"depth":146,"text":63},{"id":75,"depth":146,"text":76},{"id":99,"depth":146,"text":100},{"id":106,"depth":146,"text":107},{"id":113,"depth":146,"text":113},"2018-07-28","md",{"layout":160,"status":161,"published":162,"author":163,"author_login":165,"author_email":166,"wordpress_id":167,"wordpress_url":168,"date_gmt":169,"excerpt":170},"post","publish",true,{"display_name":164,"login":165,"email":166,"url":93},"风铃","flinkor","flinkor@foxmail.com",2409,"\u002F?p=2409","2018-07-28 02:03:37 +0000",{"type":8,"value":171},[172],[11,173,13],{},"\u002F2018-07-28-ue4-tick-note",{"title":6,"description":13},"_legacy\u002F2018\u002F2018-07-28-ue4-tick-note",[178,179],"UE4","Tick","WcoVUqA7rnnKC0CuEd2pU1q4cND6cJ72eY60f8a31Hc",1,1788763179225]