Why is FTickableGameObject::Tick() being called in the editor?

Hi, I’m implementing the FTickableGameObject in one of my manager classes.

UCLASS()
class UGameFlowManager : public UObject, public FTickableGameObject
{
	GENERATED_UCLASS_BODY()
	virtual ~UGameFlowManager();
	

public:
	virtual void Tick(float DeltaTime) OVERRIDE;
	virtual bool IsTickable() const OVERRIDE;
	virtual TStatId GetStatId() const OVERRIDE;

private:

	TimeObject* _timeObject;

};

The base FTickableGameObject class defines the function:

	virtual bool IsTickableInEditor() const
	{
		return false;
	}

It returns false for being tickable in the editor but my tick function is still being called. Am I doing something wrong? How do I turn of the tick in the editor?

I also never create an instance of my class, I guess this done by the editor to give it some functionality. If someone could shed a little light on this that would be great.

Just ran into this, an answer would be nice.

So, some investigation found the answer to this pretty quickly, but it seems like a bug to me. Probably “legacy” behaviour.

Overriding IsTickableInEditor() to return false will not work because of this bit of code, I believe:

bool bTickIt = TickableObject->IsTickable() && 
(
	(TickType != LEVELTICK_TimeOnly && !bIsPaused) ||
	(bIsPaused && TickableObject->IsTickableWhenPaused()) ||
	(GIsEditor && !IsPlayInEditor() && TickableObject->IsTickableInEditor())
);

in LevelTick.cpp. As you can see that OR makes it behave strangely.

The solution I came up with:

virtual bool IsTickable() const override { return (!GWorld->HasBegunPlay() && GIsEditor) ? false : true; }

If we’re in the editor, and NOT playing, don’t tick. Otherwise, tick.

return (!GWorld->HasBegunPlay() && GIsEditor) ? false : true;

Can be replaced just with

return GWorld->HasBegunPlay() && !GIsEditor;

&&, || and ! are Boolean operators and can be used anywhere as all math operators :slight_smile:

Still passed on 4.10 can confirm this bug Epic?

I just run into this as well. Anyone can help?

4.16 - example solution is ticking in editor.

I am seeing this as well, and even if there is no instantiated version of my TickableObject.

This implies it must be the CDO ticking (Class Default Object, which UE4 makes for each class so it knows default variable settings).

Using this should work to stop the CDO ticking even in 4.16:

bool UMyTickableObject::IsTickable() const
{
// Tick only if we are both NOT a template and if we are specifically not in-editor-before-beginplay is called.
	return (!IsTemplate(RF_ClassDefaultObject)) && !(GIsEditor && !GWorld->HasBegunPlay()
}

but note that I’m seeing IsTickable() called several times a frame on the CDO when I log it - this doesn’t feel like everything is good on the engine side.

Hi!

I observed the same problem a few days ago in my project. Upon trying your code, it indeed stops the CDO from ticking, but in my case, even an instance doesn’t tick anymore. I have instanciated the uobject in a custom GameInstance, if that makes any difference. I’m also in 4.16, and this is pretty puzzling.

I think I found a solution.

*.h

virtual UWorld* GetTickableGameObjectWorld() const override;

*.cpp

UWorld* UGeneWithTick::GetTickableGameObjectWorld() const 
{
    return GetOuter()->();
}

I just ran into this in UE5.0.3 and thought it might be useful to note what I saw:

  • The behaviour as described still seems to be happening.
  • Overriding GetTickableGameObjectWorld didn’t seem to alter the behaviour at all.
  • After BeginPlay (at least when PIE) I saw three calls to IsTickable for each object. Confusingly, in two of those calls GWorld->HasBegunPlay() return false, and in one it returned true.
  • However just the call to IsTemplate seemed to be enough, i.e. if I only return true from my overriden version of IsTickable() (if the class is not the default object) then I only see a Tick called on the correct object, and only when playing.

Hi everyone.

Sorry for posting on such an old thread but I was running into the same issues just today and didn’t want to run some if check inside the tick method. It turns out that the register method gets called inside the FTickableGameObject constructor, which then obviously means that the CDO also starts ticking it self along with whatever extra objects get created (like others already mentioned).

However Epic them selves have a workaround in the engine code to prevent this without having weird workarounds inside of the Tick method it self. Figured I would share it!

Override this method in the header file:

virtual ETickableTickType GetTickableTickType() const override;

And inside the cpp file implement it like this:

ETickableTickType YOURCLASS::GetTickableTickType() const
{
    return HasAnyFlags(RF_ClassDefaultObject) ? ETickableTickType::Never : ETickableTickType::Always;
}

Hopefully it helps anyone.

4 Likes