व्यवहार करने वाले पेड़


25

मैं व्यवहार वृक्षों के आसपास अपना सिर लाने का प्रयास कर रहा हूं, इसलिए मैं कुछ परीक्षण कोड निकाल रहा हूं। एक चीज जो मैं संघर्ष कर रहा हूं वह यह है कि वर्तमान में चल रहे नोड को कैसे प्राथमिकता दी जाए जब कुछ उच्च प्राथमिकता के साथ आता है।

एक सैनिक के लिए निम्नलिखित सरल, काल्पनिक व्यवहार पेड़ पर विचार करें:

यहाँ छवि विवरण दर्ज करें

मान लीजिए कि कुछ टिक टिक गए हैं और पास में कोई दुश्मन नहीं है, सैनिक घास पर खड़ा था, इसलिए सिट डाउन नोड को निष्पादन के लिए चुना गया है:

यहाँ छवि विवरण दर्ज करें

अब बैठो कार्रवाई को निष्पादित करने में समय लगता है क्योंकि खेलने के लिए एक एनीमेशन है, इसलिए यह Runningइसकी स्थिति के रूप में वापस आता है । एक टिक या दो से जाता है, एनीमेशन अभी भी चल रहा है, लेकिन दुश्मन के पास? हालत नोड चलाता है। अब हमें एसिट डाउन नोड एएसएपी को पूर्व निर्धारित करने की आवश्यकता है ताकि हम हमला नोड को निष्पादित कर सकें । आदर्श रूप से सिपाही नीचे बैठकर भी पूरा नहीं करेगा - वह अपनी एनिमेशन दिशा को उलट सकता है यदि वह केवल बैठना शुरू कर दे। अतिरिक्त यथार्थवाद के लिए, यदि वह एनीमेशन में कुछ टिपिंग बिंदु से आगे है, तो हम उसके बजाय उसे नीचे बैठने के लिए चुन सकते हैं और उसके बाद फिर से खड़े हो सकते हैं, या शायद उसे धमकी पर प्रतिक्रिया देने के लिए जल्दबाजी में ठोकर खा सकते हैं।

जैसा मैं कर सकता हूं, कोशिश करें कि मैं इस तरह की स्थिति को संभालने के लिए मार्गदर्शन नहीं पा सका हूं। पिछले कुछ दिनों में जितने भी साहित्य और वीडियो मैंने खाए हैं (और यह बहुत हो चुके हैं) इस मुद्दे पर घिरे हुए हैं। निकटतम चीज़ जो मैं खोजने में सक्षम रहा हूँ, यह नोड्स को रीसेट करने की अवधारणा है, लेकिन इससे नोड्स को बैठने का मौका नहीं मिलता है "अरे, मैंने अभी तक काम नहीं किया है!"

मैंने शायद अपने आधार वर्ग पर एक विधि Preempt()या Interrupt()पद्धति को परिभाषित करने के बारे में सोचा Node। अलग-अलग नोड्स इसे संभाल सकते हैं कि वे कैसे फिट देखते हैं, लेकिन इस मामले में हम सैनिक को अपने पैरों पर ASAP और फिर वापस लाने का प्रयास करेंगे Success। मुझे लगता है कि इस दृष्टिकोण की भी आवश्यकता होगी कि मेरे आधार Nodeमें अन्य कार्यों के लिए अलग से शर्तों की अवधारणा है। इस तरह, इंजन केवल स्थितियों की जांच कर सकता है, और यदि वे पास हो जाते हैं, तो कार्रवाई के निष्पादन शुरू करने से पहले किसी भी समय निष्पादित नोड को पूर्व निर्धारित कर सकते हैं। यदि यह भेदभाव स्थापित नहीं किया गया था, तो इंजन को अंधाधुंध तरीके से नोड्स को निष्पादित करने की आवश्यकता होगी और इसलिए चल रहे एक को हटाने से पहले एक नई कार्रवाई को ट्रिगर कर सकता है।

संदर्भ के लिए, नीचे मेरी वर्तमान आधार कक्षाएं हैं। फिर से, यह एक स्पाइक है, इसलिए मैंने चीजों को यथासंभव सरल रखने का प्रयास किया है और जब मुझे इसकी आवश्यकता होती है तो केवल जटिलता को जोड़ता है, और जब मैं इसे समझता हूं, जो कि मैं अभी से संघर्ष कर रहा हूं।

