Vector3와 함께 연산자 '> ='를 사용할 수없는 이유는 무엇입니까?


9

나는 등을 참조 두 위치 사이에서 이동하는 사각형을 얻기 위해 노력하고 _positionA_positionB. 둘 다 유형 Vector3입니다. 사각형은 잘 움직입니다. 그러나 도달 _positionB하면 반대 방향으로 움직이지 않습니다.

코드를 다시 살펴 보았습니다. 객체가 움직일 if때 코드 의 명령문이 rects 위치가 같은 프레임을 놓쳤다 는 결론에 도달했습니다 _positionB. rects 위치가 보다 크거나 같은 경우 코드를 반대 방향으로 수정하기로 결정했습니다 _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;
            }
        }    
    }
}

그러나 변경했을 때 다음과 같은 오류 메시지가 표시됩니다.

연산자> =는 Vector3 및 Vector3 유형의 피연산자에 적용 할 수 없습니다.

이것은 두 가지 이유로 나를 혼란스럽게한다. 먼저 두 값의 데이터 형식이 동일합니다. 둘째, ==두 값에 비교 연산자 ( )를 사용하면 오류없이 작동합니다. 왜 연산자 >=Vector3s 와 함께 사용할 수 없습니까?


사이드 참고 : 2를 사용하지 않아야 Bools처럼 _atPosA하고 _atPosB. 필연적으로, 둘 다 동기화 상태를 유지하는 실수를 저지르면 버그가 발생할 수 있습니다. enum
Alexander

5
무엇을 >=의미 Vector3합니까? 구성 요소와 비교? 그것은 총 주문이 아닙니다. Vector3.MoveTowards
rwols 사용시

4
이것을 고려하십시오 : var vec1 = new Vector3(1, 0, 0)var vec2 = new Vector3(0, 1 ,0). vec1 >= vec2참 인가 거짓인가?
gronostaj

답변:


16

답변을 단순화하기 위해 네임 스페이스에서 제공 Vector3하는 사용자 정의 structUnityEngine있습니다. 사용자 정의 class또는 struct유형 을 작성할 때 해당 연산자 정의 해야합니다 . 따라서 운영자에 대한 기본 논리는 없습니다 . 에 의해 지적 예브게니 바실리 예프 , 우리가 직접 확인할 수있는, 의미가 , 그리고 값을. a 는 세 개의 개별 값으로 표시 되므로 그다지 의미가 없습니다 .>=_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)structclassstaticclassstructthisxyz

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.LerpVector3 주어진 시간에 두 값 사이의 정확한 위치를 결정할 수 있습니다 . 이 방법의 추가 혜택이 있다는 것이다 (가) Vector3목표를 오버 슛을하지 않습니다 . Vector3.Lerp세 가지 매개 변수를 취합니다. 시작 위치, 종료 위치 및 현재 위치는 0과 1 사이의 값으로 표시됩니다. 결과 위치를로 출력 Vector3하여 현재 위치로 직접 설정할 수 있습니다.

문제를 해결하기 Vector3.Lerp위해를 사용하여을 제안 합니다 targetPosition. Move각각 에서 메소드를 호출 한 후 Update, 우리가 목표에 도달했는지 확인할 수 있습니다. Lerp.Vector3하지 오버 슈트, 그래서 transform.position == targetPosition믿을된다. 우리는 지금의 위치를 확인하고 변경할 수 있습니다 targetPositionleftPosition또는 rightPosition이에 따라, 움직임을 반전 할 수 있습니다.

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. 체크하지 않으면 파란색 큐브가 망각으로 이동합니다. 빨간 입방체는 내가 의도 한 곳에서 정확하게 멈 춥니 다. 이 유형의 이동 대한 자세한 내용 은 스택 오버플로 설명서를 참조하십시오 .

체크하지 않으면 파란색 큐브가 망각으로 이동합니다.  빨간 입방체는 내가 의도 한 곳에서 정확하게 멈 춥니 다.


와우, 당신은 정말 여분의 마일을 갔다, 너무 감사합니다!
Javier Martinez

27

유형을 정의 >=하는 것은 Vector3의미가 없습니다. 한 벡터가 다른 벡터보다 큰지 여부는 어떻게 결정됩니까? 그들의 크기 또는 개별적인 x, y, z 성분?

벡터는 크기와 방향입니다. 그렇다면 어떤 방향이 더 큰지 결정하는 것은 무엇입니까?

크기를 비교해야 할 경우 사용할 수 있습니다 sqrMagnitude.

