Both Gameplay Tasks and AITasks support running other AI or Gameplay Tasks inside them. This is because they implement IGameplayTaskOwnerInterface.

To correctly manage the child task’s lifecycle, you need to pass the parent task as its task owner. The parent task must also implement OnGameplayTaskDeactivated and optionally some of the other methods from the task owner interface.

Example

Triggering and state handling

To trigger the child task, you can create a new task, for example like below:

MoveToTask = UAITask::NewAITask<UAITask_MoveTo>(*OwnerController, *this, EAITaskPriority::High, TEXT("MyTask"));
MoveToTask->SetUp(OwnerController, MoveReq);
MoveToTask->ReadyForActivation();

Note that it stores the task in a member property MoveToTask. This is so that when the task deactivates, we can correctly identify it:

void UAITask_MyTask::OnGameplayTaskDeactivated(UGameplayTask& Task)
{
	if(&Task == MoveToTask)
	{
		//check the result of the child task
	}
 
	Super::OnGameplayTaskDeactivated(Task);
}

Handling exit

When the parent task gets destroyed, you may need to manually cancel the child task.

void UAITask_MyTask::OnDestroy(bool bInOwnerFinished)
{
	if (MoveToTask)
	{
		auto* Task = MoveToTask;
		MoveToTask = nullptr;
		Task->ExternalCancel();
	}
	
	Super::OnDestroy(bInOwnerFinished);
}

The child task would get canceled as parent of the parent’s destroy sequence, but it may trigger undesirable effects. If you have code handling OnGameplayTaskDeactivated, letting the child task terminate on its own can trigger that function. By manually cleaning it up like in the above example, you avoid this issue.