public enum ExecuteResult
{
    // node needs more time to run on next tick
    Running,

    // node completed successfully
    Succeeded,

    // node failed to complete
    Failed
}

public abstract class Node<TAgent>
{
    public abstract ExecuteResult Execute(TimeSpan elapsed, TAgent agent, Blackboard blackboard);
}

public abstract class DecoratorNode<TAgent> : Node<TAgent>
{
    private readonly Node<TAgent> child;

    protected DecoratorNode(Node<TAgent> child)
    {
        this.child = child;
    }

    protected Node<TAgent> Child
    {
        get { return this.child; }
    }
}

public abstract class CompositeNode<TAgent> : Node<TAgent>
{
    private readonly Node<TAgent>[] children;

    protected CompositeNode(IEnumerable<Node<TAgent>> children)
    {
        this.children = children.ToArray();
    }

    protected Node<TAgent>[] Children
    {
        get { return this.children; }
    }
}

public abstract class ConditionNode<TAgent> : Node<TAgent>
{
    private readonly bool invert;

    protected ConditionNode()
        : this(false)
    {
    }

    protected ConditionNode(bool invert)
    {
        this.invert = invert;
    }

    public sealed override ExecuteResult Execute(TimeSpan elapsed, TAgent agent, Blackboard blackboard)
    {
        var result = this.CheckCondition(agent, blackboard);

        if (this.invert)
        {
            result = !result;
        }

        return result ? ExecuteResult.Succeeded : ExecuteResult.Failed;
    }

    protected abstract bool CheckCondition(TAgent agent, Blackboard blackboard);
}

public abstract class ActionNode<TAgent> : Node<TAgent>
{
}

क्या किसी के पास कोई अंतर्दृष्टि है जो मुझे सही दिशा में आगे बढ़ा सकती है? क्या मेरी सोच सही लाइनों के साथ है, या यह उतना ही भोला है जितना मुझे डर है?


आपको इस दस्तावेज़ पर एक नज़र डालने की आवश्यकता है: chrishecker.com/My_liner_notes_for_spore/… यहाँ वह बताते हैं कि पेड़ को कैसे चलाया जाता है, राज्य मशीन की तरह नहीं, बल्कि प्रत्येक टिक पर ROOT से, जो कि प्रतिक्रियात्मकता की सच्ची चाल है। बीटी को अपवाद या घटनाओं की आवश्यकता नहीं होनी चाहिए। वे पूलिंग सिस्टम को आंतरिक रूप से करते हैं, और सभी स्थितियों के लिए प्रतिक्रिया करते हैं जो हमेशा रूट से नीचे बहने के लिए धन्यवाद करते हैं। जो कि प्रीमेप्टिविटी काम करता है, अगर उच्च प्राथमिकता की बाहरी स्थिति की जांच होती है, तो यह वहां बहती है। ( Stop()सक्रिय नोड्स से बाहर निकलने से पहले कुछ कॉलबैक कहते हैं)
v.oddou

यह aigamedev.com/open/article/popular-behavior-tree-design भी बहुत अच्छी तरह से विस्तृत है
v.oddou

जवाबों:


6

मैंने अपने आप से एक ही सवाल पूछते हुए पाया और इस ब्लॉग पेज के कमेंट सेक्शन में मेरी बहुत कम बातचीत हुई जहाँ मुझे समस्या का एक और समाधान प्रदान किया गया।

पहली बात समवर्ती नोड का उपयोग करना है। समवर्ती नोड एक विशेष प्रकार का मिश्रित नोड है। इसमें एकल कार्रवाई नोड के बाद पूर्व शर्त चेक के अनुक्रम शामिल हैं। यह सभी बच्चों के नोड्स को अपडेट करता है, भले ही यह एक्शन नोड 'रनिंग' स्थिति में हो। (अनुक्रम नोड के विपरीत जो इसे चालू होने वाले बच्चे के नोड से अपडेट होना चाहिए।)

मुख्य विचार एक्शन नोड्स के लिए दो और रिटर्न स्टेट्स बनाना है: "रद्द करना" और "रद्द करना"।

