鼠标拖动方向公差

Mouse drag direction tolerance

我正在开发一款 2D 游戏,玩家可以在其中拖动方块。它的工作方式是玩家点击并按住一个方块,然后根据玩家移动鼠标的方向决定拖动方向。

然而,问题是这过于敏感了。通常情况下,玩家开始拖动并想垂直拖动,但由于鼠标灵敏度的原因,结果却是水平拖动(反之亦然)。

有没有人知道如何为这种拖动行为添加容忍阈值?我代码中的相关部分基本上是这样的:

private void Update()
{
    if (_isMouseDown && sourceTile != null)
    {
        _isDraggingTile = true;

        /* Determine drag direction and drag target cell. */
        Vector3 dragDistance = Input.mousePosition - _originMousePosition;
        dragDistance.Normalize();
        if (_dragDirection == DragDirection.None)
        {
            float f = Vector3.Dot(dragDistance, Vector3.up);

            /* Mouse up drag. */
            if (f >= 0.5f)
            {
                _dragDirection = DragDirection.Up;
                _dragTargetCell = sourceTile.gridCell.upNeighbor;
            }
            /* Mouse down drag. */
            else if (f <= -0.5f)
            {
                _dragDirection = DragDirection.Down;
                _dragTargetCell = sourceTile.gridCell.downNeighbor;
            }
            else
            {
                /* Mouse right drag. */
                f = Vector3.Dot(dragDistance, Vector3.right);
                if (f >= 0.5f)
                {
                    _dragDirection = DragDirection.Right;
                    _dragTargetCell = sourceTile.gridCell.rightNeighbor;
                }
                /* Mouse left drag. */
                else if (f < -0.5f)
                {
                    _dragDirection = DragDirection.Left;
                    _dragTargetCell = sourceTile.gridCell.leftNeighbor;
                }
            }
        }

        if (_dragTargetCell != null)
        {
            // Take care of moving the dragged tile!
        }
    }
}

简单地将 dragDistance 的计算延迟一些帧并不会很好地工作。我认为需要的是一个解决方案来确定鼠标的移动并决定它在哪个轴上移动得最远。像上面那样确定拖动方向可能永远不会很好。

我认为您应该在拖动后立即创建一个大小有限的位置队列。

通过比较队列的最终值和第一个值可以找到方向。

如果你想获得更好的结果,你可以使用 Variance of positions 并获得更好的结果。

任何信息收集的问题都是噪音。在您的情况下,噪音是由用户的错误动作定义的。尽管如此,应该可以通过对值进行平均来最小化噪声的影响。

DSP 中使用了高级算法,但我想您的情况应该对信息进行基本平均。

您可以尝试的是,不要像您那样立即在更新中移动,而是收集几帧的移动,然后对所有这些帧进行平均,看看它是否变得更好:

IEnumerator GetAverageMovement(Action<Vector3> result)
{
    int frames = 0; 
    List<Vector3>list = new List<Vector3>();
    while(frames < 30f) // half a second appr
    {
        list.Add(GetDirection());
        frames++;
        yield return null;
    }
    result(AverageAllValues()); 
}

GetDirection 只是返回当前位置和上一个位置之间的增量,AverageAllValues 只是将列表中的所有值相加并除以 list.Count(又名 30)。

这应该可以解决用户一直向右移动但最后向上移动的情况。最后一点应该被大的右运动取消。

如果这还不够,那么您可以在方法中添加一些逻辑,如果某个值与平均值相差太大,则将其丢弃。我认为你不需要这个。