Vector3s ile neden '> =' operatörünü kullanamıyorum?


9

Ben _positionAve olarak adlandırılan iki konum arasında hareket etmek için bir dikdörtgen almaya çalışıyorum _positionB. Her ikisi de tiptedir Vector3. Dikdörtgen gayet iyi hareket ediyor. Bununla birlikte, ulaştığında _positionB, ters yönde hareket etmez, olması gerektiği gibi.

Bir göz atmak için koda geri döndüm. Ben nesne hareket ettikçe, ifkoddaki ifadeler rects konumunun eşit olduğu çerçeveyi kaçırdığı sonucuna vardım _positionB. Eğer rects pozisyonu büyük veya ona eşitse kodu ters yönde değiştirmeye karar verdim _positionB. Kodum çok uzun değil, bu yüzden aşağıda göstereceğim:

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;
            }
        }    
    }
}

Ancak değiştirdiğimde, aşağıdaki hata mesajı konusunda beni uyardı:

Operatör> =, Vector3 ve Vector3 tipindeki işlenenlere uygulanamaz.

Bu beni iki nedenden dolayı karıştırıyor; ilk olarak, her iki değer de aynı veri türündedir. İkinci olarak, ==iki değer üzerinde karşılaştırma işleci ( ) kullanmak hatasız çalışır. Operatörü neden s >=ile kullanamıyorum Vector3?


Yan not: 2 Boolsgibi _atPosAve kullanmaktan kaçınmalısınız _atPosB. Kaçınılmaz olarak, ikisini de senkronize tutarken hata yaparsınız ve hatalara yol açar. enumTüm pozisyonları içeren bir şey yapmak daha iyidir (A, B, belki de gelecekte başkaları) ve bunu kullanarak
Alexander - Reinstate Monica

5
A için ne >=anlama geliyor Vector3? Bileşen açısından karşılaştırılsın mı? Bu tam bir düzen olmazdı. Kullanmayı düşününVector3.MoveTowards
rwols

4
Şunu düşünün: var vec1 = new Vector3(1, 0, 0)ve var vec2 = new Vector3(0, 1 ,0). Mı vec1 >= vec2doğru veya yanlış?
gronostaj

Yanıtlar:


16

Cevabı basitleştirmek için , ad alanı tarafından sağlanan Vector3bir gelenek . Özel veya tür oluşturduğumuzda , operatörlerini de tanımlamamız gerekir . Bu nedenle, operatör için varsayılan bir mantık yoktur . Tarafından işaret edildiği gibi Evgeny Vasilyev , doğrudan kontrol edebilirsiniz olarak, mantıklı , ve değerleri. a'nın üç ayrı değerle temsil edilmesi nedeniyle çok mantıklı değildir .structUnityEngineclassstruct>=_rect_tfm.position == _positionBVector3.xVector3.yVector3.z_rect_tfm.position >= _positionBVector3

TeorideVector3 uygun operatörleri içerecek şekilde sınıfı aşırı yükleyebiliriz , ancak bu oldukça karmaşık görünüyor. Bunun yerine, sadece daha kolay olacağını uzatmakVector3 uygun olan sınıf yöntemiyle . Bununla birlikte, bu mantığı hareket için kullanmak istediğiniz anlaşılıyor. Bu nedenle, Vector3.Lerpyöntemi kullanmak çok daha kolay olabilir ; öyleyse, aşağıda daha fazla bilgi edinin.

Ekleme yöntemleri ekleme Vector3

Daha önce uygulanması, belirtildiği gibi, <=ya da >=bir Vector3çoğu mantıksız değildir. Hareket için, muhtemelen Vector3.Lerpyöntem için daha fazla okumak istersiniz . Bununla birlikte, <= =>aritmetiği başka nedenlerle uygulamak isteyebilirsiniz , bu yüzden size kolay bir alternatif vereceğim.

