Skip to the content.

Ticker 扩充笔记 FTickerObjectBase

在编写全局事件分发器的时候,参考网络上一个现成的方案,发现分发器的管理器继承的FTickerObjectBase也实现了Tick的功能,google后并没有发现网络上有相关的内容。
简单的扒了下代码。 没有权威资料参考,不保证完全正确。

/**
 * Base class for ticker objects
 */
class FTickerObjectBase
{
public:

	/**
	 * Constructor
	 *
	 * @param InDelay Delay until next fire; 0 means "next frame"
	 * @param Ticker the ticker to register with. Defaults to FTicker::GetCoreTicker().
	*/
#if ( PLATFORM_WINDOWS && defined(__clang__) )
	CORE_API FTickerObjectBase()							// @todo clang: non-default argument constructors needed to prevent an ICE in clang
		: FTickerObjectBase(0.0f, FTicker::GetCoreTicker())	// https://llvm.org/bugs/show_bug.cgi?id=28137
	{
	}

	CORE_API FTickerObjectBase(float InDelay)
		: FTickerObjectBase(InDelay, FTicker::GetCoreTicker())
	{
	}

	CORE_API FTickerObjectBase(float InDelay, FTicker& Ticker);
#else
	CORE_API FTickerObjectBase(float InDelay = 0.0f, FTicker& Ticker = FTicker::GetCoreTicker());
#endif

	/** Virtual destructor. */
	CORE_API virtual ~FTickerObjectBase();

	/**
	 * Pure virtual that must be overloaded by the inheriting class.
	 *
	 * @param DeltaTime	time passed since the last call.
	 * @return true if should continue ticking
	 */
	virtual bool Tick(float DeltaTime) = 0;

private:
	// noncopyable idiom
	FTickerObjectBase(const FTickerObjectBase&);
	FTickerObjectBase& operator=(const FTickerObjectBase&);

	/** Ticker to register with */
	FTicker& Ticker;
	/** Delegate for callbacks to Tick */
	FDelegateHandle TickHandle;
};

从名字能看出来差别 FTickerObjectBase 和 FTickableGameObject的父类FTickableObjectBase。 实际这两个的调用是不一样的逻辑。


FTickableObjectBase

FTickableObjectBase是使用的单例结构体FTickableStatics作为Tick对象的一个载体。

   struct FTickableStatics
{
	FCriticalSection TickableObjectsCritical;
	TArray<FTickableObjectBase::FTickableObjectEntry> TickableObjects;

	FCriticalSection NewTickableObjectsCritical;
	TSet<FTickableGameObject*> NewTickableObjects;

	bool bIsTickingObjects = false;

	void QueueTickableObjectForAdd(FTickableGameObject* InTickable)
	{
		FScopeLock NewTickableObjectsLock(&NewTickableObjectsCritical);
		NewTickableObjects.Add(InTickable);
	}

	void RemoveTickableObjectFromNewObjectsQueue(FTickableGameObject* InTickable)
	{
		FScopeLock NewTickableObjectsLock(&NewTickableObjectsCritical);
		NewTickableObjects.Remove(InTickable);
	}

	static FTickableStatics& Get()
	{
		static FTickableStatics Singleton;
		return Singleton;
	}
};

该结构体内维护一个TickableObjects,每次创建一个FTickableObjectBase类时,在构造函数内就会Get到这个单例FTickableStatics,并且把FTickableObjectBase添加入这个FTickableStatics的成员变量TickableObjects内。
在LevelTick.cpp和GameEngine.cpp内再去调用FTickableGameObject::TickObjects这个静态方法实现Tick的完成流程。


FTickerObjectBase

	CORE_API FTickerObjectBase(float InDelay = 0.0f, FTicker& Ticker = FTicker::GetCoreTicker());

FTickerObjectBase的构造函数可以看到获取的FTicker::GetCoreTicker()

FTicker& FTicker::GetCoreTicker()
{
	return TLazySingleton<FCoreTicker>::Get();
}

返回的就是一个FCoreTicker的单例.

FTickerObjectBase::FTickerObjectBase(float InDelay, FTicker& InTicker)
	: Ticker(InTicker)
{
	// Register delegate for ticker callback
	FTickerDelegate TickDelegate = FTickerDelegate::CreateRaw(this, &FTickerObjectBase::Tick);
	TickHandle = Ticker.AddTicker(TickDelegate, InDelay);
}

在FTickerObjectBase构造函数里就会把Tick函数包装成一个委托注册给这个单例FTicker. 在整个引擎代码中有多个地方调用整个单例FTicker的Tick函数,PhysScene,PreLoadScreenManager,LaunchEngineLoop… 虽然没有得到证实,整个FTicker应该是从引擎启动到关闭一直在被执行Tick的。 与FTickableStatics的Tick是被Word调用的相比,FTicker的Tick调用几乎是不间断并且调用间隔也是写死的。 从这点上来说有些类似Unity的FixedUpdate。