行为树新增StepSequence

kvfreedom
Posts: 69
Joined: 2024/07/11 04:36

行为树新增StepSequence

Post by kvfreedom »

1.png
1.png (76.09 KiB) Viewed 16308 times
希望行为树新增StepSequence,如图例可以实现输出"a" "b1" "a" "b2" "a" "b1"
User avatar
caitsithware
管理人
Posts: 90
Joined: 2024/03/26 01:56

Re: 行为树新增StepSequence

Post by caitsithware »

该提案将取决于“自己节点的父节点”来确定如何执行“自己节点的子节点”,从而使行为树不那么通用。
首先请重新考虑一下是否有必要使用行为树。
kvfreedom
Posts: 69
Joined: 2024/07/11 04:36

Re: 行为树新增StepSequence

Post by kvfreedom »

caitsithware wrote: 2024/09/04 11:55 该提案将取决于“自己节点的父节点”来确定如何执行“自己节点的子节点”,从而使行为树不那么通用。
首先请重新考虑一下是否有必要使用行为树。
1.png
1.png (180.82 KiB) Viewed 16299 times
StepSequence似乎并不需要“自己节点的父节点”来确定如何执行“自己节点的子节点”,StepSequence只需要记录一个Index,就可以判断需要执行哪一个子节点。
如图上的方式来实现,节点会比较多。StepSequence确实没有Sequence和Selector那么常用,最初我准备自己实现StepSequence,但是发现CompositeComponent是internal。
User avatar
caitsithware
管理人
Posts: 90
Joined: 2024/03/26 01:56

Re: 行为树新增StepSequence

Post by caitsithware »

您可以使用 OutputExecutePort 创建一个 TaskComponent。
例如,创建如下所示的脚本。

Code: Select all

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using LogicToolkit;

[System.Serializable]
public class StepTask : TaskComponent, IPauseReceiver
{
    [SerializeField]
    [FieldPlacement(FieldPlacement.Top)]
    private List<OutputExecutePort> _Steps;

    private int _Index;
    private OutputExecutePort _Current;
    private TaskStatus _TaskStatus;

    protected override void OnActivated()
    {
        _Current = _Steps[_Index];

        _TaskStatus = TaskStatus.Running;
        if (_Current == null || !_Current.Play(OnExit))
        {
            _TaskStatus = TaskStatus.Failure;
        }
    }

    bool OnExit(OutputExecutePort execute, FlowExitNode exitNode)
    {
        _Index = (_Index + 1) % _Steps.Count;

        if (exitNode == null
            || exitNode is ExitNode)
        {
            _TaskStatus = TaskStatus.Success;
            return true;
        }

        return false;
    }

    protected override TaskStatus OnExecute()
    {
        _Current?.Update();

        return _TaskStatus;
    }

    void IPauseReceiver.OnPause(bool pause)
    {
        if (pause)
        {
            _Current?.Pause();
        }
        else
        {
            _Current?.Resume();
        }
    }
}
StepTask.png
StepTask.png (55.86 KiB) Viewed 16284 times
User avatar
caitsithware
管理人
Posts: 90
Joined: 2024/03/26 01:56

Re: 行为树新增StepSequence

Post by caitsithware »

主要问题是该图没有显示该组件维护其子节点的执行索引。
组件的复杂性也会根据是否中途重置而增加。
目前,请创建您自己的脚本来处理该问题。
kvfreedom
Posts: 69
Joined: 2024/07/11 04:36

Re: 行为树新增StepSequence

Post by kvfreedom »

caitsithware wrote: 2024/09/04 13:54 您可以使用 OutputExecutePort 创建一个 TaskComponent。
自己写一个StepTask可能是不错的方式,如果父节点是一个行为树节点,似乎只需要再加一个ExecuteTask就可以了
kvfreedom
Posts: 69
Joined: 2024/07/11 04:36

Re: 行为树新增StepSequence

Post by kvfreedom »

caitsithware wrote: 2024/09/04 13:54 您可以使用 OutputExecutePort 创建一个 TaskComponent。
例如,创建如下所示的脚本。

Code: Select all

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using LogicToolkit;

[System.Serializable]
public class StepTask : TaskComponent, IPauseReceiver
{
    [SerializeField]
    [FieldPlacement(FieldPlacement.Top)]
    private List<OutputExecutePort> _Steps;

    private int _Index;
    private OutputExecutePort _Current;
    private TaskStatus _TaskStatus;

    protected override void OnActivated()
    {
        _Current = _Steps[_Index];

        _TaskStatus = TaskStatus.Running;
        if (_Current == null || !_Current.Play(OnExit))
        {
            _TaskStatus = TaskStatus.Failure;
        }
    }

    bool OnExit(OutputExecutePort execute, FlowExitNode exitNode)
    {
        _Index = (_Index + 1) % _Steps.Count;

        if (exitNode == null
            || exitNode is ExitNode)
        {
            _TaskStatus = TaskStatus.Success;
            return true;
        }

        return false;
    }

    protected override TaskStatus OnExecute()
    {
        _Current?.Update();

        return _TaskStatus;
    }

    void IPauseReceiver.OnPause(bool pause)
    {
        if (pause)
        {
            _Current?.Pause();
        }
        else
        {
            _Current?.Resume();
        }
    }
}
StepTask.png
1.png
1.png (12.13 KiB) Viewed 14824 times
2.png
2.png (10.86 KiB) Viewed 14824 times
3.png
3.png (9.92 KiB) Viewed 14824 times
收起Steps列表,关闭Logic编辑器再打开Logic编辑器,会显示连线错误
User avatar
caitsithware
管理人
Posts: 90
Joined: 2024/03/26 01:56

Re: 行为树新增StepSequence

Post by caitsithware »

这是由于 Unity 内部规范造成的问题。
“当 Foldout 关闭时,不会构建内部 UI,因此你不知道 Foldout 内部的电线连接在哪里。”
如果展开它,将显示端口,您可以确认它已连接。
我创建了一个编辑器扩展,以便 Foldout 不用于 If 节点等内容。
我们还将考虑将此编辑器扩展用于用户脚本。
User avatar
caitsithware
管理人
Posts: 90
Joined: 2024/03/26 01:56

Re: 行为树新增StepSequence

Post by caitsithware »

我忘记用 OnDeactivated 停止执行。
修改后的脚本如下。

Code: Select all

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using LogicToolkit;

[System.Serializable]
public class StepTask : TaskComponent, IPauseReceiver
{
    [SerializeField]
    [FieldPlacement(FieldPlacement.Top)]
    private List<OutputExecutePort> _Steps;

    private int _Index;
    private OutputExecutePort _Current;
    private TaskStatus _TaskStatus;

    protected override void OnActivated()
    {
        _Current = _Steps[_Index];

        _TaskStatus = TaskStatus.Running;
        if (_Current == null || !_Current.Play(OnExit))
        {
            _TaskStatus = TaskStatus.Failure;
        }
    }

    bool OnExit(OutputExecutePort execute, FlowExitNode exitNode)
    {
        _Index = (_Index + 1) % _Steps.Count;

        if (exitNode == null
            || exitNode is ExitNode)
        {
            _TaskStatus = TaskStatus.Success;
            return true;
        }

        return false;
    }

    protected override TaskStatus OnExecute()
    {
        _Current?.Update();

        return _TaskStatus;
    }

    protected override void OnDeactivated()
    {
        base.OnDeactivated();

        _Current?.Stop();
    }

    void IPauseReceiver.OnPause(bool pause)
    {
        if (pause)
        {
            _Current?.Pause();
        }
        else
        {
            _Current?.Resume();
        }
    }
}
Post Reply