समवर्ती नोड में पूर्व-निर्धारण जांच में विफलता एक तंत्र है जो इसे रद्द करने वाले एक्शन नोड को चलाता है। यदि एक्शन नोड को लंबे समय तक चलने वाले रद्द करने वाले तर्क की आवश्यकता नहीं है, तो यह तुरंत 'रद्द' हो जाएगा। अन्यथा यह 'रद्द' स्थिति में बदल जाता है जहां आप कार्रवाई के सही व्यवधान के लिए सभी आवश्यक तर्क रख सकते हैं।


नमस्कार और GDSE में आपका स्वागत है। यह बहुत अच्छा होगा, यदि आप उस ब्लॉग से उस उत्तर को यहाँ और उस ब्लॉग के अंतिम लिंक में खोल सकते हैं। लिंक्स मरते हैं, यहाँ पूरी तरह से उत्तर देते हैं, इसे और अधिक स्थायी बनाता है। प्रश्न में अभी 8 वोट हैं, इसलिए अच्छा उत्तर भयानक होगा।
काटू

मैं ऐसा कुछ भी नहीं सोचता, जो व्यवहार के पेड़ को परिमित अवस्था में लाए, एक अच्छा उपाय है। आपका दृष्टिकोण मुझे ऐसा लगता है जैसे आपको प्रत्येक राज्य की सभी निकास स्थितियों की कल्पना करने की आवश्यकता है। जब यह वास्तव में FSM की खामी है! बीटी को रूट पर वापस शुरू करने का लाभ है, यह पूरी तरह से जुड़ा हुआ एफएसएम है, जो हमें स्पष्ट रूप से बाहर निकलने की स्थिति लिखने के लिए टालता है।
v.oddou

5

मुझे लगता है कि आपके सैनिक को मन और शरीर (और जो कुछ भी) में विघटित किया जा सकता है। इसके बाद, शरीर को पैरों और हाथों में विघटित किया जा सकता है। फिर, प्रत्येक भाग को अपने स्वयं के व्यवहार के पेड़ की आवश्यकता होती है, और उच्च या निचले स्तर के हिस्सों के अनुरोधों के लिए - सार्वजनिक इंटरफ़ेस भी।

इसलिए, हर एक क्रिया को माइक्रो-मैनेज करने के बजाय, आप सिर्फ "बॉडी, कुछ समय के लिए बैठें" या "बॉडी, वहां दौड़ें" जैसे इंस्टेंट-शॉट संदेश भेजें, और बॉडी एनिमेशन, स्टेट ट्रांज़िशन, देरी और अन्य सामान को प्रबंधित करेगा आप।

वैकल्पिक रूप से, शरीर अपने आप से इस तरह के व्यवहार का प्रबंधन कर सकता है। यदि इसका कोई आदेश नहीं है, तो यह मन से पूछ सकता है "क्या हम यहां बैठ सकते हैं?"। अधिक दिलचस्प बात यह है कि एनकैप्सुलेशन के कारण, आप आसानी से थकावट या अचेत होना जैसी सुविधाओं को मॉडल कर सकते हैं।

आप भागों को इंटरचेंज भी कर सकते हैं - ज़ोंबी की बुद्धि के साथ हाथी बनाएं, मानव को पंख जोड़ें (वह भी नोटिस नहीं करेगा), या जो भी हो।

इस तरह के विघटन के बिना, मैं शर्त लगाता हूं कि आपको दहनशील विस्फोट, जल्द या बाद में मिलने का खतरा है।

इसके अलावा: http://www.valvesoftware.com/publications/2009/ai_systems_of_l4d_mike_booth.pdf


धन्यवाद। आपके उत्तर को 3 बार पढ़ने के बाद, मुझे लगता है कि मैं समझ गया हूं। मैं इस सप्ताह के अंत में पीडीएफ पढ़ूंगा।
मी -

1
पिछले एक घंटे से इस बारे में सोचने के बाद, मुझे यकीन नहीं है कि मैं मन और शरीर के लिए पूरी तरह से अलग बीटी होने के बीच के अंतर को समझता हूं। एक बीटी जो उप-पेड़ों में विघटित है (विशेष सज्जाकार के माध्यम से संदर्भित, बिल्ड-टाइम स्क्रिप्ट के साथ सब कुछ एक साथ एक बड़ी बीटी में बांधना)। मुझे ऐसा लगता है कि यह समान अमूर्त लाभ प्रदान करेगा और वास्तव में यह समझना आसान बना सकता है कि किसी दिए गए इकाई का व्यवहार कैसा है क्योंकि आपको कई अलग-अलग बीटी में नहीं देखना है। हालाँकि, मैं शायद भोली हूँ।
मी -

