【问题标题】:Get normalized click position on a RectTransform获取 RectTransform 上的标准化点击位置
【发布时间】:2021-08-13 06:00:12
【问题描述】:

我通过使用带有碰撞器的 UI 图像制作了一个 UI 触摸/点击控制器。用户界面是使用堆叠的相机渲染的。

我使用 IPointerDownHandler.OnPointerDown 来获取点击事件。 控制器应该给出一个 0-1 的值,具体取决于您单击它的距离。

我在 UI 上使用 Canvas Scaler 使控制器根据设备调整大小。但这会打乱我的计算,因为点击位置不会相同。这个应该怎么处理?现在,只有当我禁用 Canvas Scaler 或在具有默认尺寸的显示器上运行它时,计算才正确。

public void OnPointerDown(PointerEventData pointerEventData)
{

    SetAccelerationValue(pointerEventData.position.y);
}
    private void SetAccelerationValue(float posY)
{   
    float percentagePosition;
    var positionOnAccelerator = posY - minY;
    var acceleratorHeight = maxY - minY;
    percentagePosition = positionOnAccelerator / acceleratorHeight;
    

    Debug.Log(percentagePosition);

}

【问题讨论】:

  • 您是否尝试将您的acceleratorHeightpositionOnAccelerator 乘以变换比例?
  • 不,我没有。是 Canvas Scaler 使用的变换比例吗?我会试试的。

标签: unity3d


【解决方案1】:

我会使用RectTransformUtility.ScreenPointToLocalPointInRectangle 在给定RectTransform 的本地空间中获取位置。

然后将其与Rect.PointToNormalized结合起来

返回对应点的归一化坐标。

返回的Vector2 在 0 到 1 的范围内,值大于 1 或小于零。

RectTransform.rect (0,0) 中获得标准化位置 左下角 角,(1,1) 是 右上角

[SerializeField] private RectTransform _rectTransform;

private void Awake ()
{
    if(!_rectTransform) _rectTransform = GetComponent<RectTransform>();
}

private bool GetNormalizedPosition(PointerEventData pointerEventData, out Vector2 normalizedPosition)
{   
    normalizedPosition = default;

    // get the pointer position in the local space of the UI element
    // NOTE: For click vents use "pointerEventData.pressEventCamera"
    // For hover events you would rather use "pointerEventData.enterEventCamera"
    if(!RectTransformUtility.ScreenPointToLocalPointInRectangle(_rectTransform, pointerEventData.position, pointerEventData.pressEventCamera, out var localPosition)) return false;
    
    normalizedPosition = Rect.PointToNormalized(_rectTransform.rect, localPosition);
    // I think this kind of equals doing something like
    //var rect = _rectTransform.rect;
    //var normalizedPosition = new Vector2 (
    //    (localPosition.x - rect.x) / rect.width, 
    //    (localPosition.y - rect.y) / rect.height);  

    Debug.Log(normalizedPosition);

    return true;
}

由于归一化位置返回的值类似于

(0|1)-----(1|1)
  |         |
  |  (0|0)  |
  |         |
(0|0)-----(1|0)

但听起来你想要得到的是

 (-1|1)----(1|1)
   |         |
   |   0|0   |
   |         |
(-1|-1)----(1|-1)

所以你可以简单地使用例如移动返回的值

// Shift the normalized Rect position from [0,0] (bottom-left), [1,1] (top-right)
// into [-1, -1] (bottom-left), [1,1] (top-right)
private static readonly Vector2 _multiplcator = Vector2.one * 2f;
private static readonly Vector2 _shifter = Vector2.one * 0.5f;

private static Vector2 GetShiftedNormalizedPosition(Vector2 normalizedPosition)
{
    return Vector2.Scale((normalizedPosition - _shifter), _multiplcator);
}

所以最后你会使用例如

public void OnPointerDown(PointerEventData pointerEventData)
{
    if(!GetNormalizedPosition(pointerEventData, out var normalizedPosition)) return;

    var shiftedNormalizedPosition = GetShiftedNormalizedPosition(normalizedPosition);

    SetAccelerationValue(shiftedNormalizedPosition.y);

    // And probably for your other question also
    SetSteeringValue(shiftedNormalizedPosition.x);
}

当然,在SetAccelerationValue 内,您无需计算任何内容,只需设置值;)

这始终使用当前矩形,因此您不必存储任何最小值/最大值,它也适用于矩形的任何动态重新缩放。

这可能也适用于您的other almost duplicate question ;)

【讨论】:

  • OMFG 谢谢,谢谢,谢谢。正如你所说,它适用于所有情况。这也是很好的学习资料。我可以查看这些转换方法来找出我需要了解的有关屏幕和 ui 数学的知识。但是,Unity 是怎么回事。我无法理解我试图做的事情是如此罕见且难以找到解决方案。我会确保支付它并帮助其他人。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-02
  • 1970-01-01
  • 2015-09-26
  • 2020-12-13
相关资源
最近更新 更多