जांचें कि क्या गेम ऑब्जेक्ट का घटक नष्ट हो सकता है


11

एकता में एक खेल का विकास करना, मैं [RequireComponent(typeof(%ComponentType%))]यह सुनिश्चित करने के लिए उदार उपयोग कर रहा हूं कि घटकों को सभी निर्भरताएं मिलें।

अब मैं एक ट्यूटोरियल प्रणाली लागू कर रहा हूं जो विभिन्न UI ऑब्जेक्ट्स को हाइलाइट करता है। हाइलाइटिंग करने के लिए, मैं GameObjectदृश्य में एक संदर्भ ले रहा हूं , फिर मैं इसे तत्काल () के साथ क्लोन करता हूं और फिर उन सभी घटकों को पुन: हटा देता हूं, जिन्हें प्रदर्शन की आवश्यकता नहीं है। समस्या यह है कि RequireComponentइन घटकों के उदार उपयोग के साथ , कई को केवल किसी भी क्रम में हटाया नहीं जा सकता है, क्योंकि वे अन्य घटकों द्वारा निर्भर हैं, जिन्हें अभी तक हटाया नहीं गया है।

मेरा प्रश्न है: क्या यह निर्धारित करने का कोई तरीका है कि वर्तमान में इससे जुड़ा Componentजा सकता है या नहीं GameObject

कोड मैं तकनीकी रूप से काम कर रहा हूं, हालांकि यह यूनिटी त्रुटियों को फेंकता है (जैसा कि छवि में देखा गया है, ट्राइ-कैच ब्लॉक में नहीं पकड़ा गया है

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

यहाँ कोड है:

public void StripFunctionality(RectTransform rt)
{
    if (rt == null)
    {
        return;
    }

    int componentCount = rt.gameObject.GetComponents<Component>().Length;
    int safety = 10;
    int allowedComponents = 0;
    while (componentCount > allowedComponents && safety > 0)
    {
        Debug.Log("ITERATION ON "+rt.gameObject.name);
        safety--;
        allowedComponents = 0;
        foreach (Component c in rt.gameObject.GetComponents<Component>())
        {
            //Disable clicking on graphics
            if (c is Graphic)
            {
                ((Graphic)c).raycastTarget = false;
            }

            //Remove components we don't want
            if (
                !(c is Image) &&
                !(c is TextMeshProUGUI) &&
                !(c is RectTransform) &&
                !(c is CanvasRenderer)
                )
            {
                try
                {
                    DestroyImmediate(c);
                }
                catch
                {
                    //NoOp
                }
            }
            else
            {
                allowedComponents++;
            }
        }
        componentCount = rt.gameObject.GetComponents<Component>().Length;
    }

    //Recursive call to children
    foreach (RectTransform childRT in rt)
    {
        StripFunctionality(childRT);
    }
}

तो जिस तरह से इस कोड ने डिबग लॉग के अंतिम तीन लाइनों को उत्पन्न किया वह निम्न है: यह GameObjectदो घटकों के साथ इनपुट के रूप में लिया गया : Buttonऔर PopupOpenerPopupOpenerआवश्यकता है कि एक Buttonघटक एक ही GameObject में मौजूद है:

[RequireComponent(typeof(Button))]
public class PopupOpener : MonoBehaviour
{
    ...
}

लूप के पहले पुनरावृत्ति (पाठ "आईएआरटीएएन ऑन बटन इनवाइट (क्लोन)" द्वारा चिह्नित) को Buttonपहले हटाने का प्रयास किया गया था , लेकिन यह PopupOpenerघटक द्वारा निर्भर नहीं किया गया था । इसने एक त्रुटि फेंक दी। फिर इसने PopupOpenerघटक को हटाने का प्रयास किया , जो उसने किया, क्योंकि यह किसी और चीज पर निर्भर नहीं है। अगले पुनरावृत्ति में (दूसरे पाठ "ITERATION ON Button Invite (क्लोन)") से निरूपित, उसने शेष Buttonघटक को हटाने का प्रयास किया , जो अब वह कर सकता PopupOpenerथा , क्योंकि पहले पुनरावृत्ति (त्रुटि के बाद) में हटा दिया गया था।

तो मेरा प्रश्न यह है कि क्या समय से पहले जांच करना संभव है कि क्या एक निर्दिष्ट घटक को अपने वर्तमान से हटाया जा सकता है GameObject, बिना आह्वान के Destroy()या DestroyImmediate()। धन्यवाद।


मूल समस्या के बारे में - GUI तत्व के गैर-संवादात्मक प्रतिलिपि (= दृश्य) बनाने का लक्ष्य है?
वंदरा

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

मुझे एकता के साथ अनुभव नहीं है, लेकिन मैं सोच रहा हूं कि क्या पूरी चीज को क्लोन करने और सामान हटाने के बजाय आप केवल उन हिस्सों की नकल कर सकते हैं जिनकी आपको ज़रूरत है?
ज़ैन लिंक्स

मैंने इसका परीक्षण नहीं किया है, लेकिन Destroyफ्रेम के अंत में घटक को हटा देता है (जैसा कि Immediateगीत के विपरीत )। DestroyImmediateवैसे भी खराब शैली को माना जाता है, लेकिन मैं सोच रहा हूं कि Destroyवास्तव में इन त्रुटियों को समाप्त कर सकता हूं ।
CAD97

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

जवाबों:


9

यह निश्चित रूप से संभव है, लेकिन इसके लिए बहुत अधिक लेगवर्क की आवश्यकता होती है: आप जांच सकते हैं कि क्या कोई ऐसा Componentअटैचमेंट है GameObjectजिसके पास एक Attributeप्रकार का है RequireComponentजिसके पास अपने m_Type#खेतों में से एक है जो उस घटक प्रकार के लिए उपयुक्त है जिसे आप निकालने वाले हैं। सभी एक विस्तार विधि में लिपटे:

static class GameObjectExtensions
{
    private static bool Requires(Type obj, Type requirement)
    {
        //also check for m_Type1 and m_Type2 if required
        return Attribute.IsDefined(obj, typeof(RequireComponent)) &&
               Attribute.GetCustomAttributes(obj, typeof(RequireComponent)).OfType<RequireComponent>()
               .Any(rc => rc.m_Type0.IsAssignableFrom(requirement));
    }

    internal static bool CanDestroy(this GameObject go, Type t)
    {
        return !go.GetComponents<Component>().Any(c => Requires(c.GetType(), t));
    }
}

GameObjectExtensionsपरियोजना में कहीं भी छोड़ने के बाद (या वैकल्पिक रूप से इसे स्क्रिप्ट पर एक नियमित विधि बनाते हैं), आप जांच सकते हैं कि क्या कोई घटक हो सकता है जैसे:

rt.gameObject.CanDestroy(c.getType());

उदाहरण के लिए, बनावट के लिए यह प्रतिपादन, लगभग पारदर्शी पैनल के साथ यह डालने क्लिक्स रोकना होगा जो या - लेकिन वहाँ संयुक्त राष्ट्र-सहभागी जीयूआई वस्तु बनाने के लिए अन्य साधनों हो सकता है अक्षम करने (बजाय नष्ट करने का) सब Componentसे पाने रहा है MonoBehaviourया IPointerClickHandler


धन्यवाद! मैं सोच रहा था कि क्या एक तैयार समाधान एकता के साथ जहाज है, लेकिन मुझे नहीं लगता :) आपके कोड के लिए धन्यवाद!
लियाम लाइम

