Хорошо, поэтому я пытаюсь использовать аналоговый джойстик на геймпаде, чтобы перемещать курсор мыши на рабочем столе. Проблема в том, что мне нужно иметь возможность получить ту же плавность, что и при попытке 2, но без использования абсолютного положения мыши. Курсор должен быть перемещен относительно его текущей позиции. Причина этого заключается в том, что многие приложения (в основном видеоигры) также устанавливают мышь в абсолютное положение. Это вызывает приложение и попытку 2 сражаться друг с другом за контроль над мышью.
Попытка 1 (относительная)
// keep updating the controller state and mouse position
while (true)
{
// getState returns a 2d float vector with normalized values from [-1, 1]
// The cursor is being set relative to its current position here.
SetCursorPosition(GetCursorPosition() + analogStick->getState());
}
Это решение работает, но страдает от проблемы округления, потому что GetCursorPosition и SetCursorPosition основаны на целых числах. В результате небольшие движения не регистрируются, потому что меньшие аналоговые движения всегда будут усечены. Визуально говоря, небольшие движения на аналоговой ручке будут перемещать мышь только вдоль оси X или Y, даже если вы пытаетесь сделать диагональное движение.
Попытка 2 (абсолютная)
vec2 mouseTargetPosition = GetCursorPosition(); // global cursor position
while (true)
{
mouseTargetPosition += leftStick->getState();
vec2 newPosition = lerp(GetCursorPos(), mouseTargetPosition, 0.8f);
SetCursorPos(round(newPosition.x), round(newPosition.y));
}
Это решение прекрасно работает, мышь реагирует на малейшие движения и движется очень естественно в результате интерполяции накопленных аналоговых движений. Но он устанавливает мышь в абсолютное положение (mouseTargetPosition), что делает это решение прерывателем сделки.
Я полагаю, это очень специфический вопрос. После того, как дурачиться с несколькими конфигурациями, это тот, который чувствует себя гладким и работает хорошо. Это в основном волшебство, учитывая, что он может добавить поддержку аналоговых ощущений для игр и зрителей, у которых ее нет 🙂
vec2 mouseTargetPos, mouseCurrentPos, change;
while (true)
{
// Their actual position doesn't matter so much as how the 'current' vector approaches
// the 'target vector'
mouseTargetPos += primary->state;
mouseCurrentPos = util::lerp(mouseCurrentPos, mouseTargetPos, 0.75f);
change = mouseTargetPos - mouseCurrentPos;
// movement was too small to be recognized, so we accumulate it
if (fabs(change.x) < 0.5f) accumulator.x += change.x;
if (fabs(change.y) < 0.5f) accumulator.y += change.y;
// If the value is too small to be recognized ( < 0.5 ) then the position will remain the same
SetCursorPos(GetCursorPos() + change);
SetCursorPos(GetCursorPos() + accumulator);
// once the accumulator has been used, reset it for the next accumulation.
if (fabs(accumulator.x) >= 0.5f) accumulator.x = 0;
if (fabs(accumulator.y) >= 0.5f) accumulator.y = 0;
}
Других решений пока нет …