数学:如何通过拖放(Canvas, 2D)来旋转轮子?

Math: How to spin a wheel by drag&drop (Canvas, 2D)?

我正在努力使用可能简单的数学运算 spin/rotate 使用拖放的轮子。

Canvas(Unity UI)中有一个径向布局,它已经可以通过设置一个名为 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;
}

有点效果,但感觉不是很流畅。这是针对 mobile/touch,因此我希望同时考虑拖动操作的 X 和 Y 增量。显然,我的例子中没有考虑 y 增量,我不知道如何正确地合并它。用户可能会在任一轴上进行线性拖放,或者 he/she 也可能会像圆形拖动一样进行。

那么如何将鼠标移动映射到 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;
}

我不知道你所有的代码和类型,但我有一个想法。我现在无法对此进行测试,也无法保证它甚至可以像这样工作,但我希望这个想法变得清晰。


我可能更愿意使用

// 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));

在智能手机上打字,但我希望思路清晰