أشجار السلوك لمشاريع unity3d. مكتوبة مع نهج مدفوع رمز لزيادة قابلية الصيانة في المشاريع الكبيرة مع نمط البناء. مستوحاة من شجرة السلوك بطلاقة.
سمات
يدعم
انضم إلى مجتمع Discord إذا كان لديك أسئلة أو تحتاج إلى مساعدة.
انظر الميزات القادمة وتقدم التطوير على لوحة 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()
Next Tree.tick (tree.Tick()
. يتم تتبع مرجع المؤشر بواسطة الشجرة ولا يمكن مسحه إلا إذا تم استدعاء tree.Reset()
. طالما تم تعيين متغير تخزين الأشجار الخاص بك على public
أو يحتوي على سمة SerializeField
. ستتمكن من طباعة تصور لشجرتك أثناء تشغيل اللعبة في المحرر. لاحظ أنه لا يمكنك عرض الأشجار أثناء عدم تشغيل اللعبة. كما يجب بناء الشجرة من أجل تصور.
يمكنك إضافة رمز جديد بأمان إلى أشجار سلوكك بعدة أسطر. السماح لك بتخصيص 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 ( ) ;
}
}
يتم استخدام شجرة سلوك السوائل من خلال مدير حزمة الوحدة. من أجل استخدامه ، ستحتاج إلى إضافة الأسطر التالية إلى ملف Packages/manifest.json
. بعد ذلك ، ستتمكن من التحكم بصريًا في إصدار محدد من شجرة سلوك السوائل التي تستخدمها من نافذة Manager Package في الوحدة. يجب القيام بذلك حتى يتمكن محرر الوحدة الخاص بك من الاتصال بسجل حزمة NPM.
{
"scopedRegistries" : [
{
"name" : " NPM " ,
"url" : " https://registry.npmjs.org " ,
"scopes" : [
" com.fluid "
]
}
],
"dependencies" : {
"com.fluid.behavior-tree" : " 2.2.0 "
}
}
تتوفر أرشيف الإصدارات المحددة وملاحظات الإصدار على صفحة الإصدارات.
قد ترغب في إلقاء نظرة على مشروع Capture the Flag Example للحصول على مثال عملي على كيفية استخدام شجرة سلوك السوائل في مشروعك. إنه يوضح الاستخدام في الوقت الفعلي مع الوحدات التي تحاول التقاط العلم أثناء الاستيلاء على الطاقة لمحاولة الحصول على اليد العليا.
قد ترغب في إلقاء نظرة على مشروع Capture the Flag Example للحصول على مثال عملي على كيفية استخدام شجرة سلوك السوائل في مشروعك. إنه يوضح الاستخدام في الوقت الفعلي مع الوحدات التي تحاول التقاط العلم أثناء الاستيلاء على الطاقة لمحاولة الحصول على اليد العليا.
تأتي شجرة سلوك السوائل مع مكتبة قوية من الإجراءات والظروف والمركبات وغيرها من العقد الأخرى للمساعدة في تسريع عملية التطوير الخاصة بك.
يمكنك إنشاء إجراء عام أثناء الطيران. إذا وجدت نفسك تعيد استخدام نفس الإجراءات التي قد ترغب في النظر في القسم الخاص بكتابة الإجراءات المخصصة الخاصة بك.
. 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 ( )
يدير جميع العقد الفرعية في نفس الوقت حتى يعودوا جميعًا النجاح . يخرج ويوقف جميع العقد الجري إذا كان أي منها يعيد فشل .
. Parallel ( )
// Both of these tasks will run every frame
. Do ( ( ) => { return TaskStatus . Continue ; } )
. Do ( ( ) => { return TaskStatus . Continue ; } )
. End ( )
الديكورون هم عناصر أولياء الأمور التي تلتف أي عقدة لتغيير قيمة الإرجاع (أو تنفيذ منطق خاص). إنها قوية للغاية ومجاملة كبيرة للإجراءات والظروف والمركبات.
يمكنك لف أي عقدة برمز الديكور المخصص الخاص بك. هذا يتيح لك تخصيص وظائف قابلة لإعادة الاستخدام.
ملاحظة : يجب عليك الاتصال يدويًا Update()
على عقدة الطفل أو لن تطلق النار. أيضا يجب أن يتبع كل ديكور .End()
. وإلا فإن الشجرة لن تبني بشكل صحيح.
. 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 ( )
إرجاع TaskStatus.Failure
إذا كان الطفل يعيد TaskStatus.Success
. لا يغير TaskStatus.Continue
.
. Sequence ( )
. ReturnFailure ( )
. Do ( ( ) => { return TaskStatus . Success ; } )
. End ( )
. End ( )
إرجاع TaskStatus.Continue
بغض النظر عن الحالة التي يعيدها الطفل. يمكن مقاطعة هذا الديكور (وجميع مهام المنحدر) عن طريق استدعاء BehaviorTree.Reset()
.
. Sequence ( )
. RepeatForever ( )
. Do ( ( ) => { return TaskStatus . Success ; } )
. End ( )
. End ( )
إرجاع TaskStatus.Failure
إذا كان الطفل يعيد TaskStatus.Failure
، وإلا فإنه يعيد TaskStatus.Continue
.
. Sequence ( )
. RepeatUntilFailure ( )
. Do ( ( ) => { return TaskStatus . Success ; } )
. End ( )
. End ( )
إرجاع TaskStatus.Success
إذا كان الطفل يعيد 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 ( ) ;
}
}
ما يجعل شجرة سلوك السوائل قوية للغاية هو القدرة على كتابة العقد الخاصة بك وإضافتها إلى المنشئ دون تحرير أي مصدر. يمكنك حتى إنشاء حزم الوحدة التي تضيف وظائف منشئ جديدة. على سبيل المثال ، يمكننا كتابة طريقة منشئ الأشجار الجديدة مثل هذه التي تحدد هدف نظام الذكاء الاصطناعي مع بضعة أسطر من التعليمات البرمجية.
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
من خلال عمل AgentDestation الجديد. لمزيد من المعلومات حول ملحقات الفئة 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 ,
} ) ;
}
}
يمكن إضافة الظروف المخصصة مع قالب المثال التالي. ستحتاج إلى استخدام هذه الفحوصات مثل البصر ، إذا كان بإمكان الذكاء الاصطناعي الانتقال إلى موقع ، والمهام الأخرى التي تتطلب فحصًا معقدًا.
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 ,
} ) ;
}
}
لا تقتصر شجرة سلوك السوائل على الإجراءات والظروف المخصصة. يمكنك إنشاء أنواع مركبة جديدة مع واجهة برمجة تطبيقات بسيطة إلى حد ما. فيما يلي مثال على التسلسل الأساسي.
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 ) ;
}
}
إذا كنت تستخدم تنسيقًا تلقائيًا ، فمن المحتمل أن يتم تنسيق الكود الخاص بك مع بناء جملة البناء. لتجنب ذلك ، يمكنك إيقاف التنسيق مثل ذلك في Rider Jetbrains. إذا كنت بحاجة إلى IDE محددة ، فلا ينبغي أن يكون من الصعب جدًا على Google تعليق تعطيل التنسيق المحدد الذي تحتاجه.
// @formatter:off
_tree = new BehaviorTreeBuilder ( gameObject )
. Sequence ( )
. Condition ( " Custom Condition " , ( ) => {
return true ;
} )
. Do ( " Custom Action " , ( ) => {
return TaskStatus . Success ;
} )
. End ( )
. Build ( ) ;
// @formatter:on
للوصول إلى بنيات Nightly من develop
والتي هي ودية مديرة الحزمة ، ستحتاج إلى تحرير Packages/manifest.json
يدويًا.
{
"dependencies" : {
"com.fluid.behavior-tree" : " https://github.com/ashblue/fluid-behavior-tree.git#nightly "
}
}
لاحظ أنه للحصول على بناء ليلي أحدث ، يجب عليك حذف هذا الخط وأي بيانات قفل ذات صلة في البيان ، دع الوحدة إعادة بناء ، ثم إضافته مرة أخرى. كما الوحدة تغلق التجزئة الالتزام لعناوين URL GIT كحزم.
إذا كنت ترغب في تشغيل بيئة التطوير ، فستحتاج إلى تثبيت Node.js. ثم قم بتشغيل ما يلي من الجذر مرة واحدة.
npm install
إذا كنت ترغب في إنشاء بناء npm run build
من الجذر وسوف يملأ مجلد dist
.
يجب إجراء جميع الالتزامات باستخدام Commentizen (والتي يتم تثبيتها تلقائيًا عند تشغيل npm install
). يتم تجميع الالتزامات تلقائيًا إلى أرقام الإصدار عند الإصدار ، لذا يعد هذا أمرًا مهمًا للغاية. سيتم رفض PRS التي لا تملك الالتزامات القائمة على الالتزام.
لجعل نوع الالتزام ما يلي في محطة من الجذر
npm run commit
يرجى الاطلاع على وثيقة الإرشادات المساهمة لمزيد من المعلومات.
شكراً لهؤلاء الأشخاص الرائعين (مفتاح الرموز التعبيرية):
الرماد الأزرق | جيسي تالافيرا-جرينبرغ | puresaltproductions ؟ | مارتن دوفيرجي ؟ | مكالمة ؟ | بيوتر جاستنبسكي | سونغو |
tnthomas ؟ | ownez | Angstr0m ؟ | إيزي ؟ | جيريميفانسنيك |
يتبع هذا المشروع مواصفات جميع المساهمين. مساهمات من أي نوع ترحيب!
شكراً لهؤلاء الأشخاص الرائعين (مفتاح الرموز التعبيرية):
يتبع هذا المشروع مواصفات جميع المساهمين. مساهمات من أي نوع ترحيب!