Почему я не могу использовать оператор '> =' с Vector3s? Does Steam уведомляет пользователя о том, что им нужна Java для игры, когда они покупают /загружают /устанавливают его? Framework или библиотека Game Engine [закрыто] Как создать математический механизм для сбалансированной игры? Дизайн игры Lexicon: терминология для драгоценных камней и т. д. [закрыто] Framerate влияет на скорость объекта. Вы рекомендуете хорошую книгу или проект для начинающих для молодого человека? [closed] Что такое самый простой жанр игры? [закрыто] Как я могу отмечать уровни как «завершенные» таким образом, чтобы предотвратить обман? Введение в игровые движки для детей [закрыто] Unity 3d 4 игрока В один момент можно нажать только 4 кнопки. Каковы некоторые хорошие ресурсы для создания игрового движка в XNA? [закрыто] Использование модифицированной музыки, защищенной авторским правом, в некоммерческих играх. Набирает точки на линии между двумя точками. Сколько «параллельных блоков» имеет графический процессор? 2D. Карты сверху вниз. Разрабатывание интересной игровой механики, когда не жадный игрок. Огре против Иррихта [закрыто]. Сколько память делает текстуру на GPU? Как я могу предотвратить читы модификации памяти?

Я пытаюсь получить прямоугольник для перемещения между двумя позициями, которые я называю _positionA и _positionB. Оба имеют тип Vector3. Прямоугольник движется просто отлично. Однако, когда он достигает _positionB, он не перемещается в противоположном направлении, как это должно быть.

Я вернулся в код, чтобы посмотреть. Я пришел к выводу, что по мере перемещения объекта операторы if в коде пропускали рамку, в которой позиция rects была равна ---- +: = 5 =: + ----. Я решил изменить код в обратном направлении, если позиция rects больше или равна _positionB. Мой код не слишком длинный, поэтому я покажу его ниже:

_positionB

Однако, когда я изменил его, он предупредил меня о следующем сообщении об ошибке:

  

Оператор> = не может применяться к операндам типа Vector3 и Vector3.

Это меня смущает по двум причинам; во-первых, оба значения имеют один и тот же тип данных. Во-вторых, использование оператора сравнения (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; } } } } ) по двум значениям работает без ошибок. Почему я не могу использовать оператор == с помощью >=

0 голосов | спросил DreddTrekkiterDaemoniorumAndrey RubshteinConfusedC 29 Jpm1000000pmFri, 29 Jan 2016 18:02:45 +030016 2016, 18:02:45

4 ответа


15

Чтобы упростить ответ, Vector3 является пользовательским struct, предоставляемый пространством имен UnityEngine. Когда мы создаем пользовательские типы class или struct , мы должны также определить его операторов . Таким образом, для оператора >= не существует логики по умолчанию. Как отметил Евгений Васильев , _rect_tfm.position == _positionB имеет смысл, так как мы можем напрямую проверить Vector3.x, Vector3.y и Vector3.z. _rect_tfm.position >= _positionB не имеет особого смысла из-за того, что Vector3 представлен тремя отдельными значениями.

Мы могли бы перегрузить класс Vector3, чтобы содержать подходящие операторы в теории , но это кажется довольно сложным , Вместо этого было бы проще просто расширить класс Vector3 с помощью подходящего метода . При этом кажется, что вы намереваетесь использовать эту логику для движения. Таким образом, вам может быть проще использовать метод Vector3.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 для перехода к targetPosition. После вызова метода Move в каждом Update , мы можем проверить, достигли ли мы указанной цели; Lerp.Vector3 превысит not , поэтому transform.position == targetPosition становится надежным. Теперь мы можем проверить позицию и изменить targetPosition на leftPosition или 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. Слепой неконтролируемый, синий куб уходит в небытие; в то время как красный куб точно останавливается там, где я его намерен. Вы можете больше узнать об этом типе движения в документации переполнения стека .

 Влево неконтролируемое, синий куб уходит в небытие, а красный куб точно останавливается там, где я его намерен.

ответил Gnemlock 1 Mayam17 2017, 04:02:24
28

Определение >= для Vector3 тип не имеет смысла. Что определяет, если один вектор больше другого? Их величина или их отдельные компоненты x, y, z?

Вектор представляет собой величину & ​​amp; направление. Итак, что определяет, какое направление больше?

Если вам нужно сравнить величины, вы можете использовать sqrMagnitude.

В этом случае Vector3 переопределяет == просто сравнить разные компоненты, чтобы убедиться, что они одинаковые. (в пределах порога)

Это та же самая причина, когда умножение двух векторов с использованием * невозможно. Просто нет математического способа сделать это. Некоторые люди используют * для точечного продукта, но это нечеткий дизайн API.

ответил Evgeny Vasilyev 30 PMpSun, 30 Apr 2017 22:25:10 +030025Sunday 2017, 22:25:10
0

Просто добавьте к тому, что размещено Gnemlock , относительно добавления методов расширения в класс Vector3. В Unity (и я уверен, что другие игровые движки) есть проблема с некоторыми операторами сравнения (==, <= и >=) между двумя значениями float, из-за того, как с плавающей запятой вычисление обрабатывается. 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;
    }
}
ответил Anthony 8 FebruaryEurope/MoscowbThu, 08 Feb 2018 22:16:33 +0300000000pmThu, 08 Feb 2018 22:16:33 +030018 2018, 22:16:33
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 <= patrolStart на оси Z. Наш «достигнутый или пройденный» оператор отличается от одной оси к другой, поэтому теперь нет четкого сопоставления между нашей концепцией прохождения порога и простой проверкой неравенства.

Но мы можем выделить только одну строку в 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();

В качестве бонуса, если вы нормализуете вектор оси перед его использованием, то все точечные продукты представляют расстояния, поэтому вы можете точно определить, насколько далеко вы находитесь с любого конца по оси перемещения.

ответил DMGregory 9 FebruaryEurope/MoscowbFri, 09 Feb 2018 04:31:38 +0300000000amFri, 09 Feb 2018 04:31:38 +030018 2018, 04:31:38

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132