Bunun yerine mantığını uygulanması Vector3 <= Vector3ya da Vector3 >= Vector3I uzanan öneren, Vector3için yöntemler dahil sınıfı isGreaterOrEqual(Vector3 other)ve isLesserOrEqual(Vector3). Biz yapabilirsiniz uzatma yöntemleri eklemek bir etmek structveya classbir onları bildirerek staticmiras değil sınıfın. Ayrıca anahtar kelimeyi kullanarak hedefi classveya structilk parametre olarak ekleriz this. Not benim örnekte, hepinizin üç ana değerleri (sağlamak için demek farz olduğunu x, yve z) olan tüm sırasıyla büyük veya eşit veya daha az ya da eşittir. İstediğiniz gibi burada kendi mantığınızı sağlayabilirsiniz.

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;
        }
    }
}

Bu yöntemleri Vector3sınıftan çağırmaya çalıştığımızda, yöntemi çağırdığımız örneği localtemsil eder Vector3. Yöntemlerin static; uzatma yöntemleri gerekir olmak static, ama yine örneğinden onları aramak zorunda. Yukarıdaki uzantı yöntemleri göz önüne alındığında, artık bunları doğrudan Vector3türlerinize uygulayabilirsiniz .

Vector3 left;
Vector3 right;

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

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

Hareketli Vector3olanVector3.Lerp

Yöntemin çağrılması ,Vector3.LerpVector3 belirli bir zamanda iki değer arasındaki kesin konumu belirlememizi sağlar . Bu yöntemin ek bir yararı , Vector3iradenin hedefini aşmayacağıdır . Vector3.Lerpüç parametre alır; başlangıç ​​konumu, bitiş konumu ve geçerli konum 0 ile 1 arasında bir değer olarak temsil edilir. Sonuç Vector3olarak, geçerli konum olarak doğrudan ayarlayabildiğimiz sonuç konumunu a olarak verir.

Sorununuzu çözerek, Vector3.Lerpa targetPosition. MoveHer birinde yöntemi çağırdıktan sonra Update, söz konusu hedefe ulaşıp ulaşmadığımızı kontrol edebiliriz; Lerp.Vector3will not aşım, bu yüzden transform.position == targetPositiongüvenilir hale gelir. Şimdi konumunu kontrol etmek ve değiştirmek targetPositioniçin leftPositionya da rightPositionbuna göre, hareket ters.

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);
}

Bunu aşağıdaki animasyonda görebilirsiniz. Mavi küpü tercüme ediyorum Vector3.LerpUnclamped, bu da bize basit kontrolsüz çeviriye benzer bir sonuç veriyor. Kırmızı küpü kullanarak çeviriyorum Vector3.Lerp. Denetlenmeden bırakıldığında, mavi küp unutulmaya başlar; kırmızı küp tam istediğim yerde duruyor. Bu tür hareketlerle ilgili daha fazla bilgiyi Yığın Taşması belgelerinde okuyabilirsiniz .

Denetlenmeden bırakıldığında, mavi küp unutulmaya başlar;  kırmızı küp tam istediğim yerde duruyor.


Vay be, gerçekten ekstra mil yaptın, çok teşekkür ederim!
Javier Martinez

27

>=Bir Vector3tür tanımlamak mantıklı değildir. Bir vektörün diğerinden büyük olup olmadığını ne belirler? Büyüklükleri veya bireysel x, y, z bileşenleri?

Bir vektör bir büyüklük ve yöndür. Peki hangi yönün daha büyük olduğunu belirleyen nedir?

Kullanabileceğiniz büyüklükleri karşılaştırmanız gerekiyorsa sqrMagnitude.

Bu durumda , aynı olup olmadıklarını görmek için farklı bileşenleri basitçe karşılaştırmak için Vector3geçersiz kılınır ==. (bir eşik dahilinde)

İki vektörünü kullanarak çoğaltmak da aynı nedendir *. Bunu yapmanın matematiksel bir yolu yoktur. Bazı insanlar *nokta ürünü için kullanır , ancak bu belirsiz bir API tasarımıdır.


Birlik adlı Vector3bir olduğunu struct, bu nedenle referans karşılaştırma hakkında paragraf tam olarak doğru değil.
31eee384

Bu olabilir , her eksen yalnızca bir grup olarak, 2 tamsayılar karşılaştırarak benzer şekilde, diğer 's, daha büyük olan ilgili bir vektörün konumun her anlamına gelir. Uygulamada her özelliği tek tek karşılaştırmaya kıyasla biraz daha sınırlıdır, ancak en azından hala kullanılabilir.
17'de Piz

