Practical use of Unity3d engine
В этой статье рассмотрим следующую задачу: необходимо реализовать выбор объектов левой клавишей мыши, причем при выборе объекта необходимо его подсветить. Эта статья является продолжением второй статьи (http://denis-potapenko.blogspot.com/2013/03/2-unity3d.html). Поэтому перед началом чтения этой статьи желательно прочесть вторую часть. Результат, который мы хотим получить представлен на рисунке В:
Рисунок. В. – Результирующая сцена
Выбор объекта
Для начала создадим переменную – член класса, которая будет хранить выбранный объект.
// selected GameObject private GameObject mSelectedObject;
Также создадим свойство на этот объект.
////// Gets or sets selected GameObject /// public GameObject SelectedObject < get < return mSelectedObject; >set < … // assign new game object mSelectedObject = value; … >>
Работу сеттера этого свойства рассмотрим ниже.
Теперь создадим метод, который будет выбирать объект. Определим объект, находящийся под мышкой. Алгоритм выбора объекта следующий:
- Перевести позицию мышки из пространства окна (2д координаты) в трехмерные координаты (А);
- Построить луч, идущий от позиции мышки в 3д координатах в сторону «от камеры» (Б);
- Найти пересечение луча с любым объектом в сцене;
- Первый объект, попавшийся на пересечении, является выбранным;
Преобразуем позицию мыши в луч исходящий от камеры (Объединим пункты А и Б) используя метод «ScreenPointToRay».
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
Теперь найдем пересечение луча с любым объектом в сцене. Для этого используем метод «Physics.Raycast».
RaycastHit hit; if (Physics.Raycast(ray, out hit, Constants.cMaxRayCastDistance))
Хочу сразу заметить, что на каждый объект, с которым мы хотим посчитать пересечение, должен быть назначен так называемый «Collider». «Collider» используется в основном для работы с физикой и в частности для определения пересечений. Для того чтоб назначить «Collider» на GameObject, необходимо выделить объект в сцене, и выбрать пункт меню «Component / Physics / Box Collider». В дальнейших статьях мы более подробно изучим эти компоненты.
В случае если пересечение найдено метод «Physics.Raycast» возвращает «true» и заполняет переменную «hit». Теперь определим GameObject, который соответствует найденному объекту типа «RaycastHit».
// get game object GameObject rayCastedGO = hit.collider.gameObject;
И наконец, установим найденный объект, как выделенный.
// select object this.SelectedObject = rayCastedGO;
А теперь нужно вызвать метод “SelectObjectByMousePos” в методе «Update». Причем вызывать мы его будет, только при нажатии левой клавиши мыши.
// process object selection if (Input.GetMouseButtonDown(0))
Теперь давайте подробно рассмотрим, как работает сеттер свойства «SelectedObject».
Подсветка объекта
С начала немного теории. Дело в том, что подсветку объектов можно сделать множеством способов. Я расскажу способ, который можно добиться, не используя никакие дополнения к движку Unity3d. После описания теории и практики я расскажу Вам, на мой взгляд, более совершенный способ реализации подсветки.
И так алгоритм реализации подсветки объектов следующий:
- Создать 2 материала: первый обычный материал, второй материал подсветки;
- Передать эти материалы в скрипт;
- При выделении объекта, установить «подсвеченный» материал на выделенный объект;
- На объект, который был выделен ранее, установить обычный материал ;
Теперь рассмотрим реализацию этого метода. В редакторе Unity3d создадим папку с материалами, и назовём ее «Materials». В этой папке создадим 2 материала – обычный “SimpleMat”, и подсвеченный “HighlightedMat”. Получившая иерархия папок и файлов показана на рисунке 2.1
Рис. 2.1 — Структура файлов и папок с материалами
Хочу отметить, что у обоих материалов установлен стандартный шейдер “Diffuse”. Материалы настроены идентично, за исключением того что у материала «HighlightedMat» диффузный цвет установлен в красный. На рис. 2.2 показаны настройки материала «HighlightedMat».
Рисунок 2.2 – Настройки материала «HighlightedMat»
Теперь создадим 2 публичных переменных – члена класса “AppRoot”, которые будут хранить созданные материалы.
// materials for highlight public Material SimpleMat; public Material HighlightedMat;
Теперь присвоим этим переменным значение. Сделаем это прямо в редакторе. Процесс назначения материалов в скрипт показан на рис. 2.3.
Рисунок 2.3 – Назначение материалов в скрипт “AppRoot”
Теперь наконец-то реализация сеттера свойства “SelectedObject”.
Получим «старый» выбранный объект.
// get old game object GameObject goOld = mSelectedObject;
Установим новый выбранный объект.
// assign new game object mSelectedObject = value;
Если выбранный объект не поменялся, просто выходим с метода.
// if this object is the same — just not process this if (goOld == mSelectedObject)
Установим материал на старый выбранный объект.
// set material to non-selected object if (goOld != null)
Установим материал на выбранный объект.
// set material to selected object if (mSelectedObject != null)
В результате мы получили в сцену, в которой пользователь, с помощью левой клавиши мыши, может выбирать объекты, и они будут окрашиваться в красный цвет.
Замечания
Как я уже писал выше, я не считаю выше описанный алгоритм подсветки объектов самым эффективным. Я считаю, что более эффективный метод будет использовать шейдер с компонентом «Emissive». Этот компонент умножается особым способ на результирующий цвет, таким образом, выделенный объект получает «окраску» например красного цвета, а не полностью закрашивается. Вы вполне можете создать такой шейдер своими руками. В последующих статьях я расскажу как это сделать. Из существующих стандартных шейдеров в Unity3d, я нашел шейдер «Reflective/Diffuse», который в некоторых случаях очень подходит для целей подсветки объектов. Можете попробовать использовать этот шейдер и его поле “Reflection Color” вместе “Emissive”.
как изменить цвет объекта в unity 5.6.1
GameObject[] pu = GameObject.FindGameObjectsWithTag («Pick Up»);
for (int i = 0; i < pu.Length; i++)
pu [i].GetComponent < MeshRenderer >().materials [0].color = new Color(Random.Range(0, 255)/100, Random.Range(0, 255)/100, Random.Range(0, 255)/100, 1);
Олег ОлеговичПросветленный (22716) 6 лет назад
Мне тут скучно было, интересную штуку намутил.
int i = 0;
void Update () this.GetComponent < MeshRenderer >().materials [0].color =
new Color(Mathf.PingPong(i++, 100f)/100f,Mathf.PingPong(i + 50, 100f)/100f,Mathf.PingPong(i + 100, 100f)/100f);
>
Остальные ответы
А не renderer случаем надо получать?