मैं वेक्टर 3s के साथ ऑपरेटर '> =' का उपयोग क्यों नहीं कर सकता?


9

मैं दो पदों जो मैं के रूप में उल्लेख के बीच ले जाने के लिए एक आयत पाने के लिए कोशिश कर रहा हूँ _positionAऔर _positionB। दोनों प्रकार के हैं Vector3। आयत ठीक चलती है। हालांकि, जब यह पहुंचता है तो _positionBयह विपरीत दिशा में नहीं बढ़ता है, जैसे इसे होना चाहिए।

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

using UnityEngine;
using System.Collections;

public class Rectangle : MonoBehaviour 
{
    private Vector3 _positionA = new Vector3(-0.97f, -4.28f); //Start position
    private Vector3 _positionB = new Vector3(11.87f, -4.28f); //End position
    private Transform _rect_tfm;
    private bool _atPosA = false, _atPosB = false;

    public Vector2 speed = new Vector2(1f, 0f);

    private void Start()
    {
        _rect_tfm = gameObject.GetComponent<Transform>();
        _rect_tfm.position = _positionA;
        _atPosA = true;
    }

    private void Update()
    {
        /*NOTE: Infinite loops can cause Unity to crash*/
        Move();
    }

    private void Move()
    {
        if (_atPosA)
        {
            _rect_tfm.Translate(speed * Time.deltaTime);

            if (_rect_tfm.position == _positionB)
            {
                _atPosA = false;
                _atPosB = true;
            }
        }

        if (_atPosB)
        {
            _rect_tfm.Translate(-speed * Time.deltaTime);

            if (_rect_tfm.position == _positionA)
            {
                _atPosA = true;
                _atPosB = false;
            }
        }    
    }
}

जब मैंने इसे बदल दिया, तब भी, इसने मुझे निम्न त्रुटि संदेश की चेतावनी दी:

ऑपरेटर> = वेक्टर 3 और वेक्टर 3 के ऑपरेंड पर लागू नहीं किया जा सकता है।

यह मुझे दो कारणों से भ्रमित करता है; सबसे पहले, दोनों मान एक ही डेटा प्रकार के हैं। दूसरा, ==दो मूल्यों पर तुलना ऑपरेटर ( ) का उपयोग त्रुटि के बिना काम करता है। मैं ऑपरेटर का उपयोग क्यों नहीं कर सकते हैं >=साथ Vector3रों?


साइड नोट: आपको 2 Boolsलाइक _atPosAऔर का उपयोग करने से बचना चाहिए _atPosB। अनिवार्य रूप से, आप उन दोनों को सिंक में रखते हुए एक गलती करेंगे, और इससे कीड़े पैदा होंगे। enumभविष्य में सभी पदों (ए, बी, शायद दूसरों को शामिल करना) बनाना बेहतर है , और इसका उपयोग करते हुए
अलेक्जेंडर - मोनिका

5
>=एक के लिए क्या मतलब होना चाहिए Vector3? घटक-वार तुलना करें? यह कुल आदेश नहीं होगा। उपयोग करने पर विचार करेंVector3.MoveTowards
rwols

4
इस पर विचार करें: var vec1 = new Vector3(1, 0, 0)और var vec2 = new Vector3(0, 1 ,0)। है vec1 >= vec2सही या गलत?
ग्रोनोस्तज

जवाबों:


16

उत्तर को सरल बनाने के लिए, Vector3एक कस्टम नामस्थान structद्वारा प्रदान किया गया UnityEngineहै। जब हम कस्टम classया structप्रकार बनाते हैं, तो हमें इसके ऑपरेटरों को भी परिभाषित करना चाहिए । जैसे, ऑपरेटर के लिए कोई डिफ़ॉल्ट तर्क नहीं है । के रूप में द्वारा बताया एवगेनी वासिलयेव , समझ में आता है, हम सीधे जांच कर सकते हैं के रूप में , और मूल्यों। तथ्य यह है कि तीन अलग-अलग मूल्यों द्वारा प्रतिनिधित्व किया जाता है की वजह से ज्यादा मतलब नहीं है ।>=_rect_tfm.position == _positionBVector3.xVector3.yVector3.z_rect_tfm.position >= _positionBVector3

