как узнать глобальные координаты объекта unity
Разновидности координат используемые в GUI Unity3d
Почему разновидности и сколько их?
Часто сталкиваюсь с тем, что люди просто не понимают как подвинуть объект в UI на какое то значение, и удивляются что результат зачастую непредсказуем. Или допустим как получить правильные координаты объекта в UI. Если мы через дебагер выведем обычную позицию объекта(position), то она будет сильно отличаться от той что мы видим в инспекторе у UI элемента, так что же мы там видим и как это работает? В итоге перебираются 100500 решений с форумов пока какое либо не подойдет. Хочу придать подобным процессам осмысленное движение.
Суть подвоха заключается в следующем — у обычного Transform есть потомок RectTransform который и отвечает за положение и многие вещи связанные с размером, скейлом и тд — элемента UI. И благодаря ему мы можем получить следующие варианты координат.
Обычная позиция
Обычная позиция не относится к системе координат UI от слова вообще. Это некие общие координаты объекта во всём мире юнити, и в мире некое представление позиции объекта которое не связано с интерфейсом.Eсли вы захотите сдвинуть объект на его ширину, это не сработает, так как у канваса координаты в пикселях относительно экрана. А в глобальных координатах это не пиксели. Поэтому объект сместится в мире допустим на 200 единиц измерения мира, а не на 200 пикселей, и просто улетит в неведомые дали. Но это можно разумно использовать. Позже расскажу как.
Якорная позиция (anchoredPosition)
То что мы видим в инспекторе — и есть оно.
В юнити можно выставлять якорные точки, это некая точка относительно которой будет позиционироваться UI элемент, в том числе при изменениях размера/пропорций родительского объекта.
Вот тут видно что мы поменяли размер родительского объекта и пропорции, наш объект придерживается центра родительского объекта, и его координаты не изменились, хотя на экране он уже не на том месте что раньше.
Якорная позиция — координаты объекта относительно якоря. Выставим якорь в левый верхний угол и увидим что координаты изменились.
Если вы хотите сместить объект на его ширину, то надо менять anchoredPosition или localPosition. Локальная позиция для UI элементов тоже вычисляется в пикселях, но по другому. Поэтому если вам нужно манипулировать двумя UI элементами относительно друг друга. То лучше использовать локальную позицию. Почему же?
Локальная позиция (localPosition)
Итак, что же такое локальная позиция:
Для чего можно использовать обычный position для UI элементов? Скажем так, в рамках глобальных координат, если одному объекту назначить координаты второго, то они будут находится в одной точке, безотносительно своих якорей или локальных позиций, иногда это удобно — когда элементы находятся на разных канвасах/в разных панелях и системы координат локальные/якорные не совпадают.
Вывод/итог
RectTransformUtility, или как сделать компонент, который анимированно сдвигает элементы UI за экран
В прошлой статье — Разновидности координат используемые в GUI Unity3d я попытался кратко рассказать о разновидностях координат в Unity UI/RectTransform. Теперь хочется немножко осветить такую полезную для UI штуку как RectTransformUtility. Которая является одним из основных инструментов вычисления чего либо в UI по отношению к чему либо ещё.
Простая непростая задача
Есть задача — нужен компонент который анимированно убирает UI элемент за выбранный край экрана. Компоненту должно быть фиолетово где он находится иерархически, в каких местах стоят якоря, какой размер экрана, и в каком месте экрана он находится. Компонент должен уметь убирать объект в 4е стороны (вверх, вниз, влево, вправо) за заданное время.
Размышления
В принципе как такое можно сделать? Узнать размеры экрана в координатах объекта, подвинуть объект в координату за краем экрана, и вроде бы дело в шляпе. Но есть пару но:
Как узнать координаты экрана относительно UI?
Если гуглить в лоб, то гуглится какая то ахинея или не полезные штуки, или даже вопросы без ответа. Самое близкое что подходит — это случаи когда какой то UI элемент следует за курсором, который как раз существует в координатах экрана.
Это непосредственно RectTransformUtility и ScreenPointToLocalPointInRectangle. Мы тут получаем локальные координаты внутри ректа(RectTransform), исходя из позиции точки на экране.
В текущем примере мы находим локальные координаты курсора мыши, нам их нужно заменить на край экрана:
И вот мы получили координату верхней правой точки экрана, чтобы объект уехал за экран вправо, наш объект должен быть дальше чем эта точка + допустим ширина ректа или заданный отступ.
Мы получили локальные координаты которые подходят для объектов непосредственно внутри канваса, если рект который надо сместить лежит в другом ректе, то его локальные координаты будут считаться относительно родителя, а не канваса. То есть непосредственно эти координаты нам не подходят.
Тут есть два пути, первое — воспользоваться глобальными координатами, на то они и глобальные. Или высчитывать координаты экрана в локальных координатах каждого ректа в отдельности.
Рассмотрим первый случай — как конвертировать локальные координаты в глобальные.
В большинстве нагугленных способов используют — TransformPoint.
Таким образом мы конвертируем локальные координаты в глобальные.
На мой взгляд это вообще лишний шаг, так как у RectTransformUtility, есть метод ScreenPointToWorldPointInRectangle, который сразу возвращает глобальную позицию.
Нам нужно сместить рект за правый край экрана, для этого мы возьмем X координату с найденной позиции, а Y оставим того ректа который двигаем, чтобы он просто двигался вправо.
Полученную координату скормим DoTween.
И ура, объект уезжает направо. Но…
Тут мы выясним, что на самом деле позиционирование ректа, зависит от rect pivot.
Поэтому объект может плясать с позиционированием в зависимости от pivot, плюс объект может быть очень большой, и offset не задвинет его полностью за экран, всегда будет шанс что кусочек будет торчать.
То есть нам нужно к offset прикрутить компенсацию которая будет учитывать размер ректа + pivot.
Второй нюанс заключается в том, чтобы сдвинуть объект на размер ректа, надо знать локальные или якорные координаты, а мы получаем глобальные координаты. Сразу скажу что глобальные координаты нельзя взять и конвертировать в локальные координаты UI, или же в якорные.
Я придумал следующий костыль, мы запоминаем стартовую позицию ректа, перемещаем его в конечную глобальную позицию, сдвигаем якорную позицию на размер ректа вправо, запоминаем глобальную позицию которая учитывает уже смещение с учётом размера объекта, её и скармливаем дутвину, не забывая перед этим вернуть на начальную позицию.
Выглядит как гигантский костыль, но этот костыль позволяет синхронизировать глобальные и прочие координаты. Это выручает когда в интерфейсе есть объекты которые движутся относительно друг друга, и они находятся в разных иерархиях. Ну и плюс пока это единственный способ который я нашел для получения рект координат из глобальных.
На этом месте мы скажем нет костылям, и вернемся к мысли получения размера экрана в локальных координатах.
Второй путь
Второй путь заключается в том, чтобы получить размеры экрана для каждого ректа в отдельности, таким образом мы будем знать локальные координаты краёв экрана вне зависимости от канваса и иерархии.
Объекты могут находится где угодно на экране, в отличии от канваса который перекрывает весь экран. Поэтому расстояния до левого и правого краёв экрана могут существенно отличаться. В случае с канвасом нам хватило бы только правого верхнего края, а минус правый верхний это был бы левый верхний. В данном случае надо получить нижнюю левую и верхнюю правую точки отдельно, что и показано в примере кода.
Локальная координата это смещение относительно центра родителя, когда рект вложен в другой рект, который занимает небольшую часть канваса, то нам нужна координата которая учитывает оба смещения, ну тут всё просто.
складываем вектора и получаем нужную нам координату. Получается более запутано чем с глобальным координатами, но теперь мы можем проводить любые вычисления связанные с размерами ректа. И спокойно наконец дописать компенсацию без костылей.
Вот так выглядит координата для смещения вправо с компенсацией ширины ректа и смещением за экран на ширину ректа, тут нет возможности задавать офсет, планирую дописать чуть позже, но думаю кому нибудь будет интересно самому попробовать написать такое.
Выводы
FAQ по юнити
FAQ по юнити
автор raingo Вс Янв 28, 2018 4:00 pm
Писал три года назад. Надо бы проверить функции и исправить. И все это по большей части для 3d, не уверен, что для 2d подойдет идеально. Но пускай будет.
Последний раз редактировалось: raingo (Вс Янв 28, 2018 4:51 pm), всего редактировалось 1 раз(а)
Re: FAQ по юнити
автор raingo Вс Янв 28, 2018 4:02 pm
Игровой объект
Создание нового игрового объекта с именем MyGameObject. Созданный объект будет доступен по ссылке myObject.
Код: var myObject = new GameObject(«MyGameObject»);
Уничтожение объекта:
Код: Destroy(myObject);
Уничтожение объекта через минуту, после его создания:
Код: Destroy(myObject, 60);
Получение имени объекта:
Код: string name = myObject.name;
//или
Debug.Log(myObject); //используется встроенная функция ToString(), возвращает имя
Работа с transform (обязательный компонент всех объектов):
Код: Transform myTransform = myObject.transform;
Аналогично с тегом, слоем, состоянием:
Код: myObject.tag = «Player»;
myObject.layer = 2;
gameObject.SetActive(false);
Создаем объект уже после загрузки сцены в реальном времени:
Код:
GameObject thePrefab; //оригинальный объект
void Start () <
GameObject instance = new GameObject(); //вновь созданный
instance = Instantiate(thePrefab, //копируем префаб в instance
transform.position, //в позицию префаба
transform.rotation) as GameObject; //с ротацией префаба
>
Последний раз редактировалось: raingo (Вс Янв 28, 2018 4:18 pm), всего редактировалось 6 раз(а)
Re: FAQ по юнити
автор raingo Вс Янв 28, 2018 4:04 pm
Поиск игрового объекта
Поиск компонента
Поиск по типу
Последний раз редактировалось: raingo (Вс Янв 28, 2018 4:18 pm), всего редактировалось 1 раз(а)
Re: FAQ по юнити
автор raingo Вс Янв 28, 2018 4:10 pm
Работа с компонентами
Получение доступа к скрипту, который лежит на этом же объекте:
Код: test2 tt = GetComponent ;
tt.one = 5;
Если скрипт на другом объекте, сначала нужно найти этот объект:
Код: test1 tt = Find(«nameObject»).GetComponent ();
tt.one = 5;
Компонент Transform добывается проще, т.к. используется часто:
Код: Transform tratata = Find(«nameObject»).transform;
Привязать компонент myComponent к объекту GameObject и получить ссылку:
Код: myComponent component = gameObject.AddComponent(«myComponent») as myComponent;
myComponent component = gameObject.AddComponent (); //равноценно
Отвязать:
Код: Destroy(GetComponent ());
В остальном работа с компонентами аналогична манипуляциями игровыми объектами.
Re: FAQ по юнити
автор raingo Вс Янв 28, 2018 4:13 pm
Положение игрового объекта
Обязательный компонент transform игрового объекта содержит в себе данные о положении объекта в игровом мире. Рекомендуется использовать transform только если нет физического тела
Возвращает глобальные координаты объекта в игровом мире. Возвращаемая величина имеет тип Vector3, который представляет из себя список из 3 координат — x, y и z:
Код: Vector3 pos = GameObject.transform.position;
int x = pos.x;
Текущий угол поворота объекта, основанный на кватернионах. Возвращает объект типа Quaternion:
Код: Quaternion target = transform.rotation;
Масштабирование объекта возможно только в локальных координатах (что естественно):
Код: transform.localScale += new Vector3(0.1F, 0, 0);
Тоже самое, что и в случае глобальных координат, но с локальными. Локальные координаты рассчитываются относительно родительского объекта. В случае отсутствия родительского объекта локальные координаты совпадают с глобальными:
Код: transform.localPosition = new Vector3(0, 0, 0);
Текущий поворот объекта, основанный на кватернионах, но относительно родительского объекта:
Код: Quaternion target = transform.localRotation;
Поворот объекта в углах Эйлера. Метод также возвращает координаты в виде объекта Vector3:
Код: Vector3 eulerAngle = GameObject.transform.eulerAngles;
Vector3 localEulerAngle = GameObject.transform.localEulerAngles;
Перемещение
Ротация
Re: FAQ по юнити
автор raingo Вс Янв 28, 2018 4:17 pm
Работа с физическими объектами
Компонент rigidbody объекта GameObject хранит в себе его физические свойства. Прежде, чем использовать rigidbody, его необходимо добавить к игровому объекту.
Получаем/задаем вектор скорости объекта:
Код: Rigidbody rb = GetComponent ();
rb.velocity = new Vector3(0, 10, 0);
Сила противодействия объекта. Может использоваться для замедления скорости, в среде с отсутствующей силой трения. Наиболее часто используется для замедления падающих объектов, например при создании парашюта. Принимает в качестве параметра целое число:
Код: GetComponent ().drag = 100;
Задание массы объекту. Рекомендуется использовать массу в пределах от 0.1 до 10. Использование слишком больших значений может привести к непредсказуемым результатам при расчете физики:
Код: GetComponent ().mass = 5;
Влияние на объект гравитации. Принимает в качестве параметра булево значение. Позволяет отключить влияние гравитации на отдельные объекты:
Код: GetComponent ().useGravity = false;
Влияние физики на игровой объект. Позволяет отключить частично, либо полностью влияние физических законов на объект:
Код: GetComponent ().isKinematic = true;
Запрет на вращение объекта. Наиболее часто используется, когда необходимо сохранить определенный угол поворота даже после столкновения с другими объектами:
Код: GetComponent ().freezeRotation = true;
Указание координат точки центра массы объекта. Применяет координаты в виде уже знакомого нам объекта Vector3.
Код: GetComponent ().centerOfMass = Vector3(1, 0, 0);
Использовать ли для объекта обнаружение столкновений с другими объектами. Можно выключить, тогда ваш объект будет игнорировать любые столкновения:
Код: GetComponent ().detectCollisions = false;
Режим определения столкновений между объектами. Можно указать несколько разных режимов:
CollisionDetectionMode.ContinuousDynamic для быстро движущихся объектов;
CollisionDetectionMode.Continuous для столкновений с быстро движущимися объектами;
CollisionDetectionMode.Discrete (по умолчанию) для обычных столкновений;
В случае отсутствия проблем с определением столкновений рекомендуется использовать свойство по умолчанию.
Задать плотность объекта:
Код: GetComponent ().SetDensity(1.5);
Применить импульс к объекту с указанным вектором. В результате применения импульса объект придет в движение пропорционально силе импульса.
Код: GetComponent ().AddForce(5, 0, 0);
Применить импульс к объекту с вектором в его (объекта) системы координат:
Код: GetComponent ().AddRelativeForce(0, 0, 5);
Добавить объекту крутящий момент. Применение данного метода заставит объект вращаться вокруг своего центра масс centerOfMass.
Код: GetComponent ().AddTorque(0, 1, 0);
Тоже самое, что и предыдущий пример, но относительно координат объекта:
Код: GetComponent ().AddRelativeTorque (1, 0, 0);
Применение импульса к объекту из внешней указанной точки. Заставляет объект двигаться и вращаться одновременно. Может использоваться, например, для симуляции попадания в объект пули. Первый параметр указывает вектор направления силы, второй параметр — исходную точку направления силы.
Код: GetComponent ().AddForceAtPosition(Vector3(0, 5, 7), Bomb.transform.position);
Для полноценной симуляции объемных взрывов в Unity3D есть отдельный метод. Первый параметр метода позволяет указать мощность импульса, второй параметр — точку, из которой исходит импульс, третий параметр — радиус распространения импульса, четвертый параметр — модификатор сжатия сферы распространения силы, пятый, необязательный, параметр указывает тип используемого импульса:
Код: GetComponent ().AddExplosionForce(power, explosionPos, radius, 2.0);
Заставить объект «уснуть», и запретить дальнейший расчет физических показателей для него:
Код: GetComponent ().Sleep();
Проверить «заснул» ли объект:
Код: GetComponent ().IsSleeping();
«Разбудить» объект для возможности дальнейшего применения влияния физики на него:
Код: GetComponent ().WakeUp();
Последний раз редактировалось: raingo (Вс Янв 28, 2018 4:47 pm), всего редактировалось 1 раз(а)
Re: FAQ по юнити
автор raingo Вс Янв 28, 2018 4:19 pm
Трассировка лучей
Один из самых часто используемых в разработке на Unity3D объект, это Ray. Данный объект позволяет выпустить луч из указанной точки, в указанном направлении, и вернуть некоторые свойства объектов, которых он смог достичь.
Создаем объект класса RaycastHit, который содержит информацию об объекте, с которым столкнулся луч:
Код: RaycastHit hit;
Отправляем луч длиной в 50 юнитов из позиции rayPosition в направлении rayVector, и заносим объект, с которым столкнулся луч в переменную hit:
Код: Physics.Raycast(rayPosition, rayVector.forward, hit, 50);
Получаем дистанцию до объекта, с которым столкнулся луч. Дистанция не может быть больше, чем протяженность луча:
Код: float distance = hit.distance;
Иногда бывает необходимо получить имя объекта, с которым произошло столкновение луча. Наиболее простой способ это сделать:
Код: string objectName = hit.collider.gameObject.name;
Для получения тега объекта используем следующий способ:
Код: string Tag = hit.collider.tag;
Получение ссылки на «просвеченный» лучом объект
Код: GameObject Target;
Target = hit.collider.gameObject;
Re: FAQ по юнити
автор raingo Вс Янв 28, 2018 4:23 pm
Регулярные события в Юнити
Каждый раз, когда создается пользовательский класс ему автоматически прописываются два события, в теле которых и ведется вся работа движком
пример вновь созданного кода:
Код: using UnityEngine;
using System.Collections;
public class NewBehaviourScript : MonoBehaviour <
// Use this for initialization
void Start () <
// Update is called once per frame
void Update () <
Все эти события наследуются от MonoBehaviour. В Юнити множество разных дефолтных функций, отвечающих на самые разные запросы, от рендера, до ввода и гуи. По сути функции Awake() и Start() не являются регулярными, но я внес их сюда для более облегченного понимания порядка вызовов. Они логически связаны и при написании игры используются в единой структуре.
Unity3D C# Как глобальные координаты перевести в локальные(LineRender.positions)
На плоскости с помощью LineRenderer между спрайтами нарисовал линию. Создал «obj» на линии и научил его двигаться по линии перебирая сохраненные точки линии из массива positions компонента line Draw:
lr.GetPosition(indpos + 1).
Но нужно чтобы «obj» поворачивался в сторону движения. Для этого использую:
Строка №1 GETrot = Vector3.Angle(lr.GetPosition(indpos), lr.GetPosition(indpos+1)); //тут беру 2 Vector3 и получаю угол между ними по оси Z
Строка №2 obj.transform.localEulerAngles = new Vector3(0, 0, GETrot); //тут меняю Элеровский угол по локальной оси z найденный строчкой выше.
В Строке №1 вычитается угол в глобальных координатах т.е. относительно центра координат, а не локальных координат «obj».
но не дало не какого эффекта.
Но поскольку я не программист не смог понять как их корректно использовать.
ИЗ ВСЕГО ВЫШЕСКАЗАННОГО ВОПРОС: Как посчитать угол в локальных координатах и присвоить его объекту?
Помогите люди добрые, сами мы не местные. судьба жестокая заставила осваивать Юнити+С# в короткие сроки. Дедлайн близко, а нехера не сделано, ничего не успеваю!!
endeavour_pr спасибо за отклик. Мб позже скину. Это не последний вопрос наверняка.
seaman, спасибо думаю вы правы.
Transform’ does not contain a definition for ‘rotate’ and no extension method ‘rotate’ accepting a first argument of type ‘Transform’ could be found (are you missing a using directive or an assembly reference?)
судя по всему операцию присваивания тут нельзя использовать.
DellLoiD
> И вот эта штука не работает
Ошибся в одной букве. Вам быстрее было бы посмотреть в мануале где.
https://docs.unity3d.com/ScriptReference/Transform.Rotate.html
seaman
У меня заработало как надо вот так:
В целом у меня 4 таких блока: сверху-вниз; снизу-вверх; слева-направо; справа-налево;
В каждом блоке я вношу поправки для 2 точек линии: 1. На предыдущем спрайте исходящую точку. 2. На текущем спрайте входящую точку.
Итого под спрайтом 2 точки линии с позиционированные ближе к краю спрайта за счет чего линии в 90% случаях находятся рядом и не пересекаются.
Вдруг кто знает какое то стандартное решение такой задачи? Или этот велосипед который я привел выше можно оставить??
Координаты дочерних объектов в Unity
Помощь в написании контрольных, курсовых и дипломных работ здесь.
Отключение дочерних объектов
Есть панель,в панели находятся дочерние кнопки,нужно делать их из скрипта «interactble» в.
Деформация объектов в Unity
Всем привет! Вопрос есть такой: Как сделать в Unity3D что бы объекты могли деформироваться.
Отслеживание объектов Vuforia и Unity
Здравствуйте, на этом видео, показано как создать сканирование и отслеживание объектов с помощью.
Всплывающие подсказки для объектов unity c#
Доброго времени суток. Предупреждаю сразу, в Unity я новичок, так что. Нужно создать.
Basea, это невозможно. Только если ты сам предусмотришь систему родитель-ребенок, и находиться все объекты будут в самом корне.
Добавлено через 1 минуту
Basea, или перетаскиваешь дочерний объект в самый корень иерархии и увидишь глобальные. Поменяешь, а потом перетаскиваешь обратно.
Помощь в написании контрольных, курсовых и дипломных работ здесь.
Большие масштабы объектов. Планеты на Unity 5
Здравствуйте, недавно написал скрипт на смещение мира каждые 1000 юнитов и возвращая игрока в центр.
Unity 5. Как сделать создание и удаление объектов
Пишу скрипты на C# хочу сделать ферму но не знаю как сделать создание объекта пшеница на.