行为树(Behavior Trees)

行为树(Behavior Trees)是一种在游戏开发中广泛使用的AI设计模式,主要用于描述AI的行为和决策过程,实现更加智能和自然的游戏AI。它由多个节点组成,每个节点代表一个行为或决策,按照特定的方式连接在一起,形成一个树状结构。
在行为树中,根节点是AI的起点,通过遍历子节点来决策AI的行为。节点有以下三种状态:成功(Success)、失败(Failure)和运行(Running)。前两个通知其父节点其操作是成功还是失败。第三种意味着尚未确定成功或失败,并且该节点仍在运行。下次树被选择时,该节点将再次被选择,此时它将再次有机会成功,失败或继续运行。
行为树的节点有以下几种主要原型:

  1. 组合控制节点(Composite):一种将多个子节点组合在一起的节点,用于实现复杂的行为和决策逻辑。主要包括次序节点(Sequencer)和选择节点(Selector)。次序节点并行执行多个子节点,直到所有子节点都返回成功或者任意一个子节点返回失败为止。选择节点按照顺序执行子节点,当某个子节点返回成功时,停止执行并返回成功。
    在这里插入图片描述
    在这里插入图片描述

  2. 修饰节点(Decorator):一种特殊的节点,它不执行具体的行为或决策,而是修饰其它节点的行为或决策。主要包括逆变节点(Inverter)和重复节点(Repeater)。逆变节点可以将子节点的结果倒转,比如子节点返回了失败,则这个修饰节点会向上返回成功,以此类推。重复节点重复执行其子节点指定的次数或者一直重复执行,直到其子节点返回成功或者失败。
    在这里插入图片描述
    在这里插入图片描述

  3. 叶节点(Leaf):树的最末端,就是这些AI实际上去做事情的命令。

行为树通过模拟树状结构来描述AI的行为和决策过程,使得AI的行为更加灵活、自然和智能。
代码实现
在这里插入图片描述

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using BehaviourTree;

namespace BehaviourTree
{
    public class BehaviourTree : MonoBehaviour
    {
        private Node root = null;
        private Blackboard blackboard;

        public Node Root
        {
            get
            {
                return root;
            }
            set
            {
                root= value;
            }
        }

        void Start()
        {
            Init();
        }

        void Update()
        {
            if(root!=null&& gameObject!=null)
            {
                root.Evaluate(gameObject.transform,blackboard);
            }
        }

        protected virtual void Init()
        {
            blackboard = new Blackboard();
        }
        
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using BehaviourTree;

namespace BehaviourTree
{
    //行为树共享数据
    public class Blackboard
    {
        private Dictionary<string,object> Data;

        public Blackboard()
        {
            Data = new Dictionary<string, object>();
        }

        //获取数据
        public T Get<T>(string key)
        {
            if(Data.ContainsKey(key))
            {
                return (T)Data[key];
            }
            return default;
        }

        //添加数据
        public void Add<T>(string key,T value)
        {
            if(Data.ContainsKey(key))
            {
                Data[key] = value;
            }
            else
            {
                Data.Add(key,value);
            }
        }

        //删除数据
        public void Remove(string key)
        {
            if(Data.ContainsKey(key))
            {
                Data.Remove(key);
            }
            else
            {
                Debug.Log("数据不存在 "+key);
            }
        }
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using BehaviourTree;

namespace BehaviourTree
{
    //状态类型
    public enum Status
    {
        Running,    //运行中
        Failure,    // 失败
        Success,    //成功
    }

    //节点基类
    public abstract class Node
    {
        protected Node parent;
        protected Status status;

        Status Status
        {
            get
            {
                return status;
            }
            set
            {
                status = value;
            }
        }

        public Node()
        {
            
        }
        
        //声明节点状态返回方法
        public abstract Status Evaluate(Transform transform,Blackboard blackboard);
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using BehaviourTree;

namespace BehaviourTree
{
    //复合节点类
    public abstract class Composite : Node
    {
        //子节点列表
        protected List<Node> children = new List<Node>();
        protected int index;//子节点下标计数
        protected Composite(List<Node> children)
        {
            index = 0;
            foreach(var child in children) 
            {
                this.children.Add(child);
            }
        }
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using BehaviourTree;

namespace BehaviourTree
{
    //修饰器节点
    public abstract class Decorator : Node
    {
        //子节点列表
        protected List<Node> children;
        protected Decorator(List<Node> children)
        {
            children = new List<Node>(){};
            foreach(var child in children) 
            {
                this.children.Add(child);
            }
        }
    }

}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using BehaviourTree;

namespace BehaviourTree
{
    //选择节点,所有子节点都为失败则失败
    public class Selector : Composite
    {
        