@ user13414 अंतर यह है कि आपको पेड़ बनाने के लिए विशेष लिपियों की आवश्यकता होगी, जब सिर्फ अप्रत्यक्ष पहुंच का उपयोग करना (यानी जब शरीर नोड को अपने पेड़ से पूछना होगा कि कौन सी वस्तु पैरों का प्रतिनिधित्व करती है) पर्याप्त हो सकती है और इसके लिए किसी अतिरिक्त ब्रेनफक की आवश्यकता नहीं होगी। कम कोड, कम त्रुटियाँ। इसके अलावा, आप रनटाइम में (आसानी से) स्विच सबट्री की क्षमता खो देंगे। यहां तक ​​कि अगर आपको इस तरह के लचीलेपन की आवश्यकता नहीं है, तो आप कुछ भी नहीं खो सकते हैं (निष्पादन गति सहित)।
शैडो इन रेन

3

कल रात बिस्तर पर लेटते हुए, मुझे इस बात का आभास हुआ कि जिस जटिलता के बारे में मैं अपने प्रश्न की ओर झुकाव कर रहा था, उसे पेश किए बिना मैं इस बारे में कैसे जा सकता हूं। इसमें (खराब नाम वाला, IMHO) "समांतर" समग्र का उपयोग शामिल है। यहाँ मैं सोच रहा हूँ:

यहाँ छवि विवरण दर्ज करें

उम्मीद है कि यह अभी भी काफी पठनीय है। महत्वपूर्ण बिंदु हैं:

  • बैठ जाओ / देरी / खड़े हो अनुक्रम एक समानांतर अनुक्रम (भीतर एक दृश्य है एक )। हर टिक पर, समानांतर अनुक्रम भी शत्रु को स्थिति (उलटा) के पास जाँच रहा है । यदि एक दुश्मन है पास, हालत विफल रहता है और तो भी पूरे समानांतर अनुक्रम करता है (तुरंत, भले ही बच्चे अनुक्रम के माध्यम से रास्ते के मध्य में है सिट डाउन , देरी , या खड़े हो )
  • असफलता पर, समानांतर अनुक्रम के ऊपर चयनकर्ता बी रुकावट को संभालने के लिए चयनकर्ता सी में नीचे कूद जाएगा । महत्वपूर्ण बात यह है कि चयनकर्ता C समानांतर क्रम A को सफलतापूर्वक पूरा करने पर नहीं चलेगा
  • चयनकर्ता सी तो सामान्य रूप से खड़े होने की कोशिश करता है, लेकिन एक ठोकर एनीमेशन को भी ट्रिगर कर सकता है अगर सैनिक वर्तमान में बहुत अजीब है तो बस खड़े होने की स्थिति में है

मुझे लगता है कि यह काम करेगा (जल्द ही अपने स्पाइक में इसे आजमाने जा रहा हूं), मैंने परिकल्पना की तुलना में थोड़ा अधिक गन्दा होने के बावजूद। अच्छी बात यह है कि मैं अंततः उप-पेड़ों को तर्क के पुन: प्रयोज्य टुकड़ों के रूप में संलग्न कर सकता हूं और उन्हें कई बिंदुओं से संदर्भित कर सकता हूं। वह मेरी अधिकांश चिंता को दूर कर देगा, इसलिए मुझे लगता है कि यह एक व्यवहार्य समाधान है।

बेशक, मैं अभी भी सुनना पसंद करूँगा अगर किसी को इस पर कोई विचार है।

अद्यतन : हालांकि यह दृष्टिकोण तकनीकी रूप से काम करता है, मैंने इसे सक्सेक्स किया है। ऐसा इसलिए है क्योंकि पेड़ के अन्य भागों में परिभाषित शर्तों के बारे में असंबंधित उप-पेड़ों को "पता" करने की आवश्यकता है ताकि वे अपनी उपज को ट्रिगर कर सकें। जब भी उप-वृक्ष संदर्भ साझा करते हैं, तो इस दर्द को कम करने का कोई तरीका होगा, यह अभी भी विपरीत है कि व्यवहार के पेड़ को देखकर क्या उम्मीद है। वास्तव में, मैंने एक ही सरल स्पाइक पर दो बार वही गलती की।