हम सिद्धांत मेंVector3 उपयुक्त ऑपरेटरों को शामिल करने के लिए कक्षा को अधिभार दे सकते हैं , लेकिन यह जटिल लगता है। इसके बजाय, यह आसान हो बस करने के लिए विस्तार एक उपयुक्त साथ वर्ग विधि । कहा जा रहा है, ऐसा लगता है कि आंदोलन के लिए इस तर्क का उपयोग करने का आपका इरादा है। जैसे, आपको विधि का उपयोग करना बहुत आसान लग सकता है ; यदि हां, तो आगे पढ़ें।Vector3Vector3.Lerp

के लिए विस्तार विधियाँ जोड़ना Vector3

पहले से, उल्लेख किया है को लागू करने <=या >=करने के लिए एक Vector3अक्सर विसंगत है। आंदोलन के लिए, आप शायद Vector3.Lerpविधि के लिए आगे पढ़ना चाहते हैं । उसने कहा, आप <= =>अन्य कारणों से अंकगणित को लागू करना चाह सकते हैं , इसलिए मैं आपको एक आसान विकल्प दूंगा।

इसके बजाय के तर्क को लागू करने का Vector3 <= Vector3या Vector3 >= Vector3, मैं विस्तार प्रस्ताव Vector3के लिए तरीकों में शामिल करने के लिए वर्ग isGreaterOrEqual(Vector3 other)और isLesserOrEqual(Vector3)। हम विस्तार विधियों को एक structया classएक staticवर्ग में घोषित करके जोड़ सकते हैं जो विरासत में नहीं मिलती है । हम कीवर्ड का उपयोग करके लक्ष्य classया structपहले पैरामीटर के रूप में भी शामिल हैं this। नोट मेरी उदाहरण में, मुझे लगता है कि यह है कि आप यह सुनिश्चित करें कि सभी तीन मुख्य मूल्यों (मतलब x, yऔर z) कर रहे हैं सभी क्रमशः अधिक या बराबर, या कम या बराबर,। आप अपने स्वयं के तर्क प्रदान कर सकते हैं, यहाँ, आपको आवश्यकतानुसार।

public static class ExtendingVector3
{
    public static bool IsGreaterOrEqual(this Vector3 local, Vector3 other)
    {
        if(local.x >= other.x && local.y >= other.y && local.z >= other.z)
        {
            return true;
        }
        else
        {
            return false;
        }
    }

