Элементы пользовательского интерфейса не масштабируются при использовании Canvas Scaler

Я пытаюсь заставить свои элементы пользовательского интерфейса работать и оставаться неизменными для каждого другого разрешения. Я добавил Canvas Scaler в свой Canvas и поиграл с настройками, пока все не выглядело законченным.

Затем я попытался собрать игру и запустить ее в нескольких разных разрешениях, чтобы убедиться, что она работает. Однако Canvas Scaler, похоже, не работает.

http://prntscr.com/d1afz6

Выше указано какое-то случайное разрешение, но это то, насколько велик мой экран редактора, и это то, что я использую в качестве эталонного разрешения. Это также иерархия для этого конкретного холста http://prntscr.com/d1aggx. При разрешении 640x480 занимает почти весь экран. Я понятия не имею, почему это не работает. Я прочитал большинство руководств по единству, но ни у кого из них, похоже, нет этой проблемы.


person mashinkata    schedule 31.10.2016    source источник
comment
Вероятно, это не вина скейлера. Вероятно, вы используете абсолютные координаты и размеры, которые не меняются с размером экрана.   -  person Chuck Savage    schedule 01.11.2016
comment
Можете ли вы быть немного более конкретным и разработать немного больше? Я не уверен, что означают абсолютные координаты и размеры, вы говорите о свойствах элементов пользовательского интерфейса или холста?   -  person mashinkata    schedule 01.11.2016


Ответы (1)


Хорошо, чтобы уместить что-то независимо от размера экрана, вы должны использовать отдельную систему координат, отличную от абсолютной системы Unity. Одной из моделей Unity является View. Вид имеет координаты 0,0 вверху слева и 1,1 внизу справа. Создание базового Rect, который обрабатывает это, заключается в следующем.

using UnityEngine;

namespace SeaRisen.nGUI
{
    public class RectAnchored
    {
        public float x, y, width, height;

        public RectAnchored(float x, float y, float width, float height)
        {
            this.x = x;
            this.y = y;
            this.width = width;
            this.height = height;
        }

        public static implicit operator Rect(RectAnchored r)
        {
            return new Rect
            {
                x = r.x * Screen.width,
                y = r.y * Screen.height,
                width = r.width * Screen.width,
                height = r.height * Screen.height
            };
        }
    }
}

Здесь мы берем обычные числа с плавающей запятой Rect, координаты x, y, а также ширину и высоту. Но это значения [0..1]. Я не зажимаю его, поэтому при желании его можно анимировать на экране и за его пределами с анимацией.

Ниже приведен простой сценарий, который создает кнопку в правом нижнем углу экрана и изменяет ее размер по мере увеличения или уменьшения экрана.

void MoveMe()
{
    RaycastHit hit;
    if (Physics.Raycast(transform.position, -Vector3.up, out hit, float.MaxValue)
        || Physics.Raycast(transform.position, Vector3.up, out hit, float.MaxValue))
        transform.position = hit.point + Vector3.up * 2;
}

void OnGUI()
{
    if (GUI.Button(new RectAnchored(.9f, .9f, .1f, .1f), "Fix me"))
    {
        MoveMe();
    }
}

X равен 0,9 вправо и Y 0,9 сверху, а ширина и высота равны 0,1, поэтому кнопка занимает 1/10 экрана по высоте и ширине, расположенная в нижней 1/10 экрана.

Поскольку OnGUI визуализируется каждый кадр (или около того), прямоугольник кнопки автоматически обновляется с изменением размера экрана. То же самое будет работать в типичном пользовательском интерфейсе, если вы используете Update() для рендеринга ваших окон.

Я надеюсь, что это объясняет разницу между тем, что я имел в виду с абсолютными координатами. Скажем, в предыдущем примере (с использованием абсолютных значений) в разрешении 640x480 это будет что-то вроде new Rect(576, 432, 64, 48), и оно не будет масштабироваться. Используя new RectAnchored(.9f, .9f, .1f, .1f) и визуализируя его в пространстве пользовательского интерфейса в зависимости от размера экрана, он автоматически масштабируется.

person Chuck Savage    schedule 01.11.2016