Bu Java değil. Eşit operatörün tanımlandığı yapılarda veya sınıflarda referans karşılaştırması doğru değildir
Gustavo Maciel

Bu bölümü kaldırmak için cevabımı değiştirdim. Ancak C # bir noktada Java idi. Bildiğim kadarıyla sınıfların çekirdeği hala aynı çalışıyor ve == fazla yazılmadıysa, tam olarak java'da nasıl davranacağını biliyor.
Evgeny Vasilyev

2

Bu eski bir sorudur, ancak daha az teknik terim koymak gerekirse, Vector3 3 kayan değer için bir "kap" tır - x, y, z.

İki Vector3'ün x değerlerini karşılaştırma gibi tek tek değerleri karşılaştırabilirsiniz, çünkü bunlar yalnızca sayıdır.

Ancak, Vector3'ün tamamı başka bir Vector3 ile karşılaştırılamaz, çünkü ikisini karşılaştırmak için kullanılabilecek tek bir değer yoktur.


0

Sadece Vectorn sınıfına genişletme yöntemleri ekleme konusunda Gnemlock'un yayınladığı şeyleri ekliyoruz . Kayan nokta hesaplamasının nasıl yapıldığından dolayı iki kayan değer arasında belirli karşılaştırma işleçlerini ( ==ve <=ve >=) kullanırken Unity'de (ve eminim diğer oyun motorlarında) bir sorun var . Mathf.Approximatelybunun yerine iki vektörün birbirine = = veya <= olup olmadığını kontrol etmek için aşağıdaki uzatma yöntemleri eklenebilir:

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;
    }
}

Değer unders ve ≥ testlerinin değer biraz düştüğünde gerçekte dönmesini istiyorsanız, bunu kesinlikle kullanabilirsiniz. Bununla birlikte, genellikle, eşit bir kontrolü sadece belirli bir değere eşitlik testi yaparken uygularız. Çeki tek bir noktadan (atlaması kolay) her iki tarafta küçük bir hata payına "genişletir". ≤ ve ≥ zaten yerleşik bir hata payına sahiptir: sırasıyla düşük veya yüksek uca herhangi bir aşma yakalanır, bu nedenle hesaplamadaki küçük sapmalar nedeniyle istenen bir vakayı kaçırmaya zaten daha az duyarlıdırlar.
DMGregory

0

Bu soruyu farklı bir şekilde yorumlamak istiyorum. Bunun gibi bir kod modeli:

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

temel olarak >=/ <=operatörlerini "sol taraf sağ tarafa ulaştı veya geçti mi?" testleri.

Kullanılması >=/ <=konumum sadece şamandıra ise, tek boyutlu bir anlamda mantıklı "ulaşılması veya geçirilen" anlamında:

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

Ancak 3B alanda, ölçmek, hangi tarafın "yüksek / uzak" ve hangi tarafın "düşük / yakın" olduğuna karar vermek için tek bir çizgimiz yok. Örneğin, noktalar arasında devriye gezmeye çalışıyor olabiliriz

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

Şimdi patrolStart <= myPosition <= patrolEndX ekseninde, ama patrolEnd <= myPosition <= patrolStartZ ekseninde bekliyoruz. "Ulaşılan veya geçirilen" operatörünüz bir eksenden diğerine farklıdır, bu nedenle artık bir eşiği geçme konseptimiz ile basit bir eşitsizlik kontrolü arasında açık bir eşleme yoktur.

Ama biz 3 boyutlu uzayda sadece bir satır seçmek ve bizim yapabilir bir yolu vardır >=/ <=seçtik bu hat boyunca tek şamandıra vaka gibi davranmaya:

// 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();

Bir bonus olarak, eksen vektörünü kullanmadan önce normalleştirirseniz, tüm nokta ürünleri mesafeleri temsil eder, böylece seyahat ekseni boyunca her iki uçtan ne kadar uzakta olduğunuzu tam olarak ölçebilirsiniz.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.