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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM