总共有三种模式
最终选择Camera模式。RenderCamera选择另建一个UICamera专门渲染UI。UICamera设置 ClearFlags选择DepthOnly,CullingMask选择只渲染UI层,这里注意既然UICamera已经渲染了UI了,主摄像机就不要再选择渲染UI层了。
粒子特效layer要设为UI层,要不UICamera渲染不到。
粒子和其他UI的层级关系:
CanvasScaler/UI Scale Mode UI缩放模式 选择Scale With Screen Size
CanvasScaler/Reference Resolution 参考分辨率 选择美术提供的参考分辨率
CanvasScaler/Match 根据实际手机的分辨率选择0或者1
public class CanvasManager : MonoBehaviour
{
private void Awake()
{
if((float)Camera.main.pixelWidth / (float)Camera.main.pixelHeight >=
this.GetComponent().referenceResolution.x / this.GetComponent().referenceResolution.y)
{
this.GetComponent().matchWidthOrHeight = 0;
}
else
{
this.GetComponent().matchWidthOrHeight = 1;
}
}
}
这里主要是对UI的背景板做适配。要实现的效果是如果手机实际分辨率宽高比比参考分辨率高,即更宽,则以宽适配UI大小,这样UI背景板会在高度上切去一部分。如果手机实际分辨率宽高比比参考分辨率低,即更高,则以高适配UI大小,这样UI背景板会在宽度上切去一部分。即背景板始终会被切去一部分,而不会以黑边填充。
有两种屏幕坐标。
第一种input.mouseposition或者pointerhandler的eventdata.position等的输入坐标。这些坐标都是根据手机的实际分辨率给出的和参考分辨率无关,比如参考分辨率2048 * 1024,实际分辨率 1024 * 1024,输入点在屏幕中间,则mouseposition为 (512, 512)。
第二种Camera.main.WorldToScreenPoint(vecter3 position),将空间中的物体位置转换为屏幕坐标。如果是main camera的话,这里返回的坐标点是和第一种一样的。即看到场景中的物体,在屏幕上的坐标位置就是相当于输入坐标的位置。比如场景正中央的物体转化为屏幕坐标时,实际分辨率1024 * 1024 参考分辨率为 2048 * 1024,则屏幕坐标为(512, 512)。什么情况下不一样呢,就是camera有rendertexture,并且rendertexture的分辨率不是手机的实际分辨率。经常是参考分辨率。这时返回的坐标是参考分辨率的坐标。比如场景正中央的物体转化为屏幕坐标时,实际分辨率1024 * 1024 参考分辨率为 2048 * 1024,相机上的rendertexture分辨率为2048 * 1024,则屏幕坐标为(1024, 512)。
将屏幕坐标转化为anchorposition代码如下:
///
/// 必须是无拉伸的才可以调用这个方法,并且获取的是世界anchorPosition
///
///
///
public static Vector2 GetAnchorpositionByScreenPoint(Vector2 anchorMin, Vector2 anchorMax, Vector2 screenPoint, bool needScale = true)
{
Vector2 point = Vector2.zero;
float width = 0, height = 0;
float widthScale = (float)GameManager.Instance.referrenceWidth / (float)Camera.main.pixelWidth;
float heightScale = (float)GameManager.Instance.referrenceHeight / (float)Camera.main.pixelHeight;
float screenPointScale = widthScale <= heightScale ? widthScale : heightScale;
if (needScale)
{
screenPoint = screenPoint * screenPointScale;
}
if (widthScale <= heightScale)
{
width = GameManager.Instance.referrenceWidth;
height = Camera.main.pixelHeight * widthScale;
}
else
{
width = Camera.main.pixelWidth * heightScale;
height = GameManager.Instance.referrenceHeight;
}
//
if (anchorMin == Vector2.zero && anchorMax == Vector2.zero)
{
point = screenPoint;
}
if (anchorMin == Vector2.right * 0.5f && anchorMax == Vector2.right * 0.5f)
{
point = screenPoint - Vector2.right * width / 2;
}
if (anchorMin == Vector2.right && anchorMax == Vector2.right)
{
point = screenPoint - Vector2.right * width;
}
if (anchorMin == Vector2.up * 0.5f + Vector2.zero && anchorMax == Vector2.up * 0.5f + Vector2.zero)
{
point = screenPoint - Vector2.up * height / 2;
}
if (anchorMin == Vector2.up * 0.5f + Vector2.right * 0.5f && anchorMax == Vector2.up * 0.5f + Vector2.right * 0.5f)
{
point = screenPoint - Vector2.right * width / 2 - Vector2.up * height / 2;
}
if (anchorMin == Vector2.up * 0.5f + Vector2.right && anchorMax == Vector2.up * 0.5f + Vector2.right)
{
point = screenPoint - Vector2.right * width - Vector2.up * height / 2;
}
if (anchorMin == Vector2.up + Vector2.zero && anchorMax == Vector2.up + Vector2.zero)
{
point = screenPoint - Vector2.up * height;
}
if (anchorMin == Vector2.up + Vector2.right * 0.5f && anchorMax == Vector2.up + Vector2.right * 0.5f)
{
point = screenPoint - Vector2.right * width / 2 - Vector2.up * height;
}
if (anchorMin == Vector2.up + Vector2.right && anchorMax == Vector2.up + Vector2.right)
{
point = screenPoint - Vector2.right * width - Vector2.up * height;
}
return point;
}
这个函数可以将屏幕坐标转化为anchorposition,也就是在UI缩放适配的情况下,可以让UI元素比如button跟着鼠标走。前两个参数是recttransform 下的 anchorMax anchorMin,后者是输入坐标,最后一个参数是是否需要对输入的坐标缩放,默认是需要。除非你用相机的函数WorldToScreenPoint获取的屏幕坐标,并且这个相机还得设置了rendertexture,并且rendertexture的分辨率不是手机实际的分辨率。也就是说如果相机带有rendertexture慎用这个函数。
代码如下:
using System;
using UnityEngine;
public enum AnchorPresets
{
TopLeft,
TopCenter,
TopRight,
MiddleLeft,
MiddleCenter,
MiddleRight,
BottomLeft,
BottonCenter,
BottomRight,
BottomStretch,
VertStretchLeft,
VertStretchRight,
VertStretchCenter,
HorStretchTop,
HorStretchMiddle,
HorStretchBottom,
StretchAll
}
public enum NoStrechAnchorPresets
{
TopLeft,
TopCenter,
TopRight,
MiddleLeft,
MiddleCenter,
MiddleRight,
BottomLeft,
BottonCenter,
BottomRight,
BottomStretch,
}
public enum StrechAnchorPresets
{
VertStretchLeft,
VertStretchRight,
VertStretchCenter,
HorStretchTop,
HorStretchMiddle,
HorStretchBottom,
StretchAll
}
public enum PivotPresets
{
TopLeft,
TopCenter,
TopRight,
MiddleLeft,
MiddleCenter,
MiddleRight,
BottomLeft,
BottomCenter,
BottomRight,
}
public static class RectTransformExtensions
{
public static void SetStrechAnchor(this RectTransform source, PivotPresets pivot, StrechAnchorPresets allign, Vector2 anchorPosition, Vector2 sizeDelta,Vector2 leftbottom, Vector2 rightup)
{
SetPivot(source,pivot);
string sna = Enum.GetName(typeof(StrechAnchorPresets), allign);
SetAnchor(source,(AnchorPresets)Enum.Parse(typeof(AnchorPresets),sna), anchorPosition.x, anchorPosition.y);
switch (allign)
{
case StrechAnchorPresets.VertStretchLeft:
source.offsetMin = Vector2.up * leftbottom.y;
source.offsetMax = Vector2.up * -rightup.y;
source.sizeDelta = new Vector2(sizeDelta.x, -leftbottom.y - rightup.y);
break;
case StrechAnchorPresets.VertStretchCenter:
source.offsetMin = Vector2.up * leftbottom.y;
source.offsetMax = Vector2.up * -rightup.y;
source.sizeDelta = new Vector2(sizeDelta.x, -leftbottom.y - rightup.y);
break;
case StrechAnchorPresets.VertStretchRight:
source.offsetMin = Vector2.up * leftbottom.y;
source.offsetMax = Vector2.up * -rightup.y;
source.sizeDelta = new Vector2(sizeDelta.x, -leftbottom.y - rightup.y);
break;
case StrechAnchorPresets.HorStretchBottom:
source.offsetMin = Vector2.right * leftbottom.x;
source.offsetMax = Vector2.right * -rightup.x;
source.sizeDelta = new Vector2(-leftbottom.x - rightup.x, sizeDelta.y);
break;
case StrechAnchorPresets.HorStretchMiddle:
source.offsetMin = Vector2.right * leftbottom.x;
source.offsetMax = Vector2.right * -rightup.x;
source.sizeDelta = new Vector2(-leftbottom.x - rightup.x, sizeDelta.y);
break;
case StrechAnchorPresets.HorStretchTop:
source.offsetMin = Vector2.right * leftbottom.x;
source.offsetMax = Vector2.right * -rightup.x;
source.sizeDelta = new Vector2(-leftbottom.x - rightup.x, sizeDelta.y);
break;
case StrechAnchorPresets.StretchAll:
source.offsetMin = leftbottom;
source.offsetMax = -rightup;
break;
}
}
public static void SetNoStrechAnchor(this RectTransform source, PivotPresets pivot,NoStrechAnchorPresets allign, Vector2 anchorPosition, Vector2 sizeDelta)
{
SetPivot(source, pivot);
string sna = Enum.GetName(typeof(StrechAnchorPresets), allign);
SetAnchor(source, (AnchorPresets)Enum.Parse(typeof(AnchorPresets), sna), anchorPosition.x, anchorPosition.y);
source.sizeDelta = sizeDelta;
}
private static void SetAnchor(this RectTransform source, AnchorPresets allign, float offsetX = 0, float offsetY = 0)
{
source.anchoredPosition = new Vector3(offsetX, offsetY, 0);
switch (allign)
{
case (AnchorPresets.TopLeft):
{
source.anchorMin = new Vector2(0, 1);
source.anchorMax = new Vector2(0, 1);
break;
}
case (AnchorPresets.TopCenter):
{
source.anchorMin = new Vector2(0.5f, 1);
source.anchorMax = new Vector2(0.5f, 1);
break;
}
case (AnchorPresets.TopRight):
{
source.anchorMin = new Vector2(1, 1);
source.anchorMax = new Vector2(1, 1);
break;
}
case (AnchorPresets.MiddleLeft):
{
source.anchorMin = new Vector2(0, 0.5f);
source.anchorMax = new Vector2(0, 0.5f);
break;
}
case (AnchorPresets.MiddleCenter):
{
source.anchorMin = new Vector2(0.5f, 0.5f);
source.anchorMax = new Vector2(0.5f, 0.5f);
break;
}
case (AnchorPresets.MiddleRight):
{
source.anchorMin = new Vector2(1, 0.5f);
source.anchorMax = new Vector2(1, 0.5f);
break;
}
case (AnchorPresets.BottomLeft):
{
source.anchorMin = new Vector2(0, 0);
source.anchorMax = new Vector2(0, 0);
break;
}
case (AnchorPresets.BottonCenter):
{
source.anchorMin = new Vector2(0.5f, 0);
source.anchorMax = new Vector2(0.5f, 0);
break;
}
case (AnchorPresets.BottomRight):
{
source.anchorMin = new Vector2(1, 0);
source.anchorMax = new Vector2(1, 0);
break;
}
case (AnchorPresets.HorStretchTop):
{
source.anchorMin = new Vector2(0, 1);
source.anchorMax = new Vector2(1, 1);
break;
}
case (AnchorPresets.HorStretchMiddle):
{
source.anchorMin = new Vector2(0, 0.5f);
source.anchorMax = new Vector2(1, 0.5f);
break;
}
case (AnchorPresets.HorStretchBottom):
{
source.anchorMin = new Vector2(0, 0);
source.anchorMax = new Vector2(1, 0);
break;
}
case (AnchorPresets.VertStretchLeft):
{
source.anchorMin = new Vector2(0, 0);
source.anchorMax = new Vector2(0, 1);
break;
}
case (AnchorPresets.VertStretchCenter):
{
source.anchorMin = new Vector2(0.5f, 0);
source.anchorMax = new Vector2(0.5f, 1);
break;
}
case (AnchorPresets.VertStretchRight):
{
source.anchorMin = new Vector2(1, 0);
source.anchorMax = new Vector2(1, 1);
break;
}
case (AnchorPresets.StretchAll):
{
source.anchorMin = new Vector2(0, 0);
source.anchorMax = new Vector2(1, 1);
break;
}
}
}
private static void SetPivot(this RectTransform source, PivotPresets preset)
{
switch (preset)
{
case (PivotPresets.TopLeft):
{
source.pivot = new Vector2(0, 1);
break;
}
case (PivotPresets.TopCenter):
{
source.pivot = new Vector2(0.5f, 1);
break;
}
case (PivotPresets.TopRight):
{
source.pivot = new Vector2(1, 1);
break;
}
case (PivotPresets.MiddleLeft):
{
source.pivot = new Vector2(0, 0.5f);
break;
}
case (PivotPresets.MiddleCenter):
{
source.pivot = new Vector2(0.5f, 0.5f);
break;
}
case (PivotPresets.MiddleRight):
{
source.pivot = new Vector2(1, 0.5f);
break;
}
case (PivotPresets.BottomLeft):
{
source.pivot = new Vector2(0, 0);
break;
}
case (PivotPresets.BottomCenter):
{
source.pivot = new Vector2(0.5f, 0);
break;
}
case (PivotPresets.BottomRight):
{
source.pivot = new Vector2(1, 0);
break;
}
}
}
}
总共两个函数一个设置有拉伸(四个锚点没有聚成一个花)的锚点信息: SetStrechAnchor,一个设置无拉伸(四个锚点聚在一块)的锚点信息:SetNoStrechAchor。
pivot, anchors, anchorPosition, sizeDelta,left_buttom_right_up,五个值需要一块填入。
pivot元素的中心点,总共6种。
StrechAnchorPresets 总共有7种拉伸模式,在inspector界面可以看到
anchors在inspector界面可以看到就在pivot设置的上面 有min 和max两个vector2数值。
anchorPosition x, y 两个数值inspector界面有显示就填入数值没显示就填0
sizeDelta x,y 两个数值inspector界面有显示就填入数值没显示就填0
leftbottom x,y 两个数值inspector界面有显示就填入数值没显示就填0 x代表left y代表bottom
rightup x,y 两个数值inspector界面有显示就填入数值没显示就填0 right y代表up