Математика: Как крутить колесо перетаскиванием (Canvas, 2D)? - PullRequest
0 голосов
/ 09 января 2020

Я борюсь с, возможно, простой математикой, чтобы вращать / вращать колесо с помощью перетаскивания.

В Canvas (пользовательский интерфейс Unity) есть радиальная компоновка, и ее уже можно повернуть, установив свойство StartAngle это в диапазоне от 0 до 360. В этом Radial есть элементы, поэтому StartAngle предназначен для первого элемента и размещает все дочерние элементы по радиусу макета.

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

Прямо сейчас, у меня есть это как отправная точка:

public void OnDrag(PointerEventData eventData)
{
    var delta = eventData.delta.x * Time.deltaTime;
    var newAngle = radialLayout.StartAngle + delta;
    if (newAngle >= 360)
        newAngle = newAngle - 360;
    else if (newAngle < 0)
        newAngle = Mathf.Abs(360 - newAngle);
    radialLayout.StartAngle = newAngle;
}

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

Итак, как мне отобразить движение мыши на угол поворота от 0 до 360, чтобы он чувствовал хорошо?

Редактировать: Спасибо за помощь, я сделал это сейчас так:

public void OnDrag(PointerEventData eventData)
{
    // Note the "Head-Minus-Tale rule for Vector subtraction, see http://www.maths.usyd.edu.au/u/MOW/vectors/vectors-3/v-3-7.html
    //  vSourceToDestination = vDestination - vSource;

    // First, we draw a vector from the center point of the radial to the point where we started dragging
    var from = dragStartPoint - (Vector2)radialLayout.transform.position;
    // Next, we draw a vector from the center point of the radial to the point we are currently dragging on
    var to = eventData.position - (Vector2)radialLayout.transform.position;
    // Now, we calculate the angle between these two: 
    var dragAngle = Vector2.SignedAngle(from, to);

    // Lerping makes movement fast at the beginning slow at the end
    var lerpedAngle = Mathf.Round(Mathf.LerpAngle(radialLayout.StartAngle, dragAngle, 0.5f));
    radialLayout.StartAngle = lerpedAngle;
}

1 Ответ

0 голосов
/ 09 января 2020

Я не знаю весь ваш код и типы, но у меня есть идея. Я не могу проверить это прямо сейчас и не могу гарантировать, что это даже работает так, но я надеюсь, что идея проясняется.


Я бы лучше использовал что-то вроде

// This is the vector from the center of the object to the mouse/touch position
// (in screen pixel space)
var touchDirection = eventData.position - Camera.main.WorldToScreenPoint(transform.position);
// angle between the Up (Y) axis and this touchDirection
// for the angle the length of the up vector doesn't matter so there is 
// no need to convert it to pixel space
var targetAngle = Vector2.SignedAngle(Vector2.up, touchDirection);
// since the returned angle might be negative wrap it to get values 0-360
if(targetAngle < 0) targetAngle += 360;

// Now either simply use Lerp
// this would simply interpolate each frame to the middle of both values
// the result is a fast movement at the beginning and a very slow at the end
radialLayout.StartAngle = Mathf.Lerp(radialLayout.StartAngle, targetAngle, 0.5f);

// or maybe use a fixed speed like 30°/second
var difference = targetAngle - radialLayout.StartAngle;
radialLayout.StartAngle += Mathf.Sign(difference) * Mathf.Min(30f * Time.deltaTime, Mathf.Abs(difference));

Печатается на смартфоне, но я надеюсь, что идея проясняется

...