做功能时候,有时需要的不仅仅是unity的基础API,更是需要在此基础上进行加工成一些工具方法,这里放一些以前用到的功能的工具方法
自定义API
将两个UI的Recttransform属性相同
public void SetRecttransformAttrSame(RectTransform toSetRecttransform, RectTransform copyFromRectTransform)
{
toSetRecttransform.anchorMax = copyFromRectTransform.anchorMax;
toSetRecttransform.anchorMin = copyFromRectTransform.anchorMin;
toSetRecttransform.pivot = copyFromRectTransform.pivot;
toSetRecttransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, copyFromRectTransform.rect.width);
toSetRecttransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, copyFromRectTransform.rect.height);
toSetRecttransform.position = copyFromRectTransform.position;
}
得到当前屏幕分辨率与Canvas Scaler参考分辨率下的高度比或者宽度比,要求传入的RectTransform是全屏大小的
public static float GetResolutionWidthRatio(RectTransform canvasRect)
{
float currentResolutionWidth;
#if UNITY_EDITOR
int canvasDisplay = canvasRect.GetComponent<Canvas>().targetDisplay;
currentResolutionWidth = Display.displays[canvasDisplay].renderingWidth;
#else
currentResolutionWidth = Screen.currentResolution.width;
#endif
float ratio = (currentResolutionWidth * 1f) / Const.standardResolutionWidth;
return ratio;
}
public static float GetResolutionHeightRatio(RectTransform canvasRect)
{
float currentResolutionHeight;
#if UNITY_EDITOR
int canvasDisplay = canvasRect.GetComponent<Canvas>().targetDisplay;
currentResolutionHeight = Display.displays[canvasDisplay].renderingHeight;
#else
currentResolutionHeight = Screen.currentResolution.height;
#endif
float ratio = (currentResolutionHeight * 1f) / Const.standardResolutionHeight;
return ratio;
}
获得鼠标位置在UI中的局部坐标
public static Vector2 GetMouseLocalPos(Vector3 screenPos, Transform transform,
RenderMode _canvasMode, Camera _camera, float canvasDistance)
{
Vector3 worldPoint = screenPos;
switch (_canvasMode)
{
case RenderMode.ScreenSpaceCamera:
worldPoint = _camera.ScreenToWorldPoint( new Vector3(screenPos.x, screenPos.y, canvasDistance));
break;
case RenderMode.ScreenSpaceOverlay:
worldPoint = screenPos;
break;
}
Vector3 localPos = transform.InverseTransformPoint(worldPoint);
return localPos;
}
根据局部坐标获得对应的uv
public static Vector2 GetLocalPosUVCoordinate(Vector2 localPos, RectTransform rectTransform)
{
Vector2 remedyOffset =
new Vector2(
rectTransform.pivot.x * rectTransform.rect.width,
rectTransform.pivot.y * rectTransform.rect.height
);
Vector2 unormalizedLocalPosUVCoordinate = localPos + remedyOffset;
Vector2 localPosUVCoordinate =
new Vector2(
unormalizedLocalPosUVCoordinate.x / rectTransform.rect.width ,
unormalizedLocalPosUVCoordinate.y / rectTransform.rect.height
);
return localPosUVCoordinate;
}
将局部坐标转换为以屏幕中心为原点,向右为x轴正方向,向上为y轴正方向的相对坐标
public static Vector2 TransformLocalToScreenCenterPos(Vector2 localPos,
RectTransform rectTransform, Canvas canvas, Camera uiCamera, RenderMode canvasRenderMode)
{
switch (canvasRenderMode)
{
case RenderMode.ScreenSpaceOverlay:
return OverlayTransformLocalToCanvasCenterPos(localPos, rectTransform, canvas);
break;
case RenderMode.ScreenSpaceCamera:
return CameraTransformLocalToCanvasCenterPos(localPos, rectTransform, canvas, uiCamera);
break;
case RenderMode.WorldSpace:
return Vector2.zero;
break;
}
return Vector2.zero;
}
public static Vector2 OverlayTransformLocalToCanvasCenterPos(Vector2 localPos,
RectTransform rectTransform, Canvas canvas)
{
Vector2 screenCenterScreenPos = GetOverlayCanvasCenterScreenPos(canvas);
Vector2 posScreen = rectTransform.TransformPoint(localPos);
Vector2 oppositePos = posScreen - screenCenterScreenPos;
return oppositePos;
}
public static Vector2 CameraTransformLocalToCanvasCenterPos(Vector2 localPos,
RectTransform rectTransform, Canvas canvas, Camera uiCamera)
{
Vector2 screenCenterScreenPos = GetCameraCanvasCenterScreenPos(canvas);
Vector3 posWorld = rectTransform.TransformPoint(localPos);
Vector3 posScreen = uiCamera.WorldToScreenPoint(posWorld);
Vector2 oppositePos = new Vector2(posScreen.x, posScreen.y) - screenCenterScreenPos;
return oppositePos;
}
获取在ScreenSpace-Camera模式下的全屏大小的Canvas的屏幕中心坐标
public static Vector2 GetCameraCanvasCenterScreenPos(Canvas canvas)
{
RectTransform canvasRectTrn = canvas.GetComponent<RectTransform>();
Vector2 screenCenterScreenPos = new Vector2(
canvasRectTrn.rect.width / 2f,
canvasRectTrn.rect.height / 2f
);
return screenCenterScreenPos;
}
获取在ScreenSpace-Overlay模式下的全屏大小的Canvas的屏幕中心坐标
public static Vector2 GetOverlayCanvasCenterScreenPos(Canvas canvas)
{
RectTransform canvasRectTrn = canvas.GetComponent<RectTransform>();
Vector2 screenCenterScreenPos = new Vector2(
canvasRectTrn.rect.width / 2f,
canvasRectTrn.rect.height / 2f
);
return screenCenterScreenPos;
}
总结
二屏UI对一屏UI的映射
有个需求是将二屏的UI映射到一屏,这种映射需求虽然很少遇到,但还是记录一下。
RawImage映射
RawImage映射做法只能是这个Ui的Canvas是ScreenSpace-Camera,并且对应的Camera指定某个相机,相机再将结果映射到某个RenderTexture上面。这个RenderTexture覆盖二屏 Overlay的UI不能映射,因为相机看不到Overlay的UI,即使角度和位置调节得很对。
相机渲染Display2
前面的做法一样,但是相机直接是设置渲染目标是Display2.注意不能有其他的Display2的Overlay的UI或者其他Display2的深度更大的相机,不然渲染结果会被覆盖
直接复制
如果不考虑实时,这种方法是很省性能的。 将一屏的某部分UI用GameObject.Instantiate直接复制到二屏,复制的物体下面的所有子物体会一起复制过去。 注意被复制的物体的所有父物体的REctTransform的属性和复制出来的所有父物体的属性都一致,效果才有保证。
实时运行读取配置表生成位置时注意
举个例子,当Overlay的UI地图的碰撞点是在38402160的Canvas Scaler的ReferenceResolution分辨率下摆放的,这时摆放位点的宽高位置上限是3840和2160。当屏幕调节成其他屏幕分辨率的时候,例如变成了19201080,为了让摆放能够正确,需要根据实际的分辨率与参考分辨率得到比例,在这个的基础上进行重新计算位置。
|