इसलिए, मैं अन्य मार्ग से नीचे जा रहा हूं: ऑब्जेक्ट मॉडल के भीतर प्रीपेप्टिंग के लिए स्पष्ट समर्थन, और एक विशेष समग्र जो प्रीएम्प्शन होने पर कार्यों के एक अलग सेट को निष्पादित करने की अनुमति देता है। जब मैं कुछ काम करूंगा तो एक अलग जवाब दूंगा।


1
यदि आप वास्तव में उपशीर्षक का फिर से उपयोग करना चाहते हैं तो कब (यहाँ "शत्रु के पास") को बाधित करने के लिए तर्क को उप-भाग का हिस्सा नहीं होना चाहिए। इसके बजाय शायद सिस्टम किसी भी सबट्री (उदाहरण के लिए बी) से पूछ सकता है कि उच्च-प्राथमिकता वाले उत्तेजना के कारण खुद को बाधित करने के लिए, और फिर यह एक विशेष रूप से चिह्नित रुकावट नोड (सी यहां) पर कूद जाएगा जो चरित्र को कुछ मानक स्थिति में वापस लाने में सक्षम होगा। , जैसे खड़े। व्यवहार के पेड़ की तरह एक बिट अपवाद से निपटने के बराबर है।
नाथन रीड

1
आप भी कई रुकावट संचालकों को शामिल कर सकते हैं जो इस बात पर निर्भर करता है कि उत्तेजना किस बाधा है। उदाहरण के लिए यदि NPC बैठी है और आग लेना शुरू कर रही है, तो आप नहीं चाह सकते कि वह (और बड़े लक्ष्य को प्रस्तुत करे) बल्कि कवर के लिए कम और हाथापाई में रहे।
नाथन रीड

@ नथन: मज़ेदार आप "अपवाद हैंडलिंग" के बारे में उल्लेख करते हैं। पिछली रात मैंने जो पहला संभव तरीका सोचा था, वह एक प्रीमेच कम्पोजिट का विचार था, जिसमें दो बच्चे होंगे: एक सामान्य निष्पादन के लिए, और एक पहले से निष्पादित निष्पादन के लिए। यदि सामान्य बच्चा पास या फेल हो जाता है, तो वह परिणाम फैल जाता है। प्रीमेप्ड बच्चा केवल तभी चलेगा जब प्रीमेप्शन हुआ हो। सभी नोड्स में एक Preempt()विधि होगी, जो पेड़ से टकराएगी। हालांकि, वास्तव में "हैंडल" करने के लिए एकमात्र चीज यह प्रीमेच कम्पोजिट होगी, जो तुरंत अपने प्रीमेच्योर चाइल्ड नोड में बदल जाएगी।
me--

तब मुझे लगा कि मैं ऊपर के समानांतर दृष्टिकोण के बारे में सोच रहा हूं, और यह अधिक सुरुचिपूर्ण लग रहा था क्योंकि इसके लिए पूरे एपीआई में अतिरिक्त cruft की आवश्यकता नहीं है। उप-वृक्षों को घेरने की आपकी बात पर, मुझे लगता है कि जहाँ भी जटिलता उत्पन्न होती है, वह एक संभव प्रतिस्थापन बिंदु होगा। यहां तक ​​कि यह भी हो सकता है कि आपके पास कई शर्तें हैं जिन्हें अक्सर एक साथ जांचा जाता है। उस स्थिति में, प्रतिस्थापन की जड़ एक अनुक्रम संमिश्र होगी, जिसमें उसके बच्चों के रूप में कई स्थितियां होंगी।
me--

मुझे लगता है कि निष्पादित करने से पहले "हिट" करने के लिए आवश्यक परिस्थितियों को जानकर सबटाइटल पूरी तरह से उचित है क्योंकि यह उन्हें आत्म निहित और बहुत स्पष्ट बनाम निहित बनाता है। अगर यह एक बड़ी चिंता है, तो शर्तों को सबट्री में न रखें, बल्कि "कॉल साइट" पर रखें।
सीवान