        public Selector(List<Node> children) : base(children)
        {
            
        }

        //所有子节点都为失败则失败
        public override Status Evaluate(Transform transform, Blackboard blackboard)
        {
            if(index>=children.Count)
            {
                index = 0;
                return Status.Success;
            }
            var status = children[index].Evaluate(transform,blackboard);
            switch(status)
            {
                case Status.Success:
                    index = 0;
                    return Status.Success;
                case Status.Failure:
                    index+=1;
                    if(index>=children.Count)
                    {
                        index = 0;
                        return Status.Failure;
                    }
                    return Status.Running;
                case Status.Running:
                    return Status.Running;
                default:
                    return Status.Failure;
            }
        }
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using BehaviourTree;

namespace BehaviourTree
{
    //顺序节点,所有子节点成功才成功
    public class Sequencer : Composite
    {
        public Sequencer(List<Node> children) : base(children)
        {
            
        }

        //所有子节点成功才成功
        public override Status Evaluate(Transform transform, Blackboard blackboard)
        {
            if(index>=children.Count)
            {
                index = 0;
                return Status.Success;
            }
            var status = children[index].Evaluate(transform,blackboard);
            switch(status)
            {
                case Status.Success:
                    index+=1;
                    if(index>=children.Count)
                    {
                        index = 0;
                        return Status.Success;
                    }
                    return Status.Running;
                case Status.Failure:
                    return Status.Failure;
                case Status.Running:
                    return Status.Running;
                default:
                    return Status.Failure;
            }
        }
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using BehaviourTree;

namespace BehaviourTree
{
    //任务节点,这里会处理对象具体行为逻辑(叶节点)
    public abstract class Task : Node
    {
        
    }
}

简单使用
实现敌人在两点之间巡逻,人物靠近会变红温并停止移动,人物远离时继续巡逻
在这里插入图片描述

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using BehaviourTree;
using System.ComponentModel.Design.Serialization;
using System.Linq;

namespace BehaviourTree
{
    public class EnemyBT : BehaviourTree
    {
        Vector3 aPos = new Vector3(4.07999992f,-2.21000004f,-2);
        Vector3 bPos = new Vector3(4.07999992f,1.65999997f,-2)
        protected override void Init()
        {
            //调用基类初始化
            base.Init();
            //创建变红节点
            TurnRed turnRed = new TurnRed();
            //创建巡逻节点
            Patrol patrol = new Patrol(aPos,bPos);
            //创建查找节点
            FindObject findObject = new FindObject();
            //创建侦查节点子节点序列
            Node[] spyChildren = {findObject,turnRed};
            //创建顺序节点用于执行侦查行为
            EnemySequencer enemySequencer = new EnemySequencer(spyChildren.ToList());
            //创建根节点子节点序列
            Node[] selectorChildren = {enemySequencer,patrol};
            //创建选择节点用于处理侦查和巡逻行为
            EnemySelector enemySelector = new EnemySelector(selectorChildren.ToList());
            //将选择节点设置为根节点
            Root = enemySelector;
            
        }
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using BehaviourTree;

namespace BehaviourTree
{
    public class EnemySelector : Selector
    {
        public EnemySelector(List<Node> children) : base(children)
        {
            
        }
    }
}

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using BehaviourTree;

namespace BehaviourTree
{
    public class EnemySequencer : Sequencer
    {
        public EnemySequencer(List<Node> children) : base(children)
        {
    
        }
    }
}

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using BehaviourTree;
using DG.Tweening;

namespace BehaviourTree
{
    public class FindObject : Task
    {
        float radius = 5f;
        int layer = 512;
        public override Status Evaluate(Transform transform, Blackboard blackboard)
        {
            Collider2D obj = Physics2D.OverlapCircle(transform.position,radius,layer);
            if(obj!=null)
            {
                return Status.Success;   
            }
            transform.gameObject.GetComponent<SpriteRenderer>().DOColor(Color.white,1);
            return Status.Failure;
        }
    }
}


using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using BehaviourTree;
using DG.Tweening;

namespace BehaviourTree
{
    //在aPoint和bPoint之间来回移动
    public class Patrol : Task
    {
        Vector3 aPoint;
        Vector3 bPoint;
        float speed = 4f;
        Vector3 target;
        public Patrol(Vector3 aPos,Vector3 bPos)
        {
            aPoint = aPos;
            bPoint = bPos;
            target = aPoint;
        }
        public override Status Evaluate(Transform transform, Blackboard blackboard)
        {
            if(Vector2.Distance(transform.position,target)<0.1f)
            {
                if(target == aPoint)
                {
                    target = bPoint;
                }
                else
                {
                    target = aPoint;
                }
            }
            else
            {
                transform.position = Vector2.MoveTowards(transform.position,target,Time.deltaTime*speed);
            }
            return Status.Success;
        }
    }
}

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using BehaviourTree;
using DG.Tweening;

namespace BehaviourTree
{
    //变红
    public class TurnRed : Task
    {
        Vector3 bPoint;
        public override Status Evaluate(Transform transform, Blackboard blackboard)
        {
            transform.gameObject.GetComponent<SpriteRenderer>().DOColor(Color.red,1);
            return Status.Success;
        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/325576.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

智能助手的巅峰对决:ChatGPT对阵文心一言

在人工智能的世界里&#xff0c;ChatGPT与文心一言都是备受瞩目的明星产品。它们凭借先进的技术和强大的性能&#xff0c;吸引了大量用户的关注。但究竟哪一个在智能回复、语言准确性、知识库丰富度等方面更胜一筹呢&#xff1f;下面就让我们一探究竟。 首先来谈谈智能回复能力…

数据结构学习 jz41 数据流中的中位数

关键词&#xff1a;排序 大顶堆 小顶堆 题目&#xff1a;数据流中的中位数 这道题我没有想到用两个堆来做。 思路&#xff1a; 关键&#xff1a;维护两个堆&#xff0c;一个大顶堆一个小顶堆。 大顶堆&#xff1a;装较小的那一半的数&#xff0c;它的顶就是较小那一半数的最…

淘宝搜索引擎API接口关键字搜索商品列表获取商品详情价格评论销量API

item_search-按关键字搜索淘宝商品 公共参数 查看API完整文档 名称类型必须描述keyString是调用key&#xff08;必须以GET方式拼接在URL中&#xff09;secretString是调用密钥api_nameString是API接口名称&#xff08;包括在请求地址中&#xff09;[item_search,item_get,it…

如何在企业微信开发者中心使用内网穿透工具回调本地接口服务

文章目录 1. Windows安装Cpolar2. 创建Cpolar域名3. 创建企业微信应用4. 定义回调本地接口5. 回调和可信域名接口校验6. 设置固定Cpolar域名7. 使用固定域名校验 企业微信开发者在应用的开发测试阶段&#xff0c;应用服务通常是部署在开发环境&#xff0c;在有数据回调的开发场…

Mysql root 密码重置详解

文章目录 1 概述1.1 前言1.2 mysql 版本查询 2 windows 操作系统2.1 mysql 8 及以上版本2.1.1 关闭 mysql 服务2.1.2 通过无认证方式启动 mysql2.1.3 新开窗口&#xff0c;登录 mysql&#xff0c;重置密码 1 概述 1.1 前言 不同的操作系统&#xff08;如&#xff1a;windows、…

Eureka 本机集群实现

距离上次发布博客已经一年多了&#xff0c;主要就是因为考研&#xff0c;没时间学习技术的内容&#xff0c;现在有时间继续完成关于代码方面的心得&#xff0c;希望跟大家分享。 今天在做一个 Eureka 的集群实现&#xff0c;我是在本电脑上跑的&#xff0c;感觉这个挺有意思&a…

AI智能化办公:巧用ChatGPT高效搞定Excel数据分析

文章目录 1. 自动提取关键信息2. 自动生成分析报告3. 自动回答问题4. 自动生成图表《巧用ChatGPT高效搞定Excel数据分析》关键点内容简介作者简介 《AI智能化办公&#xff1a;ChatGPT使用方法与技巧从入门到精通》图书特色内容简介作者简介 随着人工智能技术的不断发展&#xf…

【ELK 学习】ElasticSearch

ELK&#xff1a;ElasticSearch存储&#xff0c;Logstash收集&#xff0c;Kibana展示 版本较多&#xff0c;使用时需要版本匹配&#xff0c;还需要和mysql版本匹配&#xff08;elastic官网给了版本对应关系&#xff09; 本次使用的版本es6.8.12 filebeat 轻量级的数据收集工具 …

web前端第二次作业

1&#xff0c;计算用户指定的数值内的奇数和 效果运行图&#xff1a; 代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>计算用户指定的数值内的奇数和</title> </head>…

【Dynamo学习笔记】基础入门

目录 前言1 Dynamo的界面2 节点的操作3 几何形体的创建与编辑3.1 几何形体的创建3.1.1 直线3.1.2 圆形3.1.3 多边形3.1.4 长方体3.1.5 球体 3.2 几何形体的编辑3.2.1 坐标点的平移复制3.2.2 几何形体的平移复制3.2.3 几何形体的镜像复制3.2.4 几何形体的旋转复制3.2.5 几何形体…

数字前端/FPGA设计——握手与反压问题

声明&#xff1a;本文来自0431大小回 前言&#xff1a;在芯片设计或者FPGA设计过程中&#xff0c;流水设计是经常用到的&#xff0c;但是考虑数据安全性&#xff0c;需要与前后级模块进行握手通信&#xff0c;这时候就需要对流水数据进行反压处理&#xff0c;本文将具体介绍握手…

尺寸公差 DTAS3D产品功能介绍

DTAS 3D (Dimensional Tolerance Analysis System 3D)基于蒙特卡洛原理&#xff0c;按照产品的公差及装配关系进行建模&#xff0c;然后进行解析、仿真计算&#xff0c;最终预测产品设计是否能够满足其关键尺寸要求&#xff0c;同时预测产品合格率&#xff0c;并进行根源分析。…

【NI国产替代】NI‑9232,3通道,102.4 kS/s/ch,±30 V,C系列声音与振动输入模块

3通道&#xff0c;102.4 kS/s/ch&#xff0c;30 V&#xff0c;C系列声音与振动输入模块 NI‑9232可以测量来自集成电子压电(IEPE)和非IEPE传感器的信号&#xff0c;例如加速度计、转速计和接近式探针。 NI‑9232还可兼容智能TEDS传感器。\n\nNI‑9232集成了软件可选的AC/DC耦合…

Fpga开发笔记(二):高云FPGA发开发软件Gowin和高云fpga基本开发过程

若该文为原创文章&#xff0c;转载请注明原文出处 本文章博客地址&#xff1a;https://hpzwl.blog.csdn.net/article/details/135620590 红胖子网络科技博文大全&#xff1a;开发技术集合&#xff08;包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬…

spring Security源码分析-13种过滤器详解

13种核心过滤器 spring security的13个核心过滤器(按执行顺序陈列): WebAsyncManagerIntegrationFilterSecurityContextPersistenceFilterHeaderWriterFilterLogoutFilterUsernamePasswordAuthenticationFilterDefaultLoginPageGeneratingFilterDefaultLogoutPageGeneratingF…

Windows Server 2019配置DNS服务器

正文共&#xff1a;1234 字 31 图&#xff0c;预估阅读时间&#xff1a;1 分钟 我们在给Windows Server添加角色和功能时&#xff0c;会发现有一项“远程桌面服务安装”&#xff0c;它的介绍为“为虚拟桌面基础结构&#xff08;Virtual Desktop Infrastructure&#xff0c;VDI&…

java处理16进制字符串的一些方法和基础知识

前言&#xff1a;本篇文章是对于基础数据的处理的一些简单经验总结里边包含了一些基础的数据储存和数据转化的一些知识&#xff0c;同样也包含有部分快捷的数据处理方法。主要用于个人知识的一个记录和方便进行对应的数据转换和处理。 1、bit,字节和字的关系 1.1 bit和字节的…

怎么注册微商城?开启微商城之旅

在这个数字化时代&#xff0c;微商城的出现为商家提供了一个全新的机会&#xff0c;商家企业可以通过微商城来展示和销售自己的产品。而对于一些商家而言&#xff0c;不知道怎么注册微商城。下面给大家做一个简单的分享。 第一步&#xff1a;选择合适的微商城搭建工具 在注册…

移动通信系统关键技术多址接入OFDM学习(7)

1.OFDM是一种多载波传输方案&#xff0c;可以将高速串行传输转换为低速并行传输&#xff0c;增加符号持续时间&#xff0c;抗多径干扰能力强。 串行和并行有着不同的比特持续时间&#xff0c;同时拥有相同的数据速率。因此&#xff0c;虽然OFDM将串行信号转换为并行信号&#…

【好书推荐-第四期】《Go专家编程(第2版)》华为资深技术专家力作,第1版评分9.4,适合Go程序员面试

&#x1f60e; 作者介绍&#xff1a;我是程序员洲洲&#xff0c;一个热爱写作的非著名程序员。CSDN全栈优质领域创作者、华为云博客社区云享专家、阿里云博客社区专家博主、前后端开发、人工智能研究生。公粽号&#xff1a;程序员洲洲。 &#x1f388; 本文专栏&#xff1a;本文…