이 경우 단순히 다른 구성 요소를 비교하여 동일한 지 확인하기 위해 Vector3재정의 ==합니다. (임계 값 이내)

이것은 두 벡터를 사용하여 곱할 *수없는 것과 같은 이유 입니다. 수학적으로 수행 할 수있는 방법은 없습니다. 일부 사람들 *은 내적 제품에 사용하지만 API 디자인이 불분명합니다.


Unity 's Vector3struct이므로 참조 비교에 대한 단락이 옳지 않습니다.
31eee384

이는 각 축의 한 벡터 위치가 다른 정수보다 큰 것을 의미 할 수 있으며, 그룹으로 만 2 개의 정수를 비교하는 것과 유사합니다. 각 속성을 개별적으로 비교하는 것보다 응용 프로그램에서 조금 더 제한적이지만 여전히 사용할 수는 있습니다.
Pysis 17 년

이것은 자바가 아니다. 참조 비교는 연산자가 정의와 동일 구조체 나 클래스에서 사실이 아니다
구스타보 마시 엘

해당 부분을 제거하기 위해 답변을 수정했습니다. 그러나 C #은 한 시점에 Java였습니다. 내가 아는 한 클래스의 핵심은 여전히 ​​똑같이 작동하고 ==가 덮어 쓰지 않으면 Java에서 정확히 어떻게 작동합니다.
Evgeny Vasilyev

2

이것은 오래된 질문이지만 덜 기술적 인 용어로 말하면 Vector3은 x, y, z의 3 개의 부동 소수점 값에 대한 "컨테이너"입니다.

두 Vector3의 x 값 비교는 숫자 일 뿐이므로 개별 값을 비교할 수 있습니다.

그러나 두 Vector를 비교하는 데 사용할 수있는 단일 값이 없기 때문에 전체 Vector3을 다른 Vector3과 비교할 수 없습니다.


0

그냥 무엇에 추가 Gnemlock가 Vector3 클래스에 확장 메서드를 추가에 대해 기록했다. 부동 소수점 계산이 처리되는 방식으로 인해 두 부동 소수점 값 사이에 특정 비교 연산자 ( ==, <=>=)를 사용할 때 Unity (및 다른 게임 엔진) 에 문제가 있습니다. 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;
    }
}

값이 약간 언더 슈트 될 때 ≤ & ≥ 테스트가 모두 true를 리턴하도록하려면이를 사용할 수 있습니다. 그러나 일반적으로 단일 특정 값에 대한 동등성을 테스트 할 때만 대략 동등한 검사를 적용합니다. 단일 포인트 (쉽게 놓치기 쉬운 것)에서 어느 쪽의 작은 오류 마진까지 검사를 "넓 힙니다". ≤ 및 ≥에는 이미 오차 한계가 내장되어 있습니다. 로우 엔드 또는 하이 엔드에 대한 오버 슈트는 각각 캡처되므로 계산의 작은 편차로 인해 원하는 경우가 누락 될 가능성이 훨씬 낮습니다.
DMGregory

0

이 질문을 해석하는 다른 방법을 제안하고 싶습니다. 다음과 같은 코드 패턴 :

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

기본적으로 >=/ <=연산자를 "왼쪽이 오른쪽에 도달했거나 통과 했습니까?" 테스트.

사용 >=/ <=내 위치가 단지 플로트의 경우, 한 차원 점에서 의미가 "에 도달하거나 통과"을 의미합니다 :

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

그러나 3D 공간에는 어느 쪽이 "높은 / 먼"이고 어느 쪽이 "낮은 / 가까운"인지를 결정하기 위해 측정 할 한 줄이 없습니다. 예를 들어, 포인트 사이를 순찰하려고 할 수 있습니다

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

이제 우리 patrolStart <= myPosition <= patrolEnd는 X 축이 아니라 patrolEnd <= myPosition <= patrolStartZ 축에 기대 합니다 . "도달 또는 전달 된"연산자는 축마다 다르므로 더 이상 임계 값 전달 개념과 단순한 불평등 검사 간의 명확한 매핑이 없습니다.

그러나 3D 공간에서 한 줄만 골라서 선택한 >=/ <=이 행을 따라 단일 부동 케이스처럼 행동하도록 만들 수있는 방법 이 있습니다.

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

보너스로 축 벡터를 사용하기 전에 정규화하면 모든 내적은 거리를 나타내므로 이동 축을 따라 양쪽 끝에서 얼마나 멀리 있는지 정확하게 측정 할 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.