2

यहाँ समाधान मैं अब के लिए पर बस गया है ...

  • मेरे बेस Nodeक्लास में एक Interruptविधि है, जो डिफ़ॉल्ट रूप से, कुछ भी नहीं करता है
  • स्थितियाँ "प्रथम श्रेणी" का निर्माण करती हैं, इसमें उन्हें वापस लौटने की आवश्यकता होती है bool(इस प्रकार कि वे निष्पादन के लिए तेज़ हैं और कभी भी एक से अधिक अपडेट की आवश्यकता नहीं है)
  • Node बाल नोड्स के अपने संग्रह के लिए अलग से शर्तों के संग्रह को उजागर करता है
  • Node.Executeसभी शर्तों को पहले निष्पादित करता है और यदि कोई भी स्थिति विफल होती है तो सीधे विफल हो जाता है। यदि स्थितियां सफल होती हैं (या कोई भी नहीं हैं), ExecuteCoreतो यह कॉल करता है ताकि उपवर्ग अपना वास्तविक काम कर सके। एक पैरामीटर है जो शर्तों को लंघन की अनुमति देता है, उन कारणों के लिए जिन्हें आप नीचे देखेंगे
  • Nodeएक CheckConditionsविधि के माध्यम से भी अलगाव में स्थितियों को निष्पादित करने की अनुमति देता है । बेशक, Node.Executeवास्तव में सिर्फ कॉल करता है CheckConditionsजब इसे शर्तों को मान्य करने की आवश्यकता होती है
  • मेरा Selectorसमग्र अब CheckConditionsप्रत्येक बच्चे के लिए कहता है जिसे वह निष्पादन के लिए मानता है। यदि स्थितियां विफल हो जाती हैं, तो यह अगले बच्चे के साथ सीधे चलती है। यदि वे पास होते हैं, तो यह जांचता है कि क्या पहले से ही एक निष्पादित बच्चा है। यदि हां, तो यह कॉल करता है Interruptऔर फिर विफल हो जाता है। यह सब इस बिंदु पर कर सकता है, इस उम्मीद में कि वर्तमान में चल रहा नोड रुकावट के अनुरोध का जवाब देगा, जो यह कर सकता है ...
  • मैंने एक Interruptibleनोड जोड़ा है, जो एक विशेष डेकोरेटर की तरह है क्योंकि इसमें अपने सजाए गए बच्चे के रूप में तर्क का नियमित प्रवाह है, और फिर रुकावटों के लिए एक अलग नोड है। यह अपने नियमित बच्चे को पूरा करने या विफलता के लिए निष्पादित करता है जब तक कि यह बाधित न हो। यदि यह बाधित है, तो यह तुरंत अपने रुकावट को संभालने के लिए स्विच करता है बाल नोड, जो आवश्यक के रूप में एक उप-पेड़ जटिल हो सकता है

अंतिम परिणाम कुछ इस तरह है, मेरे स्पाइक से लिया गया:

यहाँ छवि विवरण दर्ज करें

ऊपर एक मधुमक्खी के लिए व्यवहार का पेड़ है, जो अमृत एकत्र करता है और इसे अपने छत्ते में वापस करता है। जब इसका कोई अमृत नहीं है और यह एक फूल के पास नहीं है जिसमें कुछ है, तो यह भटकता है:

यहाँ छवि विवरण दर्ज करें

यदि यह नोड इंटरप्टेबल नहीं होता तो यह कभी भी विफल नहीं होता, इसलिए मधुमक्खी हमेशा के लिए भटक जाती। हालाँकि, चूंकि मूल नोड एक चयनकर्ता है और इसमें उच्च प्राथमिकता वाले बच्चे हैं, इसलिए निष्पादन के लिए उनकी पात्रता की लगातार जाँच की जा रही है। यदि उनकी स्थितियां पास हो जाती हैं, तो चयनकर्ता एक रुकावट उठाता है और उप-पेड़ तुरंत "बाधित" पथ पर स्विच करता है, जो बस ASAP को विफल कर देता है। यह, निश्चित रूप से, पहले कुछ अन्य क्रियाएं कर सकता है, लेकिन मेरे स्पाइक में वास्तव में जमानत के अलावा कुछ भी नहीं है।

