#c# #unity3d
Вопрос:
Вот простой сценарий, демонстрирующий проблему. Этот скрипт должен переместить курсор влево на 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, так и Вектор3, который мы добавляем, являются Вектором3, и я подумал, что могу обрабатывать числа с плавающей запятой, поэтому не уверен, почему все округляется до ints, если это то, что происходит?
Ответ №1:
Проблема
Значит, по какой-то причине все округляется до ближайшего целого числа?
Скорее всего, Да!
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. Я понимаю это, и это работает. Спасибо!
Ответ №2:
У меня нет никакого опыта использования 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
Счастливого кодирования!
Комментарии:
1. Я обновил свою операцию. Кажется, что какое-то очень странное поведение с добавлением Vector3 может быть причиной, но все еще не уверен