Exemplo n.º 1
0
        private TaskStatus RunTask(BehaviorManager.BehaviorTree behaviorTree, int taskIndex, int stackIndex)
        {
            Task task = behaviorTree.taskList[taskIndex];

            // 第一步:加保护
            if (null == task)
            {
                Debug.LogError("NULL TASK");
                return(TaskStatus.Failure);
            }

            TaskStatus taskStatus = task.NodeData.ExecutionStatus;

            // 第二步:Push,再在Push里调用OnStart
            PushTask(behaviorTree, taskIndex, stackIndex);
            // 第三步:如果是父节点
            if (task is ParentTask)
            {
                ParentTask parentTask             = task as ParentTask;
                int        childIndex             = -1;
                TaskStatus currentChildTaskStatus = TaskStatus.Inactive;


                // 1、父节点是否已经执行完所有孩子了
                while (parentTask.CanExecute())
                {
                    if (task is Decorator && (behaviorTree.decoratorIndexList.Contains(taskIndex)))
                    {
                        break;
                    }

                    // 2、如果可以并行地执行所有孩子就不用等当前孩子跑完
                    if (parentTask.CanRunParallelChildren() || TaskStatus.Running != currentChildTaskStatus)
                    {
                        childIndex = parentTask.CurrentChildIndex();
                        int nextRunTaskIndex = behaviorTree.GetIndexInTaskList(taskIndex, childIndex);

                        if (parentTask.CanRunParallelChildren())
                        {
                            behaviorTree.activeStackList.Add(new Stack <int>());
                            stackIndex = behaviorTree.activeStackList.Count - 1;
                            parentTask.OnChildStarted(childIndex);
                        }
                        else
                        {
                            parentTask.OnChildStarted();
                        }

                        // 3、跑下一个子节点
                        currentChildTaskStatus = RunTask(behaviorTree, nextRunTaskIndex, stackIndex);
                        taskStatus             = currentChildTaskStatus;

                        if (parentTask is Decorator)
                        {
                            behaviorTree.decoratorIndexList.Add(taskIndex);
                            behaviorTree.decoratorIndexStatusDic.Add(taskIndex, parentTask.OverrideStatus(taskStatus));
                        }
                    }
                    else
                    {
                        break;
                    }
                }

                // 关于Decorator的特殊逻辑
                if (task is Decorator && behaviorTree.decoratorIndexList.Contains(taskIndex))
                {
                    taskStatus = behaviorTree.decoratorIndexStatusDic[taskIndex];
                    behaviorTree.decoratorIndexList.Remove(taskIndex);
                    behaviorTree.decoratorIndexStatusDic.Remove(taskIndex);
                    return(taskStatus);
                }
                taskStatus = parentTask.OverrideStatus(taskStatus);
            }
            // 第四步:如果是子节点,直接跑自己的OnUpdate
            else
            {
                taskStatus = task.OnUpdate();
            }

            // 保存好本帧自己的执行结果
            task.NodeData.ExecutionStatus = taskStatus;

            // 第五步:不管是正常跑完还是非正常终止的都要调下OnEnd
            if (TaskStatus.Running != taskStatus)
            {
                PopTask(behaviorTree, taskIndex, stackIndex, (task is ParentTask));
            }
            return(taskStatus);
        }
Exemplo n.º 2
0
        private void PopTask(BehaviorManager.BehaviorTree behaviorTree, int taskIndex, int stackIndex, bool isPopParent)
        {
            Task task = behaviorTree.taskList[taskIndex];
            // 如果pop出去的是某个父节点的子节点,特别是指Parallel属性的父节点(故父子节点在不同的栈),子节点需要写执行状态给在另一个栈的父节点
            int parentTaskIndex = behaviorTree.parentIndexMap[taskIndex];

            if (-1 != parentTaskIndex)
            {
                ParentTask parentTask = behaviorTree.taskList[parentTaskIndex] as ParentTask;
                // 作为父节点的第几个节点
                int childIndex = parentTask.GetChildIndex(task);
                // 父节点如果是并行节点是存储孩子的执行状态而顺序节点直接回写给父亲
                if (!parentTask.CanRunParallelChildren())
                {
                    parentTask.OnChildExecuted(task.NodeData.ExecutionStatus);
                }
                else
                {
                    parentTask.OnChildExecuted(childIndex, task.NodeData.ExecutionStatus);
                }
                // 这又似乎是写的不好的地方,应该可以让这里和RunTask关于返回子节点状态返回给父节点的地方合在一起
                parentTask.NodeData.ExecutionStatus = parentTask.OverrideStatus(task.NodeData.ExecutionStatus);
            }

            if (behaviorTree.activeStackList[stackIndex].Peek() == taskIndex)
            {
                behaviorTree.activeStackList[stackIndex].Pop();
                task.OnEnd();

                // 如果弹出的是父节点,需要把它还在栈中的子节点也弹出
                // 这里有问题,如果子节点也是并行节点,那还需要把子节点的子节点栈删掉
                // 所以应该是无须其他判断就可以把该栈后面所有的栈都remove掉(待验证)
                if (isPopParent)
                {
                    for (int i = behaviorTree.activeStackList.Count - 1; i > stackIndex; i--)
                    {
                        behaviorTree.activeStackList.RemoveAt(i);
                        //Stack<int> intStack = behaviorTree.activeStackList[i];

                        // 如果一个栈中的top是待查父节点的子节点,那么剩下的应该都是该父节点的子节点(待测试)
                        //int childIndex = intStack.Peek();
                        //if (behaviorTree.parentIndexMap[childIndex] == taskIndex)
                        //{
                        //    behaviorTree.activeStackList.RemoveAt(i);
                        //}
                    }
                }

                if (task.RemoveWhenFinish())
                {
                    behaviorTree.RemoveTask(taskIndex);
                }
            }
            else
            {
#if UNITY_EDITOR
                Debug.LogWarning("BehaviorManager PopTask ERROR : the task to pop is not in top.");
#endif
            }

            // 如果整个栈都是空的,那就移除
            if (0 == behaviorTree.activeStackList[stackIndex].Count)
            {
                behaviorTree.activeStackList.RemoveAt(stackIndex);
            }
        }