हालांकि, आप मेरे प्रश्न पर वापस टाई करने के लिए, आप कल्पना कर सकते हैं कि "बाधित" पथ नीचे बैठे एनीमेशन को उलटने का प्रयास कर सकता है और, असफल होने पर, सैनिक ठोकर खा सकता है। यह सब उच्च प्राथमिकता वाले राज्य में संक्रमण को बनाए रखेगा, और ठीक यही लक्ष्य था।

मुझे लगता है कि मैं इस दृष्टिकोण से खुश हूं - विशेष रूप से मुख्य टुकड़े जिन्हें मैंने ऊपर उल्लिखित किया है - लेकिन ईमानदार होने के लिए, यह शर्तों और कार्यों के विशिष्ट कार्यान्वयन के प्रसार के बारे में और प्रश्न उठाता है, और व्यवहार ट्री को एनीमेशन सिस्टम में बांधता है। मुझे यकीन नहीं है कि मैं अभी तक इन सवालों को स्पष्ट कर सकता हूं, इसलिए मैं सोच / विचार कर रहूंगा।


1

मैंने "जब" डेकोरेटर का आविष्कार करके एक ही मुद्दा तय किया। इसमें एक शर्त और दो बच्चे का व्यवहार ("फिर" और "अन्यथा") है। जब "जब" निष्पादित होता है, तो यह स्थिति की जांच करता है और इसके परिणाम पर निर्भर करता है, तब / अन्यथा बच्चा चलाता है। यदि परिणाम में परिवर्तन होता है, तो चल रहे बच्चे को रीसेट किया जाता है और अन्य शाखा के अनुरूप बच्चे को शुरू किया जाता है। यदि बच्चा निष्पादन समाप्त करता है, तो पूरे "जब" निष्पादन को पूरा करता है।

मुख्य बिंदु यह है कि इस प्रश्न में प्रारंभिक बीटी के विपरीत, जहां स्थिति केवल अनुक्रम प्रारंभ में जाँच की जाती है, मेरा "जब" चालू होने के दौरान स्थिति की जाँच करता रहता है। इसलिए, व्यवहार वृक्ष के शीर्ष को इसके साथ बदल दिया गया है:

When[EnemyNear]
  Then
    AttackSequence
  Otherwise
    When[StandingOnGrass]
      Then
        IdleSequence
      Otherwise
        Hum a tune

अधिक उन्नत "जब" उपयोग के लिए, कोई "प्रतीक्षा" कार्रवाई भी शुरू करना चाहेगा जो कि निर्दिष्ट समय के लिए या अनिश्चित काल तक (माता-पिता के व्यवहार द्वारा रीसेट होने तक) कुछ भी नहीं करता है। इसके अलावा, यदि आपको "जब" की केवल एक शाखा की आवश्यकता होती है, तो अन्य में "सफलता" या "विफल" क्रियाएं शामिल हो सकती हैं, जो संबंधित तुरंत सफल हो जाती हैं।


मुझे लगता है कि यह दृष्टिकोण बीटी के मूल आविष्कारों को ध्यान में रखते हुए करीब है। यह एक अधिक गतिशील प्रवाह का उपयोग करता है, यही वजह है कि बीटी में "रनिंग" राज्य एक बहुत ही खतरनाक स्थिति है, जिसका उपयोग बहुत कम ही किया जाना चाहिए। हमें बीटी को हमेशा किसी भी समय रूट पर वापस आने की संभावना को ध्यान में रखना चाहिए।
v.oddou

0

जबकि मुझे देर हो चुकी है, लेकिन आशा है कि यह मदद कर सकता है। ज्यादातर क्योंकि मैं यह सुनिश्चित करना चाहता हूं कि मैंने व्यक्तिगत रूप से खुद को कुछ याद नहीं किया है क्योंकि मैं यह जानने की कोशिश कर रहा हूं। मैंने ज्यादातर इस विचार को उधार लिया है Unreal, लेकिन इसे बिना Decoratorआधार के, संपत्ति को आधार बनाकर Nodeया Blackboardइसके साथ मजबूती से जुड़ा हुआ है , यह अधिक सामान्य है।

यह एक नया नोड प्रकार पेश करेगा जिसे Guardएक के संयोजन की तरह कहा जाता है Decorator, और Compositeएक के condition() -> Resultसाथ एक हस्ताक्षर हैupdate() -> Result

