zoukankan      html  css  js  c++  java
  • unity行为树制作AI简单例子(2)

    继续昨天的工程,给Monster添加一个空物体命名为AI,在AI添加脚本BehaviorTree,然后就可以打开行为树编辑器进行编辑了

    先写好自定义的节点脚本,下面是一个寻找漫游点的行为节点脚本

    using UnityEngine;
    using BehaviorDesigner.Runtime.Tasks;
    using BehaviorDesigner.Runtime;
    
    [TaskCategory("MyActions")]
    [TaskDescription("计算出更新的路径")]
    public class ChooseWanderPosition : Action {
    
        [BehaviorDesigner.Runtime.Tasks.Tooltip("最长距离")]
        public float wanderDistance;
    
        [BehaviorDesigner.Runtime.Tasks.Tooltip("存放目标地的变量")]
        public SharedVector3 destination;
        
        [BehaviorDesigner.Runtime.Tasks.Tooltip("自己")]
        public SharedGameObject monster;
        
        public override TaskStatus OnUpdate(){
    
            Vector3 direction = new Vector3(Random.Range(-1f, 1f), 0f, UnityEngine.Random.Range(-1f, 1f));
            direction *= wanderDistance;
            
            destination.Value = monster.Value.transform.position + direction;
            return TaskStatus.Success;
        }
    }

    [TaskCategory("MyActions")]

    指定文件的目录为MyActions,我是在Actions下新建了一个MyActions的文件夹,所以指定目录为MyActions

    其实也可以不指定,但是添加节点时就会显得杂乱

    [TaskDescription("计算出更新的路径")]

    这可以提示脚本的功能

    public的属性将会显示在面板上

    既可使用int float GameObject这种unity的类型,但缺点在于无法和其他脚本共享变量

    Shared xxx类型是插件提供的,他在整个行为树中都能使用

    使用Shared xxx类型前,必须在Variables先定义变量

    之后点击该按钮切换后就能选择全局的变量了

    最后设置如下,该节点就完成了

    [BehaviorDesigner.Runtime.Tasks.Tooltip("xxx")]是面板上变量的解释,移动到面板变量上会显示

    作为行为节点必须继承自Action并实现OnUpdate

    OnUpdate()是节点执行时要运行的代码

    接下来贴出其他要用到的行为节点

    using UnityEngine;
    using BehaviorDesigner.Runtime.Tasks;
    using BehaviorDesigner.Runtime;
    
    [TaskCategory("MyActions")]
    [TaskDescription("转向玩家")]
    public class FaceToPlayer : Action {
    
        [BehaviorDesigner.Runtime.Tasks.Tooltip("朝向的目标玩家")]
        public SharedGameObject player;
    
        [BehaviorDesigner.Runtime.Tasks.Tooltip("自己")]
        public SharedGameObject monster;
        
        public override TaskStatus OnUpdate(){
    
            Vector3 targetDir = player.Value.transform.position - monster.Value.transform.position;
            monster.Value.transform.rotation = Quaternion.LookRotation(targetDir);
            return TaskStatus.Success;
        }
    }
    using UnityEngine;
    using BehaviorDesigner.Runtime.Tasks;
    using BehaviorDesigner.Runtime;
    
    [TaskCategory("MyActions")]
    [TaskDescription("移动至漫游点")]
    public class MoveToWanderPoint : Action {
        
        [BehaviorDesigner.Runtime.Tasks.Tooltip("移动的速度")]
        public float speed = 3;
    
        [BehaviorDesigner.Runtime.Tasks.Tooltip("移动的目标点")]
        public SharedVector3 position;
    
        [BehaviorDesigner.Runtime.Tasks.Tooltip("自己")]
        public SharedGameObject monster;
        
        public override TaskStatus OnUpdate(){
    
            monster.Value.GetComponent<NavMeshAgent>().Move(position.Value);
            return TaskStatus.Success;
        }
    }
    using UnityEngine;
    using BehaviorDesigner.Runtime.Tasks;
    using BehaviorDesigner.Runtime;
    
    [TaskCategory("MyActions")]
    [TaskDescription("移动至玩家")]
    public class MoveToWanderPoint : Action {
        
        [BehaviorDesigner.Runtime.Tasks.Tooltip("移动的速度")]
        public float speed = 3;
    
        [BehaviorDesigner.Runtime.Tasks.Tooltip("移动的目标玩家")]
        public SharedGameObject player;
    
        [BehaviorDesigner.Runtime.Tasks.Tooltip("自己")]
        public SharedGameObject monster;
        
        public override TaskStatus OnUpdate(){
    
            monster.Value.GetComponent<NavMeshAgent>().Move(player.Value.transform.position);
            return TaskStatus.Success;
        }
    }

    因为移动调用了NavMeshAgent,所以我们先烘焙下场景并给Monster添加NavMeshAgent控件

    using UnityEngine;
    using BehaviorDesigner.Runtime.Tasks;
    using BehaviorDesigner.Runtime;
    
    [TaskCategory("MyActions")]
    [TaskDescription("设置怪物的基本属性")]
    public class SetInfo : Action {
        
        [BehaviorDesigner.Runtime.Tasks.Tooltip("玩家")]
        public SharedGameObject player;
    
        [BehaviorDesigner.Runtime.Tasks.Tooltip("自己")]
        public SharedGameObject monster;
        
        public override TaskStatus OnUpdate(){
    
            monster.Value = transform.parent.gameObject;
            player.Value = GameObject.FindWithTag("Player");
            return TaskStatus.Success;
        }
    }

    我们还需要自己写一个判断节点来判定玩家和怪物的距离,还需一个判断节点判断物体是否移动

    using UnityEngine;
    using BehaviorDesigner.Runtime.Tasks;
    using BehaviorDesigner.Runtime;
    
    [TaskCategory("MyConditionals")]
    [TaskDescription("判断范围内是否有玩家")]
    public class PlayerInRange : Conditional {
    
        [BehaviorDesigner.Runtime.Tasks.Tooltip("距离")]
        public float ranage;
        
        [BehaviorDesigner.Runtime.Tasks.Tooltip("判断距离的玩家")]
        public SharedGameObject player;
    
        [BehaviorDesigner.Runtime.Tasks.Tooltip("自己")]
        public SharedGameObject monster;
        
        public override TaskStatus OnUpdate(){
    
            if(Vector3.Distance(player.Value.transform.position, monster.Value.transform.position) > ranage){
    
                return TaskStatus.Failure;
            }
            return TaskStatus.Success;
        }
    }
    using UnityEngine;
    using BehaviorDesigner.Runtime.Tasks;
    using BehaviorDesigner.Runtime;
    
    [TaskCategory("MyConditionals")]
    [TaskDescription("判断对象是否移动")]
    public class NotMove : Conditional {
        
        [BehaviorDesigner.Runtime.Tasks.Tooltip("上一次的位置")]
        public Vector3 lastPosition;
    
        [BehaviorDesigner.Runtime.Tasks.Tooltip("判断的对象")]
        public SharedGameObject obj;
        
        public override TaskStatus OnUpdate(){
    
            if(obj.Value.transform.position == lastPosition){
                
                return TaskStatus.Success;
            }
            lastPosition = obj.Value.transform.position;
            return TaskStatus.Failure;
        }
    }

    依靠这些节点就可以拼出一颗行为树,一运行就可以看到一个简单的AI在运行,在攻击范围内它会攻击,在追击范围内它会追击敌人直到可以攻击,否则漫游

    红圈位置可以改变节点颜色,更容易观察行为树结构

    一些细节方面可以观看Demo

    http://git.oschina.net/yejinqi/BehaviorTreeDemo

    如果的事:http://y.qq.com/#type=song&mid=0040ZKt52jxJ6Y&play=1

  • 相关阅读:
    小心触发器脚本陷阱
    delphi程序如何防止多实例启动
    自定义控件wxIpCtrl –(Ip Address)
    wxWidgets流操作 (三) wxMemoryInputStream/wxMemoryOutputStream与wxImage交互
    D2 std.stream 文件读写小练习
    挂钟程序
    Lazarus+FPC2.7.1 下DLL 创建及调用
    正则表达式30分钟入门教程
    Word frequency program终结
    阅读作业第二篇
  • 原文地址:https://www.cnblogs.com/yuwenxiaozi/p/4881849.html
Copyright © 2011-2022 走看看