@LiamLime ठीक है, मैं वास्तव में पुष्टि नहीं कर सकता कि कोई भी निर्मित नहीं है, लेकिन यह संभव नहीं है क्योंकि विशिष्ट एकता प्रतिमान कोड दोष (यानी catch, लॉग जारी रखें) दोष (यानी ifसंभव, तब) को रोकने के बजाय बना रहा है । हालांकि, यह बहुत सी # शैली नहीं है (जैसे कि इस उत्तर में एक)। अंत में आपका मूल कोड इस बात के करीब हो सकता है कि चीजें आम तौर पर कैसे की जाती हैं ... और सबसे अच्छा अभ्यास व्यक्तिगत पसंद का मामला है।
वंद्रा

7

क्लोन पर घटकों को हटाने के बजाय, आप बस उन .enabled = falseपर सेटिंग करके उन्हें अक्षम कर सकते हैं। यह निर्भरता जांच को ट्रिगर नहीं करेगा, क्योंकि एक घटक को निर्भरता को पूरा करने के लिए सक्षम होने की आवश्यकता नहीं है।

  • जब कोई व्यवहार अक्षम होता है, तब भी वह ऑब्जेक्ट पर होगा और आप इसके गुणों को बदल सकते हैं और इसके तरीकों को कॉल कर सकते हैं, लेकिन इंजन अब इसकी Updateविधि को कॉल नहीं करेगा ।
  • जब कोई रेंडरर अक्षम होता है, तो वस्तु अदृश्य हो जाती है।
  • जब एक कोलाइडर अक्षम होता है, तो यह किसी भी टक्कर की घटनाओं का कारण नहीं होगा।
  • जब कोई UI घटक अक्षम होता है, तो खिलाड़ी अब इसके साथ इंटरैक्ट नहीं कर सकता है, लेकिन इसे तब भी रेंडर किया जाएगा, जब तक कि आप इसके रेंडर को निष्क्रिय नहीं करते।

घटकों में सक्षम या अक्षम की धारणा नहीं है। व्यवहार, कोलाइडर और कुछ अन्य प्रकार के होते हैं। तो यह प्रोग्रामर को विभिन्न उपवर्गों के लिए GetComponent को कई कॉल करने की आवश्यकता होगी।
डबियसपुशर 21
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.