यह इंगित करने के लिए तीन तरीके हैं कि Guardरिटर्न देते समय कैसे रद्द किया जाना चाहिए Successया Failed, कॉलिंग पर वास्तविक रद्द करना निर्भर करता है। तो एक Selectorकॉलिंग के लिए Guard:

  1. रद्द करें .self -> केवल Guard(और उसके चल रहे बच्चे) को रद्द करें यदि यह चल रहा है और स्थिति थीFailed
  2. रद्द करें .lower-> केवल निम्न प्राथमिकता वाले नोड्स को रद्द करें यदि वे चल रहे हैं और स्थिति थी SuccessयाRunning
  3. रद्द करें .both -> दोनों .selfऔर .lowerस्थितियों और चलने वाले नोड्स के आधार पर। आप स्वयं को रद्द करना चाहते हैं यदि इसके चलने और चलने की स्थिति को falseरद्द या रद्द कर देंगे, यदि वे Compositeनियम ( Selectorहमारे मामले में) के आधार पर कम प्राथमिकता पर विचार करते हैं यदि शर्त है Success। दूसरे शब्दों में, यह मूल रूप से दोनों अवधारणाएं संयुक्त हैं।

जैसा Decoratorऔर विपरीत Compositeयह केवल एक भी बच्चे को ले जाता है।

हालांकि Guardकेवल कई के रूप में एक भी बच्चे हैं, तो आप कर सकते हैं घोंसला ले Sequences, Selectorsया अन्य प्रकार के Nodesरूप में आप चाहते, सहित अन्य Guardsया Decorators

Selector1 Guard.both[Sequence[EnemyNear?]] Sequence1 MoveToEnemy Attack Selector2 Sequence2 StandingOnGrass? Idle HumATune

ऊपर दिए गए परिदृश्य में, जब भी Selector1अपडेट होता है, यह हमेशा अपने बच्चों से जुड़े गार्ड पर कंडीशन चेक चलाएगा। उपरोक्त मामले में, Sequence1संरक्षित है और कार्यों के Selector1साथ जारी रखने से पहले जाँच की जानी चाहिए running

जब भी Selector2या Sequence1जैसे ही चल रहा है EnemyNear?रिटर्न successएक के दौरान Guards condition()उसके बाद चेक Selector1व्यवधान जारी करेगा / करने के लिए रद्द कर running nodeऔर फिर हमेशा की तरह जारी है।

दूसरे शब्दों में, हम "निष्क्रिय" या "हमला" शाखा पर प्रतिक्रिया कर सकते हैं कुछ शर्तों के आधार पर व्यवहार को और अधिक प्रतिक्रियाशील बना देता है अगर हम पर बसे Parallel

यह आपको सिंगल गार्ड की भी अनुमति देता है जिसमें समान Nodeचलाने के खिलाफ उच्च प्राथमिकता हैNodesComposite

Selector1 Guard.both[Sequence[EnemyNear?]] Sequence1 MoveToEnemy Attack Selector2 Guard.both[StandingOnGrass?] Idle HumATune

यदि HumATuneएक लंबे समय से चल रहा है Node, Selector2तो हमेशा की जाँच करेगा कि अगर यह पहले नहीं था Guard। इसलिए अगर अगली बार npc एक घास के पैच पर टेलीपोर्ट हो जाता है Selector2, तो यह रन करने के लिए जाँच करेगा Guardऔर रद्द कर देगाHumATuneIdle

यह teleported हो जाता है बाहर घास पैच की, इसे चलाने नोड (रद्द हो जाएगा Idle) और को स्थानांतरितHumATune

जैसा कि आप यहाँ देख रहे हैं, निर्णय लेने वाले के कॉल करने वाले पर निर्भर करता है Guardन कि Guardखुद पर। जिसे माना जाता है उसके नियम lower priorityकॉलर के साथ बने रहते हैं। दोनों उदाहरणों में, यह वह है Selectorजो परिभाषित करता है कि एक के रूप में क्या बनता है lower priority

यदि आपके पास एक Compositeबुलाया गया था Random Selector, तो आपको उस विशिष्ट के कार्यान्वयन के भीतर नियमों को परिभाषित करना होगा Composite

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.