Unity3d 프로젝트를위한 행동 트리. 빌더 패턴으로 대규모 프로젝트에서 유지 관리 가능성을 최대화하기 위해 코드 중심 접근 방식으로 작성되었습니다. 유창한 행동 트리에서 영감을 얻었습니다.
특징
지원하다
궁금한 점이 있거나 도움이 필요한 경우 불화 커뮤니티에 가입하십시오.
Trello 보드의 다가오는 기능 및 개발 진행 상황을 참조하십시오.
트리를 만들 때 필요한 모든 데이터를 올바르게 캐시하기 위해 변수에 저장해야합니다.
using UnityEngine ;
using CleverCrow . Fluid . BTs . Tasks ;
using CleverCrow . Fluid . BTs . Trees ;
public class MyCustomAi : MonoBehaviour {
[ SerializeField ]
private BehaviorTree _tree ;
private void Awake ( ) {
_tree = new BehaviorTreeBuilder ( gameObject )
. Sequence ( )
. Condition ( " Custom Condition " , ( ) => {
return true ;
} )
. Do ( " Custom Action " , ( ) => {
return TaskStatus . Success ;
} )
. End ( )
. Build ( ) ;
}
private void Update ( ) {
// Update our tree every frame
_tree . Tick ( ) ;
}
}
작업 상태로 돌아 오는 것에 따라 다른 일이 발생합니다.
tree.Tick()
will restart the tree if no other nodes to runtree.Tick()
is called. A pointer reference is tracked by the tree and can only be cleared if tree.Reset()
is called. As long as your tree storage variable is set to public
or has a SerializeField
attribute. 게임이 편집기에서 실행되는 동안 트리 시각화를 인쇄 할 수 있습니다. 게임이 실행되지 않는 동안 나무를 볼 수 없습니다. 시각화하려면 나무를 건설해야합니다.
여러 줄로 행동 트리에 새 코드를 안전하게 추가 할 수 있습니다. 향후 버전 업그레이드를 지원하면서 BTS를 사용자 정의 할 수 있습니다.
using UnityEngine ;
using CleverCrow . Fluid . BTs . Tasks ;
using CleverCrow . Fluid . BTs . Tasks . Actions ;
using CleverCrow . Fluid . BTs . Trees ;
public class CustomAction : ActionBase {
protected override TaskStatus OnUpdate ( ) {
Debug . Log ( Owner . name ) ;
return TaskStatus . Success ;
}
}
public static class BehaviorTreeBuilderExtensions {
public static BehaviorTreeBuilder CustomAction ( this BehaviorTreeBuilder builder , string name = " My Action " ) {
return builder . AddNode ( new CustomAction { Name = name } ) ;
}
}
public class ExampleUsage : MonoBehaviour {
public void Awake ( ) {
var bt = new BehaviorTreeBuilder ( gameObject )
. Sequence ( )
. CustomAction ( )
. End ( ) ;
}
}
유체 행동 트리는 Unity의 패키지 관리자를 통해 사용됩니다. 이를 사용하려면 Packages/manifest.json
파일에 다음 줄을 추가해야합니다. 그 후에는 Unity의 패키지 관리자 창에서 사용중인 특정 버전의 유체 행동 트리를 시각적으로 제어 할 수 있습니다. Unity 편집기가 NPM의 패키지 레지스트리에 연결할 수 있도록이를 수행해야합니다.
{
"scopedRegistries" : [
{
"name" : " NPM " ,
"url" : " https://registry.npmjs.org " ,
"scopes" : [
" com.fluid "
]
}
],
"dependencies" : {
"com.fluid.behavior-tree" : " 2.2.0 "
}
}
특정 버전 및 릴리스 노트 아카이브는 릴리스 페이지에서 제공됩니다.
프로젝트에서 유동적 행동 트리를 사용하는 방법에 대한 작업 예제에 대한 FLAG 예제 프로젝트 캡처를보고 싶을 수도 있습니다. 그것은 깃발을 잡고 파워 업을 잡아서 우위를 얻으려고 시도하는 유닛의 실시간 사용을 보여줍니다.
프로젝트에서 유동적 행동 트리를 사용하는 방법에 대한 작업 예제에 대한 FLAG 예제 프로젝트 캡처를보고 싶을 수도 있습니다. 그것은 깃발을 잡고 파워 업을 잡아서 우위를 얻으려고 시도하는 유닛의 실시간 사용을 보여줍니다.
유체 행동 트리에는 개발 프로세스 속도를 높이는 데 도움이되는 미리 제작 된 액션, 조건, 복합재 및 기타 노드의 강력한 라이브러리가 제공됩니다.
즉시 일반적인 액션을 만들 수 있습니다. 자신이 동일한 작업을 재사용한다면 자신의 사용자 지정 작업 작성에 관한 섹션을 살펴보고 싶을 수도 있습니다.
. Sequence ( )
. Do ( " Custom Action " , ( ) => {
return TaskStatus . Success ;
} )
. End ( )
행동 트리에서 여러 가지 진드기를 건너 뜁니다.
. Sequence ( )
// Wait for 1 tick on the tree before continuing
. Wait ( 1 )
. Do ( MyAction )
. End ( )
통과 된 초가 deltaTime
에서 만료 될 때까지 기다립니다.
. Sequence ( )
. WaitTime ( 2.5f )
. Do ( MyAction )
. End ( )
즉시 일반 상태를 만들 수 있습니다. 자신이 동일한 작업을 재사용한다면 자신의 관습 조건을 작성하는 섹션을 살펴보고 싶을 수도 있습니다.
. Sequence ( )
. Condition ( " Custom Condtion " , ( ) => {
return true ;
} )
. Do ( MyAction )
. End ( )
통과 된 기회에 따라 노드를 참 또는 거짓으로 무작위로 평가합니다.
. Sequence ( )
// 50% chance this will return success
. RandomChance ( 1 , 2 )
. Do ( MyAction )
. End ( )
각 하위 노드를 순서대로 실행하고 다음 노드를 선택할 수있는 성공 상태가 기대됩니다. 실패가 반환되면 시퀀스는 자식 노드 실행을 중단하고 부모에게 실패를 반환합니다.
참고 모든 컴포지트 다음에 .End()
문을 따르는 것이 중요합니다. 이렇게하면 트리가 만들어 질 때 노드가 올바르게 중첩되어 있는지 확인합니다.
. Sequence ( )
. Do ( ( ) => { return TaskStatus . Success ; } )
. Do ( ( ) => { return TaskStatus . Success ; } )
// All tasks after this will not run and the sequence will exit
. Do ( ( ) => { return TaskStatus . Failure ; } )
. Do ( ( ) => { return TaskStatus . Success ; } )
. End ( )
성공이 반환 될 때까지 각 하위 노드를 실행합니다.
. Selector ( )
// Runs but fails
. Do ( ( ) => { return TaskStatus . Failure ; } )
// Will stop here since the node returns success
. Do ( ( ) => { return TaskStatus . Success ; } )
// Does not run
. Do ( ( ) => { return TaskStatus . Success ; } )
. End ( )
셔플 알고리즘이있는 하위 노드를 무작위로 선택합니다. Success
반환되거나 모든 노드가 실패 할 때까지 보입니다. 나무가 처음에 실행되기 시작할 때마다 섞습니다.
. SelectorRandom ( )
. Do ( ( ) => { return TaskStatus . Failure ; } )
. Do ( ( ) => { return TaskStatus . Success ; } )
. Do ( ( ) => { return TaskStatus . Failure ; } )
. End ( )
Runs all child nodes at the same time until they all return Success . 실패한 노드를 종료하고 중지합니다.
. Parallel ( )
// Both of these tasks will run every frame
. Do ( ( ) => { return TaskStatus . Continue ; } )
. Do ( ( ) => { return TaskStatus . Continue ; } )
. End ( )
데코레이터는 리턴 값을 변경하기 위해 모든 노드를 감싸는 부모 요소입니다 (또는 특수 논리를 실행). 그들은 행동, 조건 및 복합재에 매우 강력하고 큰 칭찬입니다.
자신의 사용자 정의 데코레이터 코드로 모든 노드를 랩핑 할 수 있습니다. 이를 통해 재사용 가능한 기능을 사용자 정의 할 수 있습니다.
참고 : 자식 노드에서 Update()
수동으로 호출해야합니다. 그렇지 않으면 발사되지 않습니다. Also every decorator must be followed by a .End()
statement. 그렇지 않으면 나무가 올바르게 구축되지 않습니다.
. Sequence ( )
. Decorator ( " Return Success " , child => {
child . Update ( ) ;
return TaskStatus . Success ;
} )
. Do ( ( ) => { return TaskStatus . Failure ; } )
. End ( )
. Do ( ( ) => { return TaskStatus . Success ; } )
. End ( )
TaskStatus.Success
또는 TaskStatus.Failure
인 경우 하위 노드의 반환 된 상태를 되돌립니다. TaskStatus.Continue
변경하지 않습니다.
. Sequence ( )
. Inverter ( )
. Do ( ( ) => { return TaskStatus . Success ; } )
. End ( )
. End ( )
TaskStatus.Success
자녀가 TaskStatus.Failure
반환하는 경우. TaskStatus.Continue
변경하지 않습니다.
. Sequence ( )
. ReturnSuccess ( )
. Do ( ( ) => { return TaskStatus . Failure ; } )
. End ( )
. End ( )
Return TaskStatus.Failure
if the child returns TaskStatus.Success
. TaskStatus.Continue
변경하지 않습니다.
. Sequence ( )
. ReturnFailure ( )
. Do ( ( ) => { return TaskStatus . Success ; } )
. End ( )
. End ( )
Return TaskStatus.Continue
regardless of what status the child returns. This decorator (and all descendent tasks) can be interrupted by calling BehaviorTree.Reset()
.
. Sequence ( )
. RepeatForever ( )
. Do ( ( ) => { return TaskStatus . Success ; } )
. End ( )
. End ( )
Return TaskStatus.Failure
if the child returns TaskStatus.Failure
, otherwise it returns TaskStatus.Continue
.
. Sequence ( )
. RepeatUntilFailure ( )
. Do ( ( ) => { return TaskStatus . Success ; } )
. End ( )
. End ( )
return TaskStatus.Success
child가 TaskStatus.Success
를 반환하면 TaskStatus.Continue
반환합니다.
. Sequence ( )
. RepeatUntilSuccess ( )
. Do ( ( ) => { return TaskStatus . Success ; } )
. End ( )
. End ( )
나무는 단지 몇 줄의 코드와 결합 될 수 있습니다. 이를 통해 검색 또는 공격과 같은 복잡한 기능을 위해 다른 노드를 번들로 연결하는 주사 가능한 동작 트리를 만들 수 있습니다.
접합 나무는 노드가 .Build()
에 깊이 복사되므로 주입을 위해 새로 제작 된 나무가 필요하다는 경고를받습니다.
using CleverCrow . Fluid . BTs . Trees ;
using CleverCrow . Fluid . BTs . Tasks ;
using UnityEngine ;
public class MyCustomAi : MonoBehaviour {
private BehaviorTree _tree ;
private void Awake ( ) {
var injectTree = new BehaviorTreeBuilder ( gameObject )
. Sequence ( )
. Do ( " Custom Action " , ( ) => {
return TaskStatus . Success ;
} )
. End ( ) ;
_tree = new BehaviorTreeBuilder ( gameObject )
. Sequence ( )
. Splice ( injectTree . Build ( ) )
. Do ( " Custom Action " , ( ) => {
return TaskStatus . Success ;
} )
. End ( )
. Build ( ) ;
}
private void Update ( ) {
// Update our tree every frame
_tree . Tick ( ) ;
}
}
유체 행동 트리를 강력하게 만드는 것은 자신의 노드를 작성하여 소스를 편집하지 않고 빌더에 추가하는 기능입니다. 새로운 빌더 기능을 추가하는 Unity 패키지를 만들 수도 있습니다. 예를 들어, 우리는 이와 같은 새로운 트리 빌더 메소드를 작성하여 AI 시스템의 목표를 몇 줄로 설정합니다.
var tree = new BehaviorTreeBuilder ( gameObject )
. Sequence ( )
. AgentDestination ( " Find Enemy " , target )
. Do ( ( ) => {
// Activate chase enemy code
return TaskStatus . Success ;
} )
. End ( )
. Build ( ) ;
첫 번째 사용자 정의 작업을 만들고 구현하는 데 약 3 분이 걸립니다. 먼저 새로운 액션을 만듭니다.
using CleverCrow . Fluid . BTs . Tasks ;
using CleverCrow . Fluid . BTs . Tasks . Actions ;
using UnityEngine ;
using UnityEngine . AI ;
public class AgentDestination : ActionBase {
private NavMeshAgent _agent ;
public Transform target ;
protected override void OnInit ( ) {
_agent = Owner . GetComponent < NavMeshAgent > ( ) ;
}
protected override TaskStatus OnUpdate ( ) {
_agent . SetDestination ( target . position ) ;
return TaskStatus . Success ;
}
}
다음으로 새로운 에이전트 디스 테스트 조치로 BehaviorTreeBuilder
스크립트를 확장해야합니다. C# 클래스 확장에 대한 자세한 내용은 공식 문서를 참조하십시오.
using CleverCrow . Fluid . BTs . Trees ;
public static class BehaviorTreeBuilderExtensions {
public static BehaviorTreeBuilder AgentDestination ( this BehaviorTreeBuilder builder , string name , Transform target ) {
return builder . AddNode ( new AgentDestination {
Name = name ,
target = target ,
} ) ;
}
}
그리고 당신은 끝났습니다! 이제 새로운 버전을 위해 미래의 증거가있는 사용자 정의 작업 및 확장 가능한 동작 트리 빌더를 만들었습니다. 다음 예제는 더 동일합니다. 그러나 각각은 다른 노드 유형을 다룹니다.
다음 템플릿으로 고유 한 사용자 정의 작업을 만들 수 있습니다. 이것은 지속적으로 사용하는 코드를 번들링하는 데 유용합니다.
using UnityEngine ;
using CleverCrow . Fluid . BTs . Tasks ;
using CleverCrow . Fluid . BTs . Tasks . Actions ;
public class CustomAction : ActionBase {
// Triggers only the first time this node is run (great for caching data)
protected override void OnInit ( ) {
}
// Triggers every time this node starts running. Does not trigger if TaskStatus.Continue was last returned by this node
protected override void OnStart ( ) {
}
// Triggers every time `Tick()` is called on the tree and this node is run
protected override TaskStatus OnUpdate ( ) {
// Points to the GameObject of whoever owns the behavior tree
Debug . Log ( Owner . name ) ;
return TaskStatus . Success ;
}
// Triggers whenever this node exits after running
protected override void OnExit ( ) {
}
}
새 노드를 확장자에 추가하십시오.
using CleverCrow . Fluid . BTs . Trees ;
public static class BehaviorTreeBuilderExtensions {
public static BehaviorTreeBuilder CustomAction ( this BehaviorTreeBuilder builder , string name = " My Action " ) {
return builder . AddNode ( new CustomAction {
Name = name ,
} ) ;
}
}
다음 예제 템플릿과 함께 사용자 정의 조건을 추가 할 수 있습니다. AI가 위치로 이동할 수있는 경우 시력과 같은 수표 및 복잡한 점검이 필요한 기타 작업을 사용하려면이를 사용하고 싶을 것입니다.
using UnityEngine ;
using CleverCrow . Fluid . BTs . Tasks ;
public class CustomCondition : ConditionBase {
// Triggers only the first time this node is run (great for caching data)
protected override void OnInit ( ) {
}
// Triggers every time this node starts running. Does not trigger if TaskStatus.Continue was last returned by this node
protected override void OnStart ( ) {
}
// Triggers every time `Tick()` is called on the tree and this node is run
protected override bool OnUpdate ( ) {
// Points to the GameObject of whoever owns the behavior tree
Debug . Log ( Owner . name ) ;
return true ;
}
// Triggers whenever this node exits after running
protected override void OnExit ( ) {
}
}
다음 스 니펫으로 동작 트리 빌더에 새 조건을 추가하십시오.
using CleverCrow . Fluid . BTs . Trees ;
public static class BehaviorTreeBuilderExtensions {
public static BehaviorTreeBuilder CustomCondition ( this BehaviorTreeBuilder builder , string name = " My Condition " ) {
return builder . AddNode ( new CustomCondition {
Name = name ,
} ) ;
}
}
유체 행동 트리는 맞춤형 동작 및 조건에만 국한되지 않습니다. 상당히 간단한 API로 새로운 복합 유형을 만들 수 있습니다. 다음은 기본 순서의 예입니다.
using CleverCrow . Fluid . BTs . TaskParents . Composites ;
using CleverCrow . Fluid . BTs . Tasks ;
public class CustomSequence : CompositeBase {
protected override TaskStatus OnUpdate ( ) {
for ( var i = ChildIndex ; i < Children . Count ; i ++ ) {
var child = Children [ ChildIndex ] ;
var status = child . Update ( ) ;
if ( status != TaskStatus . Success ) {
return status ;
}
ChildIndex ++ ;
}
return TaskStatus . Success ;
}
}
동작 트리에 맞춤 복합재를 추가하는 것은 동작을 추가하는 것만 큼 간단합니다. 한 줄의 코드를 가져갑니다.
using CleverCrow . Fluid . BTs . Trees ;
public static class BehaviorTreeBuilderExtensions {
public static BehaviorTreeBuilder CustomSequence ( this BehaviorTreeBuilder builder , string name = " My Sequence " ) {
return builder . ParentTask < CustomSequence > ( name ) ;
}
}
데코레이터는 또한 반복적 인 코드를 줄이기 위해 사용자 정의로 작성 될 수 있습니다.
using CleverCrow . Fluid . BTs . Decorators ;
using CleverCrow . Fluid . BTs . Tasks ;
public class CustomInverter : DecoratorBase {
protected override TaskStatus OnUpdate ( ) {
if ( Child == null ) {
return TaskStatus . Success ;
}
var childStatus = Child . Update ( ) ;
var status = childStatus ;
switch ( childStatus ) {
case TaskStatus . Success :
status = TaskStatus . Failure ;
break ;
case TaskStatus . Failure :
status = TaskStatus . Success ;
break ;
}
return status ;
}
}
데코레이터 구현은 복합재와 유사합니다. 합성물에 인수를 설정 해야하는 경우 Method BehaviorTreeBuilder.AddNodeWithPointer()
에서 전리품을 사용해야합니다.
using CleverCrow . Fluid . BTs . Trees ;
public static class BehaviorTreeBuilderExtensions {
public static BehaviorTreeBuilder CustomInverter ( this BehaviorTreeBuilder builder , string name = " My Inverter " ) {
// See BehaviorTreeBuilder.AddNodeWithPointer() if you need to set custom composite data from arguments
return builder . ParentTask < CustomInverter > ( name ) ;
}
}
자동 포맷터를 사용하는 경우 Builder Syntax와 함께 코드 서식을 관리 할 수 있습니다. 이를 피하기 위해 JetBrains 라이더에서 So와 같은 서식을 끄십시오. 특정 IDE가 필요한 경우 Google에 너무 어렵지 않아야합니다. 특정 서식을 비활성화하여 필요한 의견을 비활성화합니다.
// @formatter:off
_tree = new BehaviorTreeBuilder ( gameObject )
. Sequence ( )
. Condition ( " Custom Condition " , ( ) => {
return true ;
} )
. Do ( " Custom Action " , ( ) => {
return TaskStatus . Success ;
} )
. End ( )
. Build ( ) ;
// @formatter:on
패키지 관리자 친화적 인 develop
의 야간 빌드에 액세스하려면 Packages/manifest.json
수동으로 편집해야합니다.
{
"dependencies" : {
"com.fluid.behavior-tree" : " https://github.com/ashblue/fluid-behavior-tree.git#nightly "
}
}
새로운 야간 빌드를 얻으려면 매니페스트 의이 라인과 관련 잠금 데이터를 삭제해야합니다. Unity Rebuild를 다시 추가 한 다음 다시 추가하십시오. Unity가 git URL의 커밋 해시를 패키지로 잠그십시오.
개발 환경을 실행하려면 Node.js를 설치해야합니다. 그런 다음 루트에서 다음을 한 번 실행하십시오.
npm install
If you wish to create a build run npm run build
from the root and it will populate the dist
folder.
All commits should be made using Commitizen (which is automatically installed when running npm install
). 커밋은 릴리스시 버전 번호로 자동 컴파일되므로 매우 중요합니다. Commitizen 기반 커밋이없는 PR은 거부됩니다.
커밋 유형을 루트에서 터미널에 유형으로 만들려면
npm run commit
자세한 내용은 기고 가이드 라인 문서를 참조하십시오.
이 멋진 사람들에게 감사합니다 (이모티콘 키) :
애쉬 블루 | Jesse Talavera-Greenberg | PuresaltProductions ? | 마틴 duvergey ? | 콜 스택 ? | Piotr Jastzebski | Sounghoo |
tnthomas ? | 소유자 | angstr0m ? | 이지 ? | 예레미 밴스크 |
이 프로젝트는 All-Contritors 사양을 따릅니다. 모든 종류의 공헌을 환영합니다!
이 멋진 사람들에게 감사합니다 (이모티콘 키) :
이 프로젝트는 All-Contritors 사양을 따릅니다. 모든 종류의 공헌을 환영합니다!