Unity学习日志番外:简易行为树

Unity简单行为树

      • 参考与代码来自b站-ANVER-大佬
      • 教学视频
      • 以下都是一种固定模板结构,便于外部以及新项目引用。
      • 1.BehaviorTree类
      • 2.Node类
      • 3.composite
      • 4.Sequence
      • 5.Selector
      • 6.Task
      • 7.Blackboard
      • 8.实例
        • ①兔子行为树
        • ②巡逻任务
        • ③探测萝卜任务
        • ③吃萝卜任务
      • 个人对行为树的理解

参考与代码来自b站-ANVER-大佬

教学视频

以下都是一种固定模板结构,便于外部以及新项目引用。

1.BehaviorTree类

一个BehaviorTree应该包括:
1.Node节点的定义与声明。

2.Blackboard充当大脑用于存储string映射到object的键值对,因为object是所有类型的基类,在转化的过程中会产生很多的拆装箱影响性能,不过由于行为树本身就不是什么庞大(1e6甚至更多那种)底层由哈希表实现在没有哈希冲突的前提下是O(1)的时间复杂度,又由于数据范围很小所以基本不会哈希碰撞,哈希碰撞会导致时间复杂度提高到O(n)。
3.类似状态机结构中的玩家脚本,行为树脚本也是直接挂载在主物体身上的,所以在结构上需要有Blackboard,以及任务或者树的初始状态,类似状态机一开始是处于IdleState,并且在awake的时候获取它和声明它们。
5.在Update里初始化的方法应该是根节点的评估方法。


