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

public class dumbtestscript : MonoBehaviour
{

    void Start()
    {
        Mouse.current.WarpCursorPosition(new Vector3(123, 123));

        StartCoroutine(MoveCursorLeftThenRightCoroutine());
    }

    IEnumerator MoveCursorLeftThenRightCoroutine()
    {
        float startTime = Time.time;
        while (Time.time < startTime + 1)
        {
            Mouse.current.WarpCursorPosition(Input.mousePosition + 

                (Time.deltaTime * new Vector3(-0.1f, 0)));

            yield return null;
        }

        while (Time.time < startTime + 2)
        {
            Mouse.current.WarpCursorPosition(Input.mousePosition + 

                (Time.deltaTime * new Vector3(0.1f, 0)));

            yield return null;
        }

    }
}

Я что-то не понимаю в том, как должен работать WarpCursorPosition?

Любые советы приветствуются. Спасибо.

Изменить: при дальнейшем осмотре это может быть связано с передачей вектора в WarpCursorPosition. Например, независимо от того, используем ли мы это для перемещения влево:

Mouse.current.WarpCursorPosition(Input.mousePosition + new Vector3(-0.1f, 0));

Или это:

 Mouse.current.WarpCursorPosition(Input.mousePosition + new Vector3(-1f, 0));

Он движется влево с той же скоростью. Кажется, что все между -0,1 и -1 округляется до -1. И наоборот, для правильного выполнения все от 0,1 до чуть меньше 1 округляется до 0, что объясняет, почему оно не двигалось в оригинале.

Значит, по какой-то причине все округляется до ближайшего целого числа? И Input.mousePosition, и Vector3, которые мы добавляем, являются Vector3, и я подумал, что может обрабатывать числа с плавающей запятой, поэтому не уверен, почему все округляется до целых чисел, если это то, что происходит?

0
user8810083 15 Сен 2021 в 11:09

2 ответа

Лучший ответ

Проблема

Значит, по какой-то причине все округляется до ближайшего целого числа?

Скорее всего, Да!

WarpCursorPosition делает ваш фактический системный курсор переместится к заданным пиксельным координатам .

В то время как внутри Unity пространство пикселей всегда предоставляется как float для многих вещей и в основном для выполнения с ним прямых вычислений, фактический системный курсор использует пиксели (как и все, что на самом деле происходит на экране ), которые всегда являются полными значениями int!

Так что да, он всегда (не круглый, а скорее) сводит введенные вами данные к следующему int (полный пиксель). В основном, что происходит, если вы просто используете

var x = (int) (Input.mousePosition.x - 0.1f);

=> Вы увидите, что x будет точно Input.mousePosition.x - 1, поскольку, например, текущий Input.mousePosition.x был 230, тогда вы получите (int) 229.9f, который равен 229.

В другом направлении вы получите, например, 230 + 0.1f так что (int) 230.1f снова просто 230.

=> Шаги должны составлять как минимум один полный пиксель !


Решение

Поэтому вместо постоянного чтения текущего Input.mousePosition, который лежит в основе вышеупомянутых координат пикселей, лучше используйте и обновляйте локальный вектор, который не:

IEnumerator MoveCursorLeftThenRightCoroutine()
{
    // Store the current mousePosition as a Vector2
    // This uses floats and is not restricted to full pixel jumps
    var currentPosition = Input.mousePosition;

    for(var passedTime = 0f; passedTime < 1; passedTime += Time.deltaTime)
    {
        // simply continously add to the float vector
        currentPosition +=  Vector2.left * speedInPixelsPerSecond * Time.deltaTime;
        // Using that float vector as input may in some frames cause no movement where the clamp results
        // still in the same pixel but it will catch up as soon as the vector was increased/reduced enough
        Mouse.current.WarpCursorPosition(currentPosition);               

        yield return nnull;
    }

    for(var passedTime = 0f; passedTime < 1; passedTime += Time.deltaTime)
    {
        currentPosition +=  Vector2.right * speedInPixelsPerSecond * Time.deltaTime;
        Mouse.current.WarpCursorPosition(currentPosition);

        yield return null;
    }
}

В целом для новой системы ввода я бы предпочел использовать Mouse.current.position вместо Input.mousePosition.

1
derHugo 16 Сен 2021 в 10:20

У меня нет опыта использования WarpCursorPosition, но когда я экспериментировал, чтобы ответить на эту тему, я почувствовал, что это непоследовательно, и хотел бы посоветовать не использовать его.


Код

using System.Collections;
using UnityEngine;
using UnityEngine.InputSystem;

public class Q69189325 : MonoBehaviour
{
    private void Start()
    {
        Mouse.current.WarpCursorPosition(Input.mousePosition);
        StartCoroutine(MoveLogicCrt());
    }

    IEnumerator MoveLogicCrt()
    {
        yield return MoveCursorToDirectionCrt(Vector3.left, 150, 5);
        yield return null;
        yield return MoveCursorToDirectionCrt(Vector3.right, 350, 5);
    }

    private IEnumerator MoveCursorToDirectionCrt(Vector3 direction, float speed, float movementTime)
    {
        float startTime = Time.time;

        while(Time.time < startTime + movementTime)
        {
            Vector2 newMousePosition = Input.mousePosition + (Time.deltaTime * direction * speed);
            Mouse.current.WarpCursorPosition(newMousePosition);
            yield return null;
        }
    }
}

Примечание.

По какой-то причине, когда я устанавливаю одинаковую скорость и влево, и вправо, она не движется вправо, что было странно.


Обзор выполнения

https://gfycat.com/eventhriftyannelida

Удачного кодирования!

0
GhAyoub 15 Сен 2021 в 09:49