Unity UGUI screen adaptation

Unity UGUI screen adaptation

In order for the project to run normally on various electronic devices, we need to make UGUI display normally in various resolutions and ratios. In order to achieve this goal we need to do UGUI screen adaptation. In addition, the adaptation of the camera is not discussed in this article.

basic knowledge

First of all, we need to understand the relevant knowledge of mobile phone screen resolution .
In the process of screen adaptation, we mainly focus on:

  1. The aspect ratio of the screen (Aspect Ratio, screen width/screen height). Adjustments can be made in Unity's Game view.
  2. The game's design resolution. It is the resolution of the UI when designing the interface. A relatively small design resolution will reduce the size of the installation package, the size of the memory footprint, etc. But it may become blurry on large screen devices.

Adaptation scheme

Since UGUI is displayed on the interface through Canvas, the RenderMode property of Canvas needs to be adjusted to Screen Space - Camera.
When the screen resolution of the actual device is inconsistent with the design resolution, CanvasScalerthe scaling is performed through the component. CanvasScalerComponents Canvasare created automatically upon creation.
CanvasScalerThe main parameters to be adjusted by the component are UIScaleMode. For specific parameters, please refer to the Canvas Scaler . Since the design resolution cannot perfectly correspond to the screen resolution, we need to select Scale With Screen Sizeoptions to ensure that the UI will zoom in or out with the screen.

Optional adaptations:

  1. Scale proportionally to the short side
  2. Scale proportionally according to the short side, and adapt to the long side. Adaptation can be handled through Anchors and Pivot.

In addition, mobile phones now have heterosexual screens that also need to be processed. The processing method is to use Screen.safeArea to calculate and set the relevant content of the Panel to avoid the safe area.

Experimental treatment

For the convenience of development, the concept of a Panel can be abstracted. Panel is the parent node of an interface. We can control the size of the panel according to the adaptation scheme, so that all UIs under this node do not need to consider the adaptation logic. It only needs to be processed with methods such as anchor points.
First build a test scene as follows:
testscene
Canvas is our canvas, AdaptiveCanvasthe script is mounted
Panel is one of our interfaces, AdaptivePanelthe script
Bg is mounted is a comparison without adaptation, and the two squares are fixed on the upper left and lower right

Note: The code always calculates the ratio and adapts it in Update. In actual projects, it needs to handle it by sending events or other methods.

public enum AdaptivePlan
{
    
    
    Match, // 通过自适应适配,尽量填充满屏幕
    Expand, // 比例实在夸张无法适配,采用固定尺寸,其他区域留白的方式处理
}

public class AdaptiveCanvas : MonoBehaviour
{
    
    
    public static AdaptiveCanvas Instance;
    public Vector2 referenceResolutoin = new Vector2(750, 1334);

    public AdaptivePlan adaptivePlan;
    private float lastwidth = 0f;
    private float lastheight = 0f;

    CanvasScaler canvasScaler;

    private void Awake()
    {
    
    
        Instance = this;
        canvasScaler = GetComponent<CanvasScaler>();
        canvasScaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize;
        canvasScaler.referenceResolution = referenceResolutoin;
    }
    void Update()
    {
    
    
        CheckResolution();
    }
    private void CheckResolution()
    {
    
    
        if (lastwidth != Screen.width || lastheight != Screen.height)
        {
    
    
            lastwidth = Screen.width;
            lastheight = Screen.height;
            Adaptive();
        }
    }
    private void Adaptive()
    {
    
    
        // 一般情况下竖屏游戏的短边是宽,横屏游戏的短边是高
        bool shortSideIsWidth = Screen.width < Screen.height ? true : false;

        float ratio = (float)Screen.width / Screen.height;
        // Debug.Log($"width: {Screen.width}  height: {Screen.height} ratio: {ratio}");

        if (shortSideIsWidth)
        {
    
    
            if (ratio < 0.4f || ratio > 0.6f) // 比例实在太离谱,为保证游戏可用采取拓展画布区域
            {
    
    
                canvasScaler.screenMatchMode = CanvasScaler.ScreenMatchMode.Expand;
                adaptivePlan = AdaptivePlan.Expand;
                return;
            }
            canvasScaler.screenMatchMode = CanvasScaler.ScreenMatchMode.MatchWidthOrHeight;
            canvasScaler.matchWidthOrHeight = 0;
            adaptivePlan = AdaptivePlan.Match;
        }
        else
        {
    
    
            if (ratio < 1.6f || ratio > 2.5f) // 类型长方形比例
            {
    
    
                canvasScaler.screenMatchMode = CanvasScaler.ScreenMatchMode.Expand;
                adaptivePlan = AdaptivePlan.Expand;
                return;
            }
            // 比例在合适范围内使用短边适配的方案
            canvasScaler.screenMatchMode = CanvasScaler.ScreenMatchMode.MatchWidthOrHeight;
            canvasScaler.matchWidthOrHeight = 1;
            adaptivePlan = AdaptivePlan.Match;
        }
    }
}
public class AdaptivePanel : MonoBehaviour
{
    
    
    RectTransform rectTrans;
    // Start is called before the first frame update
    void Start()
    {
    
    
        rectTrans = transform as RectTransform;
    }

    private void Update()
    {
    
    
        if (AdaptiveCanvas.Instance.adaptivePlan == AdaptivePlan.Match)
        {
    
    
            rectTrans.localScale = Vector3.one;
            UpdateAdaptive();
            rectTrans.anchorMin = Vector2.zero;
            rectTrans.anchorMax = Vector2.one;
            rectTrans.offsetMin = Vector2.zero;
            rectTrans.offsetMax = Vector2.zero;
        }
        else if (AdaptiveCanvas.Instance.adaptivePlan == AdaptivePlan.Expand)
        {
    
    
            rectTrans.localScale = Vector3.one;
            UpdateAdaptive();
            rectTrans.anchorMin = Vector2.one * 0.5f;
            rectTrans.anchorMax = Vector2.one * 0.5f;
            rectTrans.offsetMin = Vector2.zero;
            rectTrans.offsetMax = Vector2.zero;

            rectTrans.sizeDelta = AdaptiveCanvas.Instance.referenceResolutoin;
        }
    }
	// 使用safeArea适配异性屏
    void UpdateAdaptive()
    {
    
    
        var r = Screen.safeArea;
        Vector2 anchorMin = r.position;
        Vector2 anchorMax = r.position + r.size;
        anchorMin.x /= Screen.width;
        anchorMin.y /= Screen.height;
        anchorMax.x /= Screen.width;
        anchorMax.y /= Screen.height;
        rectTrans.anchorMin = anchorMin;
        rectTrans.anchorMax = anchorMax;
    }
}

Guess you like

Origin blog.csdn.net/qq_36433883/article/details/125653050
Recommended