Próbuję uzyskać prostokąt, aby poruszać się między dwiema pozycjami, które nazywam _positionA
i _positionB
. Oba są tego typu Vector3
. Prostokąt porusza się dobrze. Kiedy jednak się osiągnie _positionB
, nie porusza się w przeciwnym kierunku, jak powinien.
Wróciłem do kodu, żeby się przyjrzeć. Doszedłem do wniosku, że gdy obiekt się porusza, if
instrukcje w kodzie nie mieszczą się w ramce, w której pozycja rektyfikacji była równa _positionB
. Postanowiłem zmodyfikować kod, aby odwrócić kierunek, jeśli pozycja prostokątów jest większa lub równa _positionB
. Mój kod nie jest zbyt długi, więc wyświetlę go poniżej:
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;
}
}
}
}
Kiedy go jednak zmieniłem, ostrzegł mnie przed następującym komunikatem o błędzie:
Operator> = nie można zastosować do argumentów typu Vector3 i Vector3.
Myli mnie to z dwóch powodów; po pierwsze, obie wartości są tego samego typu danych. Po drugie, użycie operatora porównania ( ==
) na dwóch wartościach działa bez błędów. Dlaczego nie mogę używać operatora >=
z Vector3
s?
źródło
Bools
takich jak_atPosA
i_atPosB
. Nieuchronnie popełnisz błąd, utrzymując je obie w synchronizacji, co doprowadzi do błędów. Lepiej zrobićenum
zawierający wszystkie pozycje (A, B, być może inne w przyszłości) i używając tego>=
znaczyć dlaVector3
? Porównać pod względem komponentów? To nie byłoby całkowite zamówienie. Rozważ użycieVector3.MoveTowards
var vec1 = new Vector3(1, 0, 0)
ivar vec2 = new Vector3(0, 1 ,0)
. Czyvec1 >= vec2
prawda czy fałsz?Odpowiedzi:
Aby uprościć odpowiedź,
Vector3
jest to zwyczajstruct
dostarczony przezUnityEngine
przestrzeń nazw. Kiedy tworzymy niestandardoweclass
lubstruct
typy, musimy również zdefiniować ich operatorów . W związku z tym>=
operator nie ma domyślnej logiki . Jak podkreślił Evgeny Wasiliew ,_rect_tfm.position == _positionB
ma sens, jak możemy bezpośrednio sprawdzićVector3.x
,Vector3.y
iVector3.z
wartości._rect_tfm.position >= _positionB
nie ma większego sensu, ponieważ aVector3
jest reprezentowane przez trzy oddzielne wartości.Moglibyśmy przeciążyć
Vector3
klasę, aby zawierała odpowiednie operatory w teorii , ale wydaje się to dość skomplikowane. Zamiast tego łatwiej byłoby po prostu przedłużyć oVector3
klasę z odpowiednim sposobem . Biorąc to pod uwagę, wydaje się, że zamierzasz użyć tej logiki do poruszania się. W związku z tym korzystanie z tejVector3.Lerp
metody może być znacznie łatwiejsze ; jeśli tak, czytaj dalej poniżej.Dodanie metod rozszerzenia do
Vector3
Jak wcześniej wspomniano, zastosowanie
<=
lub>=
doVector3
jest często nielogiczne. Jeśli chodzi o ruch, prawdopodobnie chcesz przeczytać więcej na temat tejVector3.Lerp
metody. To powiedziawszy, możesz chcieć zastosować<=
=>
arytmetykę z innych powodów, więc dam ci łatwą alternatywę.Zamiast stosowania logiki
Vector3 <= Vector3
lubVector3 >= Vector3
proponuję rozszerzenieVector3
klasy o metody dlaisGreaterOrEqual(Vector3 other)
iisLesserOrEqual(Vector3)
. Możemy dodać metody rozszerzenia do astruct
lubclass
deklarując je wstatic
klasie, która nie dziedziczy. Uwzględniamy również celclass
lubstruct
jako pierwszy parametr za pomocąthis
słowa kluczowego. Należy zauważyć, że w moim przykładzie zakładamy, że masz na myśli, aby upewnić się, że wszystkie trzy główne wartości (x
,y
iz
) są wszystkie większe lub równe lub mniejsze lub równe, odpowiednio. Tutaj możesz podać własną logikę, zgodnie z wymaganiami.Kiedy spróbujemy wywołać te metody z
Vector3
klasy,local
będzie reprezentowaćVector3
instancję, z której wywołujemy metodę. Zauważysz, że metody sąstatic
; metody rozszerzenia muszą byćstatic
, ale nadal musisz wywoływać je z instancji. Biorąc pod uwagę powyższe metody rozszerzenia, możesz teraz zastosować je bezpośrednio do swoichVector3
typów.Przeprowadzka
Vector3
zVector3.Lerp
Nazywając ten
Vector3.Lerp
sposób pozwala nam określić dokładną pozycję między dwomaVector3
wartościami w danym czasie. Dodatkową zaletą tej metody jest to, że nie wykroczy swój cel . przyjmuje trzy parametry; pozycja początkowa, końcowa i bieżąca pozycja reprezentowane jako wartość od 0 do 1. Wyprowadza wynikową pozycję jako a , którą możemy bezpośrednio ustawić jako bieżącą pozycję.Vector3
Vector3.Lerp
Vector3
Rozwiązując problem, proponuję użyć,
Vector3.Lerp
aby przejść dotargetPosition
. Po wywołaniuMove
metody w każdym z nichUpdate
możemy sprawdzić, czy osiągnęliśmy wspomniany cel;Lerp.Vector3
będzie nie przeregulowanie, więctransform.position == targetPosition
staje się wiarygodne. Możemy teraz sprawdzić pozycję i odpowiednio zmienić ruchtargetPosition
naleftPosition
lubrightPosition
odwrócić.Można to zobaczyć na poniższej animacji. Tłumaczę niebieski sześcian za pomocą
Vector3.LerpUnclamped
, co daje nam podobny wynik do prostego niesprawdzonego tłumaczenia. Tłumaczę czerwony sześcian za pomocąVector3.Lerp
. Pozostawiony bez zaznaczenia, niebieski sześcian rusza w zapomnienie; podczas gdy czerwony sześcian zatrzymuje się dokładnie tam, gdzie zamierzam. Możesz przeczytać więcej o tym rodzaju ruchu w dokumentacji przepełnienia stosu .źródło
Definiowanie
>=
dlaVector3
typu nie ma sensu. Co decyduje o tym, czy jeden wektor jest większy od drugiego? Ich wielkość czy poszczególne składniki x, y, z?Wektor jest wielkością i kierunkiem. Co decyduje o tym, który kierunek jest większy?
Jeśli musisz porównać wielkości, których możesz użyć
sqrMagnitude
.W takim przypadku
Vector3
zastępuje==
po prostu porównanie różnych komponentów, aby sprawdzić, czy są one takie same. (w ramach progu)Z tego samego powodu pomnożenie dwóch wektorów
*
nie jest możliwe. Po prostu nie ma matematycznego sposobu na zrobienie tego. Niektóre osoby używają*
produktu kropkowego, ale jest to niejasny projekt interfejsu API.źródło
Vector3
jeststruct
, więc akapit dotyczący porównania odniesień nie jest całkiem poprawny.To stare pytanie, ale mówiąc inaczej, Vector3 to „pojemnik” na 3 wartości zmiennoprzecinkowe - x, y, z.
Możesz porównać poszczególne wartości, takie jak porównanie wartości x dwóch Vector3, ponieważ są to tylko liczby.
Jednak całego Vector3 nie można porównać do innego Vector3, ponieważ nie ma jednej wartości, której można by porównać.
źródło
Dodanie do tego, co opublikował Gnemlock , dotyczące dodawania metod rozszerzenia do klasy Vector3. Jest to problem w Jedności (i jestem pewien, inne silniki gry) podczas korzystania z niektórych operatorów porównania (
==
,<=
i>=
) dwóch liczb rzeczywistych, ze względu na sposób kalkulacji pływający punkt jest obsługiwane.Mathf.Approximately
zamiast tego należy użyć następujących metod rozszerzenia, aby sprawdzić, czy dwa wektory są względem siebie> = lub <=:źródło
Chciałbym zaproponować inny sposób interpretacji tego pytania. Wzorzec kodu taki jak ten:
w zasadzie próbuje użyć operatorów
>=
/<=
, ponieważ „czy lewa strona osiągnęła lub minęła prawą?” testy.Użycie
>=
/<=
do oznaczenia „osiągnięto lub przekazano” ma sens w sensie jednowymiarowym, jeśli moja pozycja jest zmienna:Ale w przestrzeni 3D nie mamy żadnej linii do zmierzenia wzdłuż, aby zdecydować, która strona jest „wysoka / daleka”, a która strona „niska / bliska”. Na przykład moglibyśmy próbować patrolować między punktami
Więc teraz oczekujemy
patrolStart <= myPosition <= patrolEnd
na osi X, alepatrolEnd <= myPosition <= patrolStart
na osi Z. Nasz operator „osiągnięty lub przekazany” różni się od jednej osi do drugiej, więc nie ma już jasnego mapowania między naszą koncepcją przekroczenia progu a prostą kontrolą nierówności.Istnieje jednak sposób, w jaki możemy wybrać tylko jedną linię w przestrzeni 3D i sprawić, aby nasz
>=
/<=
zachowywał się jak pojedynczy przypadek zmiennoprzecinkowy wzdłuż tej linii, którą wybraliśmy:Jako bonus, jeśli znormalizujesz wektor osi przed jego użyciem, wówczas wszystkie produkty kropkowe reprezentują odległości, dzięki czemu możesz dokładnie zmierzyć, jak daleko jesteś od dowolnego końca, wzdłuż osi podróży.
źródło