【问题标题】:Math: How to spin a wheel by drag&drop (Canvas, 2D)?数学:如何通过拖放(Canvas,2D)旋转轮子?
【发布时间】:2020-01-09 16:11:19
【问题描述】:

我正在努力使用拖放来旋转/旋转轮子,这可能是简单的数学运算。

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;
}

有点效果,但感觉不是很流畅。这是针对移动/触摸的,因此我希望同时考虑拖动操作的 X 和 Y 增量。显然,在我的示例中没有考虑 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;
}

【问题讨论】:

  • 如果应用猜错用户尝试与径向菜单(旋转/线性)交互的方式,这可能会严重混淆用户。考虑选择一种交互方式和代码,或者可选地有一个布尔值来确定它的解释方式,玩家可以选择他们更喜欢线性交互还是旋转交互。

标签: unity3d drag-and-drop


【解决方案1】:

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


我可能宁愿使用类似的东西

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

在智能手机上输入,但我希望思路清晰

【讨论】:

    猜你喜欢
    • 2012-05-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-18
    • 2022-01-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多