    public static bool IsLesserOrEqual(this Vector3 local, Vector3 other)
    {
        if(local.x <= other.x && local.y <= other.y && local.z <= other.z)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
}

जब हम Vector3कक्षा से इन विधियों को कॉल करने का प्रयास localकरते हैं , तो उस Vector3उदाहरण का प्रतिनिधित्व करेंगे जिसे हम विधि से बुला रहे हैं। आप ध्यान देंगे कि विधियाँ हैं static; विस्तार विधियां अवश्य होनी चाहिए static, लेकिन आपको अभी भी उन्हें एक उदाहरण से कॉल करना होगा। उपरोक्त एक्सटेंशन विधियों को देखते हुए, अब आप उन्हें सीधे अपने Vector3प्रकारों पर लागू कर सकते हैं ।

Vector3 left;
Vector3 right;

// Is left >= right?
bool isGreaterOrEqual = left.IsGreaterOrEqual(right);

// Is left <= right?
bool isLesserOrEqual = left.IsLesserOrEqual(right);

Vector3साथ चल रहा हैVector3.Lerp

विधि को कॉल करनाVector3.Lerp हमें Vector3एक निश्चित समय में दो मूल्यों के बीच सटीक स्थिति निर्धारित करने की अनुमति देता है । इस पद्धति का एक अतिरिक्त लाभ यह है कि यह Vector3वसीयत अपने लक्ष्य की देखरेख नहीं करेगीVector3.Lerpतीन पैरामीटर लेता है; प्रारंभ स्थिति, अंतिम स्थिति और वर्तमान स्थिति 0 और 1. के बीच मान के रूप में प्रदर्शित होती है। यह परिणामी स्थिति को एक के रूप में आउटपुट करता है Vector3, जिसे हम सीधे वर्तमान स्थिति के रूप में सेट कर सकते हैं।

आपकी समस्या का समाधान, मैं एक का उपयोग Vector3.Lerpकरने का प्रस्ताव है targetPositionMoveप्रत्येक में विधि को कॉल करने के बाद Update, हम यह कह सकते हैं कि क्या हम लक्ष्य तक पहुँच गए हैं; ओवरशूट नहींLerp.Vector3 होगा , इसलिए विश्वसनीय हो जाता है। अब हम स्थिति की जांच कर सकते हैं, और तदनुसार, आंदोलन को उलटने या बदलने के लिए ।transform.position == targetPositiontargetPositionleftPositionrightPosition

public Vector3 leftPosition, rightPosition;
public float speed;
public Vector3 targetPosition;

private void Awake()
{
    targetPosition = rightPosition;
}

private void Update()
{
    Move();

    if(transform.position == targetPosition)
    {
        // We have arrived at our intended position. Move towards the other position.
        if(targetPosition == rightPosition)
        {
            // We were moving to the right; time to move to the left.
            targetPosition = leftPosition;
        }
        else
        {
            // We were moving to the left; time to move to the right.
            targetPosition = rightPosition;
        }
    }
}

private void Move()
{
    // First, we need to find out the total distance we intend to move.
    float distance = Vector3.Distance(transform.position, targetPosition);

    // Next, we need to find out how far we intend to move.
    float movement = speed * Time.deltaTime;

    // We find the increment by simply dividing movement by distance.
    // This will give us a decimal value. If the decimal is greater than
    // 1, we are moving more than the remaining distance. Lerp 
    // caps this number at 1, which in turn, returns the end position.
    float increment = movement / distance;

    // Lerp gives us the absolute position, so we pass it straight into our transform.
    transform.position = Vector3.Lerp(transform.position, targetPosition, increment);
}

आप इसे निम्नलिखित एनीमेशन में प्रदर्शित कर सकते हैं। मैं नीले घन का अनुवाद करता हूं Vector3.LerpUnclamped, जो हमें सरल अनियंत्रित अनुवाद के समान परिणाम देता है। मैं लाल घन का उपयोग करके अनुवाद करता हूं Vector3.Lerp। अनियंत्रित छोड़ दिया, नीला घन विस्मृति में चला जाता है; जबकि लाल घन बिल्कुल वहीं रूक जाता है, जहां तक ​​मैं चाहता हूं। आप स्टैक ओवरफ्लो प्रलेखन में इस प्रकार के आंदोलन के बारे में अधिक पढ़ सकते हैं ।

अनियंत्रित छोड़ दिया, नीला घन विस्मृति में चला जाता है;  जबकि लाल घन बिल्कुल वहीं रूक जाता है, जहां तक ​​मैं चाहता हूं।


वाह, आप वास्तव में अतिरिक्त मील गए, बहुत बहुत धन्यवाद!
जेवियर मार्टिनेज

27

>=एक Vector3प्रकार के लिए परिभाषित करने का कोई मतलब नहीं है। यदि एक वेक्टर दूसरे से अधिक है तो क्या निर्धारित करता है? उनके परिमाण या उनके व्यक्तिगत x, y, z घटक?

एक वेक्टर एक परिमाण और एक दिशा है। तो क्या निर्धारित करता है कि कौन सी दिशा अधिक है?

यदि आपको उन परिमाणों की तुलना करने की आवश्यकता है जो आप उपयोग कर सकते हैं sqrMagnitude

इस मामले में Vector3ओवरराइड ==करने के लिए बस अलग-अलग घटकों की तुलना करके देखें कि क्या वे समान हैं। (एक सीमा के भीतर)

यही कारण है कि दो वैक्टर का उपयोग *करना संभव नहीं है। इसे करने का कोई गणितीय तरीका नहीं है। कुछ लोग *डॉट उत्पाद के लिए उपयोग करते हैं, लेकिन यह एक अस्पष्ट एपीआई डिजाइन है।


एकता Vector3एक है struct, इसलिए संदर्भ तुलना के बारे में पैराग्राफ काफी सही नहीं है।
31ee3838

इसका मतलब हो सकता है कि प्रत्येक अक्ष पर प्रत्येक वेक्टर की स्थिति दूसरे के मुकाबले अधिक हो, 2 पूर्णांक की तुलना में, केवल एक समूह के रूप में। यह प्रत्येक संपत्ति की तुलना में व्यक्तिगत रूप से तुलना में आवेदन में थोड़ा अधिक सीमित है, लेकिन अभी भी कम से कम इस्तेमाल किया जा सकता है।
पिसिस

यह जावा नहीं है। संदर्भों की संरचना या वर्गों में सही नहीं है, जहां बराबर ऑपरेटर को परिभाषित किया गया है
गुस्तावो मैकील

मैंने उस हिस्से को हटाने के लिए अपना जवाब संशोधित कर दिया। हालाँकि C # एक बिंदु पर जावा था। जहाँ तक मुझे पता है कि कक्षाओं का मूल अभी भी वही काम करता है और अगर == लिखा हुआ नहीं है तो यह व्यवहार करता है कि यह जावा में कैसा होगा।
एव्जेनी वासिलयेव

2

यह एक पुराना सवाल है, लेकिन कम तकनीकी शब्दों में कहें, तो एक वेक्टर 3 फ्लोट वैल्यू के लिए "कंटेनर" है - x, y, z।

आप व्यक्तिगत मानों की तुलना कर सकते हैं, जैसे कि दो वेक्टर 3 के x मानों की तुलना करना, क्योंकि वे केवल संख्याएँ हैं।

हालाँकि, एक पूरे वेक्टर 3 की तुलना दूसरे वेक्टर 3 से नहीं की जा सकती क्योंकि एक भी ऐसा मूल्य नहीं है जिसका इस्तेमाल दोनों की तुलना के लिए किया जा सके।


0

बस वेक्टर 3 वर्ग में विस्तार के तरीकों को जोड़ने के बारे में, Gnemlock क्या पोस्ट किया गया है। वहाँ एकता में एक मुद्दा है (और मुझे यकीन है कि अन्य खेल इंजन हूँ) जब कुछ तुलना ऑपरेटर्स का उपयोग ( ==, <=और >=) दो नाव मूल्यों के बीच, कैसे चल बिन्दु गणना नियंत्रित किया जाता है की वजह से। Mathf.Approximatelyइसके बजाय उपयोग किया जाना चाहिए, इस प्रकार निम्नलिखित विस्तार विधियों की जाँच के लिए जोड़ा जा सकता है अगर दो वैक्टर हैं = = या <= एक दूसरे के लिए:

using UnityEngine;

public static class ExtendingVector3
{
    public static bool IsGreaterOrEqual(this Vector3 local, Vector3 other)
    {
        bool xCond = local.x > other.x || Mathf.Approximately(local.x, other.x);
        bool yCond = local.y > other.y || Mathf.Approximately(local.y, other.y);
        bool zCond = local.z > other.z || Mathf.Approximately(local.z, other.z);

        if(xCond && yCond && zCond)
            return true;

        return false;
    }