using JetBrains.Annotations;
using UnityEngine;namespace BehaviourTrees
{[RequireComponent(typeof(Blackboard))]public class BehaviourTree : MonoBehaviour{private Node root;public Node Root{get => root;protected set => root = value;}private Blackboard blackboard;[UsedImplicitly]private void Awake(){blackboard = GetComponent<Blackboard>();OnSetup();}public Blackboard Blackboard{get => blackboard;set => blackboard = value;}[UsedImplicitly]// Update is called once per framevoid Update(){root?.Evaluate(gameObject.transform, blackboard);}protected virtual void OnSetup(){}}
}

2.Node类

一个Node类应该包括:
1.currentState目前的状态{Failure = 0, Success, Running}。
2.该节点的父节点以及该节点的子节点。
3.评估节点状态逻辑函数。

using System;
using System.Collections.Generic;
using UnityEngine;namespace BehaviourTrees
{public enum Status{Failure = 0,Success,Running}public abstract class Node{protected Node parent;protected List<Node> children = new List<Node>();public Status status { get; protected set; }public Status Evaluate(Transform agent, Blackboard blackboard){status = OnEvaluate(agent, blackboard);return status;}protected abstract Status OnEvaluate(Transform agent, Blackboard blackboard);}}

3.composite

复合结构直接继承于Node用于被Sequence和Selector继承

4.Sequence

Sequence:Sequence的逻辑是AND,要求当前队列下的所有子节点都要是Success才返回success否者返回Failure,如果还在执行返回Running。

using System.Collections.Generic;
using System.Linq;
using UnityEngine;namespace BehaviourTrees
{public class Sequencer : Composite{public Sequencer(List<Node> children){this.children = children;}protected override Status OnEvaluate(Transform agent, Blackboard blackboard){bool isRunning = false;bool success = children.All((child) =>{Status status = child.Evaluate(agent, blackboard);switch (status){case Status.Failure:return false;case Status.Running:isRunning = true;break;}return status == Status.Success;});return isRunning ? Status.Running : success ? Status.Success : Status.Failure;}}
}

5.Selector

Selector:一个Selector的逻辑是or,要求当前队列下的所有子节点都要是failure才返回Failure否者返回Success,如果还在执行返回Running。

using System.Collections.Generic;
using System.Linq;
using UnityEngine;namespace BehaviourTrees
{public class Selector : Composite{public Selector(List<Node> children){this.children = children;}protected override Status OnEvaluate(Transform agent, Blackboard blackboard){bool isRunning = false;bool failed = children.All((child) =>{Status status = child.Evaluate(agent, blackboard);if (status == Status.Running) isRunning = true;return status == Status.Failure;});return isRunning ? Status.Running : failed ? Status.Failure : Status.Success;}}
}

6.Task

Task继承于Node应该对Node中的评估方法Evaluate进行重写,用于描述挂载脚本物体的逻辑。

7.Blackboard

using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting.YamlDotNet.Core.Tokens;
using UnityEngine;namespace BehavioursTree
{public class Blackboard : MonoBehaviour{private Dictionary<string, object> data = new Dictionary<string, object>();public T Get<T>(string key){if (data.TryGetValue(key, out object value)) return (T)value;return default(T);}public void Add<T>(string key, T value){data.Add(key, value);}public bool Remove<T>(string key){if (data.ContainsKey(key)){data.Remove(key);return true;}return false;}}
}

8.实例

①兔子行为树
using BehaviourTrees;
using System.Linq;
using UnityEngine;public class RabbitBehaviourTree : BehaviourTree
{[SerializeField] private Transform[] waypoints = null;[SerializeField] private float speed = 10.0f;protected override void OnSetup(){Blackboard.Add("speed", speed);var patrolTask = new PatrolTask(waypoints);var seeCarrotTask = new SeeCarrotTask();var catchCarrotTask = new CatchCarrotTask();Node[] sequencerChildren = { seeCarrotTask, catchCarrotTask };var sequencer = new Sequencer(sequencerChildren.ToList());Node[] selectorChildren = { sequencer, patrolTask };var selector = new Selector(selectorChildren.ToList());Root = selector;}
}
AWAKEprivate void Awake(){blackboard = GetComponent<Blackboard>();OnSetup();}
UPDATEvoid Update(){root?.Evaluate(gameObject.transform, blackboard);}

在这里插入图片描述

这里的兔子行为树定做了:
1.声明巡逻任务。
2.声明探测到萝卜任务。
3.声明吃萝卜任务。
4.声明一个Sequence包含两个子节点①探测到萝卜②吃萝卜。
5.声明一个Seletor包含两个子节点①Sequence②巡逻。

②巡逻任务
using BehaviourTrees;
using UnityEngine;public class PatrolTask : Task
{private int currentIndex;private Transform[] waypoints;public PatrolTask(Transform[] waypoints){this.waypoints = waypoints;currentIndex = 0;}protected override Status OnEvaluate(Transform agent, Blackboard blackboard){float speed = blackboard.Get<float>("speed");Transform currentWaypoint = waypoints[currentIndex];bool arrived = Vector2.Distance(agent.position, currentWaypoint.position) < 0.1f;if (arrived){// update current index++currentIndex;currentIndex %= waypoints.Length;}agent.position = Vector2.MoveTowards(agent.position, currentWaypoint.position, speed * Time.deltaTime);return Status.Running;}
}

巡逻任务包括1:n个巡逻点可以通过Inspector拖动赋值。
2:评估的主要逻辑。

③探测萝卜任务
using System.Collections;
using System.Collections.Generic;
using BehaviourTrees;
using UnityEngine;public class SeeCarrotTask : Task
{private float radius = 2.0f;protected override Status OnEvaluate(Transform agent, Blackboard blackboard){var colliders = Physics2D.OverlapCircleAll(agent.position, radius);if (colliders == null) return Status.Failure;foreach (Collider2D collider in colliders){if (!collider.CompareTag("Carrot")) continue;blackboard.Add("carrot", collider.gameObject);return Status.Success;}return Status.Failure;}
}

探测萝卜任务应该包括:
1.探测半径。

③吃萝卜任务
using System.Collections;
using System.Collections.Generic;
using BehaviourTrees;
using UnityEngine;public class CatchCarrotTask : Task
{protected override Status OnEvaluate(Transform agent, Blackboard blackboard){var carrot = blackboard.Get<GameObject>("carrot");var speed = blackboard.Get<float>("speed");if (carrot == null) return Status.Failure;if (Vector2.Distance(agent.position, carrot.transform.position) <= 0.01f)return Status.Success;Vector2 position = Vector2.MoveTowards(agent.position, carrot.transform.position, speed * Time.deltaTime);position.y = agent.position.y;agent.position = position;return Status.Running;}
}

吃萝卜逻辑:
检测之前在探测萝卜任务中加入到大脑的萝卜object,使用Movetowards进行两点间的移动。

个人对行为树的理解

**行为树的核心机制就是每一帧从根节点开始遍历其子节点,并根据子节点的状态调用对应的 Evaluate 方法。这种行为树的运行方式是典型的深度优先遍历,并且是基于帧的更新(Frame-based Update)。**在这个案例中Selector含有对Sequence和巡逻Task的引用,遍历的顺序就是:注意箭头顺序
在这里插入图片描述
Selector->{Sequence{找萝卜 -> 吃萝卜} -> 巡逻} -> 循环

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【SpringBoot】MD5加盐算法的详解

目录 一、什么是加盐算法 二、如何实现加盐算法 2.1 加盐算法代码实现 2.2 注册页面中进行密码加盐 2.3 登录页面进行加盐的解密 2.4 注册和登录 一、什么是加盐算法 加盐算法是一种用于增强密码安全性的技术。这种技术通过在密码存储过程中添加一个随机生成的盐值&…

【Linux学习笔记】Linux用户和文件权限的深度剖析

【Linux学习笔记】Linux用户和文件权限的深度剖析 &#x1f525;个人主页&#xff1a;大白的编程日记 &#x1f525;专栏&#xff1a;Linux学习笔记 前言 文章目录 【Linux学习笔记】Linux用户和文件权限的深度剖析前言一. Linux权限管理1.1 文件访问者的分类&#xff08;人)…

MinIO问题总结(持续更新)

目录 Q: 之前使用正常&#xff0c;突然使用空间为0B&#xff0c;上传文件也是0B&#xff08;部署在k8s中&#xff09;Q: 无法上传大文件参考yaml Q: 之前使用正常&#xff0c;突然使用空间为0B&#xff0c;上传文件也是0B&#xff08;部署在k8s中&#xff09; A: 1、检查pod状态…

c语言经典基础编程题

c语言经典基础编程题 一、输出输出1.1温度输出1.2排齐数据1.3进制转换 二、选择分支2.1求最大值2.2成绩评定2.3分段函数求值2.4 利润计算2.5判断闰年2.6二次方程根 三、循环结构3.1倒数求和3.2最大数3.3判断素数3.4判断完全数3.5打印菱形&#x1f680;&#x1f680;&#x1f68…

[多线程]基于阻塞队列(Blocking Queue)的生产消费者模型的实现

标题&#xff1a;[多线程]基于阻塞队列(Blocking Queue)的生产消费者模型的实现 水墨不写bug 文章目录 一、生产者消费者模型特点&#xff1a;二、实现2.1详细解释1. 成员变量2. 构造函数3. Isfull 和 Isempty4. Push 函数5. Pop 函数6. 析构函数7. GetSize 函数 三、总结与多线…

在vs中无法用QtDesigner打开ui文件的解决方法

解决方法 右键ui文件&#xff0c;选择打开方式&#xff0c;弹出如下界面。 点击添加&#xff0c;弹出如下界面 点击程序后边的三个点&#xff0c;去电脑查找designer.exe,我的位置为D:\Qt\Qt5.9.9\5.9.9\msvc2015_64\bin\designer.exe。 名称可以自己起一个名字&#xff0c…

[内网渗透] 红日靶场2

环境配置 靶场地址: http://vulnstack.qiyuanxuetang.net/vuln/wiki/ 环境配置可以看这个: https://www.bilibili.com/video/BV1De4y1a7Ps/?spm_id_from333.337.search-card.all.click&vd_sourcecf73ac8de9b7c0322b1bccf77de91c5dNAT模式分配111段, DHCP也要更改 再添加…

第八节:红黑树(初阶)

【本节要点】 红黑树概念红黑树性质红黑树结点定义红黑树结构红黑树插入操作的分析 一、红黑树的概念与性质 1.1 红黑树的概念 红黑树 &#xff0c;是一种 二叉搜索树 &#xff0c;但 在每个结点上增加一个存储位表示结点的颜色&#xff0c;可以是 Red和 Black 。 通过对 任何…

基于Spring Boot的网上蛋糕售卖店管理系统的设计与实现(LW+源码+讲解)

专注于大学生项目实战开发,讲解,毕业答疑辅导&#xff0c;欢迎高校老师/同行前辈交流合作✌。 技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;…

哈尔滨算力服务器托管推荐-青蛙云

哈尔滨年平均气温3.5摄氏度&#xff0c;有发展云计算和算力数据中心的天然优势 &#xff0c;今天为哈尔滨算力服务器托管服务商&#xff1a;青蛙云&#xff0c;黑龙江经营17年的老牌IDC服务商。 先来了解下算力服务器&#xff1a; 算力服务器&#xff0c;尤其是那些用于运行人…

关于Linux contOS 7 的防火墙

centos7 通过firewall-cmd命令添加防火墙白名单 。 查看防护墙状态 firewall-cmd --state 或 systemctl status firewalld active (running)-->表示防火墙已经开启&#xff1b;inactive (dead)-->表示防火墙已经关闭 开关防火墙命令 启动防火墙&#xff1a;systemctl …

【openGauss】物理备份恢复

文章目录 1. gs_backup&#xff08;1&#xff09;备份&#xff08;2&#xff09;恢复&#xff08;3&#xff09;手动恢复的办法 2. gs_basebackup&#xff08;1&#xff09;备份&#xff08;2&#xff09;恢复① 伪造数据目录丢失② 恢复 3. gs_probackup&#xff08;1&#xf…

MySql学习_基础Sql语句

目录 1.数据库相关概念 2.SQL 2.1 SQL通用语法 2.2 SQL分类 2.3 DDL&#xff08;数据库定义语言&#xff09; 2.4 DML&#xff08;数据操作语言&#xff09; 2.5 DQL&#xff08;数据查询语言&#xff09; 2.6 DCL&#xff08;数据控制语言&#xff09; 3. 函数 3.1 字…

MAE:Masked Autoencoders Are Scalable Vision Learners——论文学习

论文地址&#xff1a;https://arxiv.org/pdf/2111.06377.pdf 官方源码&#xff1a;https://github.com/facebookresearch/mae 一、主要内容 本文证明了掩码自编码器(MAE)是一种可扩展的计算机视觉自监督学习算法。本文的MAE方法很简单:屏蔽输入图像的随机补丁并重建缺失的像素…

【C++标准库类型】深入理解C++中的using声明:从基础到实践

目录 一、using声明基础 1.1 基本语法形式 1.2 典型应用场景 1.3 作用域规则 二、关键注意事项 2.1 命名冲突处理 2.2 头文件使用规范 2.3 与typedef的对比 三、面向对象中的应用 3.1. 解除派生类名称隐藏&#xff08;核心应用&#xff09; 3.2. 构造函数继承&#…

VSTO(C#)Excel开发6:与窗体交互

初级代码游戏的专栏介绍与文章目录-CSDN博客 我的github&#xff1a;codetoys&#xff0c;所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。 这些代码大部分以Linux为目标但部分代码是纯C的&#xff0c;可以在任何平台上使用。 源码指引&#xff1a;github源…

微服务Sentinel组件:服务保护详解

目录 服务保护简介 服务保护方案 安装与介绍Sentinel Sentinel整合微服务 服务保护实现 请求限流 线程隔离 OpenFeign整合Sentinel 配置线程隔离 服务熔断 编写降级逻辑 实现服务熔断 服务保护总结 服务保护简介 微服务保护是为了保障系统整体的稳定性和可靠性&am…

计算机视觉|首次写入政府工作报告!这个科技新词“具身智能”到底是什么?

一、具身智能与视觉-动作联合建模简介 具身智能&#xff08;Embodied Intelligence&#xff09; 是人工智能领域的关键研究方向&#xff0c;强调智能体通过物理实体与环境交互实现认知和智能行为。与传统人工智能基于静态数据和符号推理不同&#xff0c;具身智能依赖动态感知与…

【Azure 架构师学习笔记】- Azure Databricks (18) --Delta Live Table 架构

本文属于【Azure 架构师学习笔记】系列。 本文属于【Azure Databricks】系列。 接上文 【Azure 架构师学习笔记】- Azure Databricks (17) --Delta Live Table和Delta Table Databrics DLT 是一个ETL 框架&#xff0c;通过创建pipeline来简化开发难度&#xff0c;本文介绍两种D…

上下文学习思维链COTPrompt工程

一、上下文学习 上下文学习强调在学习过程中考虑问题所处的上下文环境。 1.1 上下文学习的分类 零样本&#xff08;Zero-Shot&#xff09;上下文学习单样本&#xff08;One-Shot&#xff09;上下文学习少样本&#xff08;Few-Shot&#xff09;上下文学习 1.2 示例选择方法 …