Unity anchoredPosition转localPosition

发布时间 2023-10-26 17:11:35作者: lunoctis

参考 https://zhuanlan.zhihu.com/p/119442308
在已经有结果的情况下,先捋一下unity对相关字段的注释就能得出很多公式
(rectMinPos表示左下角在父节点坐标系中的位置,其他以"Pos"结尾的字段同理)

pivot: The normalized position in this RectTransform that it rotates around.
  pivot: 旋转中心点的归一化位置(使用自己的宽高归一化)
  pivotPos = rectMinPos + rect.size * pivot

localPosition: Position of the transform relative to the parent transform
  localPosition: 相对于父节点的位置
  对于一个RectTransform自己,可以判断localPosition2D和pivotPos就是同一个点
  localPosition2D = pivotPos

rect.min: The position of the minimum corner of the rectangle.
  rect.min: 左下角的位置(相对于谁?应该是中心点pivot坐标)
  rect.max: 右上角的位置
  rectMinPos = rect.min + pivotPos
  rectMaxPos = rect.max + pivotPos

anchorMin: The normalized position in the parent RectTransform that the lower left corner is anchored to.
  anchorMin: 左下角相对于父节点(左下角)的归一化位置(使用父节点宽高归一化)
  anchorMax: 右上角相对于父节点的归一化位置
  anchorMin = (anchorMinPos - parentRect.min) / parentRect.size
  anchorMax = (anchorMaxPos - parentRect.min) / parentRect.size
  anchorMinPos = parentRect.min + anchorMin * parentRect.size
  anchorMaxPos = parentRect.min + anchorMax * parentRect.size

anchoredPosition: The position of the pivot of this RectTransform relative to the anchor reference point.
  anchoredPosition: 中心点相对于"the anchor reference point"的位
  anchoredPosition = pivotPos - (anchorMinPos + (anchorMaxPos - anchorMinPos) * pivot)

offsetMin: The offset of the lower left corner of the rectangle relative to the lower left anchor
  offsetMin: 左下角相对于左下锚点的偏移
  offsetMax: 右上角相对于右上锚点的偏移
  offsetMin = rectMinPos - anchorMinPos
  offsetMax = rectMaxPos - anchorMaxPos

sizeDelta: The size of this RectTransform relative to the distances between the anchors.
  sizeDelta: 宽高与锚点之间宽高的差值
  sizeDelta = rect.size - (anchorMaxPos - anchorMinPos)
            = (rectMaxPos - rectMinPos) - (anchorMaxPos - anchorMinPos)
            = (rectMaxPos - anchorMaxPos) - (rectMinPos - anchorMinPos)
            = offsetMax - offsetMin

1. 从localPosition到anchoredPosition


// 计算自身的anchoredPosition(直接从RectTransform获取即可,这里只演示推导流程,没有实用性)
public static Vector2 GetAnchoredPosition(RectTransform transform)
{
    /* 计算推导
        anchoredPosition = pivotPos - (anchorMinPos + (anchorMaxPos - anchorMinPos) * pivot)
            到这里其实就已经可以算了, 只是步骤多一点, 继续化简以达到参考文章的公式
            代入 sizeDelta = rect.size - (anchorMaxPos - anchorMinPos)
        anchoredPosition = pivotPos - anchorMinPos - (rect.size - sizeDelta) * pivot
            代入 pivotPos = localPosition2D = rectMinPos + rect.size * pivot
        anchoredPosition = rectMinPos + rect.size * pivot - anchorMinPos - rect.size * pivot + sizeDelta * pivot
                         = rectMinPos - anchorMinPos + sizeDelta * pivot
            代入 offsetMin = rectMinPos - anchorMinPos
        anchoredPosition = offsetMin + sizeDelta * pivot
    */

    if (transform == null || transform.Equals(null)) return Vector2.zero;
    return transform.offsetMin + sizeDelta * pivot;
}

public static Vector2 LocalToAnchoredPosition(RectTransform transform, Vector2 localPosition2D)
{
    if (transform == null || transform.Equals(null)) return Vector2.zero;
    RectTransform parent = transform.parent?.GetComponent<RectTransform>();
    if (parent == null) return Vector2.zero;

    // 在传入localPosition2D的情况下, 就不能使用刚才化简的结果了, 使用最早一版的公式
    Rect parentRect = parent.rect;
    Vector2 pivot = transform.pivot;
    Vector2 anchorMin = transform.anchorMin;
    Vector2 anchorMax = transform.anchorMax;
    Vector2 anchorMinPos = parentRect.min + anchorMin * parentRect.size;
    Vector2 anchorMaxPos = parentRect.min + anchorMax * parentRect.size;

    return localPosition2D - (anchorMinPos + (anchorMaxPos - anchorMinPos) * pivot);
}

2. 从anchoredPosition到localPosition

// 刚才的函数反向一下即可
public static Vector2 AnchoredToLocalPosition(RectTransform transform, Vector2 anchoredPosition)
{
    if (transform == null || transform.Equals(null)) return Vector2.zero;
    RectTransform parent = transform.parent?.GetComponent<RectTransform>();
    if (parent == null) return Vector2.zero;

    Rect parentRect = parent.rect;
    Vector2 pivot = transform.pivot;
    Vector2 anchorMin = transform.anchorMin;
    Vector2 anchorMax = transform.anchorMax;
    Vector2 anchorMinPos = parentRect.min + anchorMin * parentRect.size;
    Vector2 anchorMaxPos = parentRect.min + anchorMax * parentRect.size;

    return anchoredPosition + (anchorMinPos + (anchorMaxPos - anchorMinPos) * pivot);
}