    public static bool IsLesserOrEqual(this Vector3 local, Vector3 other)
    {
        bool xCond = local.x < other.x || Mathf.Approximately(local.x, other.x);
        bool yCond = local.y < other.y || Mathf.Approximately(local.y, other.y);
        bool zCond = local.z < other.z || Mathf.Approximately(local.z, other.z);

        if(xCond && yCond && zCond)
            return true;

        return false;
    }
}

आप निश्चित रूप से इसका उपयोग कर सकते हैं, यदि आप चाहते हैं कि दोनों certainly & return परीक्षण सही वापस लौटें जब मूल्य थोड़ा कम हो जाए। आमतौर पर, हम केवल एक ही मान के लिए परीक्षण करते समय लगभग समान जाँच लागू करते हैं। यह किसी भी तरफ त्रुटि के एक छोटे से बिंदु के लिए एकल बिंदु (आसानी से याद रखना) से चेक को "चौड़ा" करता है। Have और in में पहले से ही त्रुटि का एक मार्जिन होता है: निम्न या उच्च अंत में कोई भी ओवरशूट क्रमशः कब्जा हो जाता है, इसलिए वे गणना में छोटे विचलन के कारण वांछित मामले को याद करने के लिए पहले से ही बहुत कम अतिसंवेदनशील होते हैं।
DMGregory

0

मैं इस प्रश्न की व्याख्या करने का एक अलग तरीका प्रस्तावित करना चाहता हूं। इस तरह एक कोड पैटर्न:

if(myPosition >= patrolEnd || myPosition <= patrolStart)
    TurnAround();

मूल रूप से >=/ <=ऑपरेटरों का उपयोग करने की कोशिश कर रहा है "के रूप में बाईं ओर पहुंच गया है या सही पक्ष पारित कर दिया है?" परीक्षण।

का उपयोग करते हुए >=/ <=मतलब "पहुँच या पारित कर दिया" एक आयामी अर्थ में समझ में आता है, मेरी स्थिति सिर्फ एक नाव है यदि:

if(myX >= rightEnd || myX <= leftEnd)
    TurnAround();

लेकिन 3 डी स्पेस में हमारे पास यह मापने के लिए कोई एक लाइन नहीं है कि कौन सा पक्ष "उच्च / दूर" है और कौन सा पक्ष "कम" या "निकट" है। उदाहरण के लिए, हम बिंदुओं के बीच गश्त करने की कोशिश कर सकते हैं

patrolStart = (-10,  0,  5)
patrolEnd   = ( 10,  0, -5)

तो अब हम patrolStart <= myPosition <= patrolEndएक्स अक्ष पर उम्मीद करते हैं, लेकिन patrolEnd <= myPosition <= patrolStartजेड अक्ष पर। हमारा "पहुंच या पारित" ऑपरेटर एक अक्ष से दूसरे में भिन्न होता है, इसलिए थ्रेसहोल्ड और सरल असमानता की जांच की हमारी अवधारणा के बीच अब कोई स्पष्ट मानचित्रण नहीं है।

लेकिन, वहाँ एक तरह से हम 3 डी अंतरिक्ष में सिर्फ एक लाइन से बाहर ले सकते हैं, और हमारे बनाना है >=/ <=इस लाइन हम चुना है साथ ही नाव मामले की तरह व्यवहार करते हैं:

// Here we select the directed line from our start point to our end point.
Vector3 axis = patrolEnd - patrolStart;

// We can make a single number representing the "low" end of our range
// by taking the dot product of this axis with our start point.
float low = Vector3.Dot(axis, patrolStart);

// And the "high" end by dotting this axis with the end point.
float high = Vector3.Dot(axis, patrolEnd);

// And our progress between is the dot product of the axis with our position.
float progress = Vector3.Dot(axis, myPosition);

// Now we can use our turn-around logic just like we were in the 1D case:
if(progress >= high || progress <= low)
    TurnAround();

एक बोनस के रूप में, यदि आप इसका उपयोग करने से पहले अक्ष वेक्टर को सामान्य करते हैं, तो सभी डॉट उत्पाद दूरी का प्रतिनिधित्व करते हैं, इसलिए आप यात्रा के अक्ष के साथ-साथ आप वास्तव में कितनी दूर से हैं, इसे माप सकते हैं।

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