photo

Триггеры

Recommended Posts

Собираю всю информацию о триггерах.

На момент версии 2.12 есть три типа триггеров:

1) WorldTrigger

2) NodeTrigger

3) PhysicalTrigger

 

World Trigger 

Документация WorldTrigger, WorldTrigger Class.

Кубический примитив. Собственно все что из себя представляет. Работа с ним описана тут Удочерить нод для стандартного FPS.

Алгоритм работы:

Важно! Если вы будете работать с триггером из скрипта, то поля Enter Callback / Leave Callback должны оставаться пустыми! Физические объекты с этим триггером не реагируют.

Обнаруженный баг, (или фича). Объекты которые вы сделали физическими, а потом убрали у них физику поставив на вкладке Physics в поле Body > None, триггер так же продолжает игнорировать. Если вы очень хитрый и добавите к физическому объекту в иерархию обычный Node - то триггер на него все равно не будет реагировать. Более того, если вы вытащите его из иерархии физического объекта - триггер так же не будет на него реагировать. Не обманешь, не предашь. Возможно надо проделать какие то дополнительные танцы с бубном.

1) Создаете на сцене (World) WorldTrigger

2) На него кидаете скрипт WorldTriggerComponent

3) На объекте (нодах) который должен взаимодействовать с триггером ставите галочку Triggers Interaction которая находится в поле Node

 

Дублирую сообщения и скрипт:

On 9/2/2020 at 8:15 AM, karpych11 said:

Здравствуйте!

Функции из полей Enter Callback / Leave Callback вызываются в скрипте на UnigineScript, который настроен для текущего мира. Чтобы настроить вызов коллбеков триггера для методов компонент необходимо их добавить в коде через AddEnterCallback / AddLeaveCallback. Простой пример есть в прикрепленной компоненте. Добавьте её на любой WorldTrigger в мире. Также не забудьте про включенный флаг Triggers Interaction у тех нод, на которые должен реагировать триггер. При запуске приложения будет визуализироваться сам триггер, а в консоль будут выводиться сообщения при вызове коллбеков.

WorldTriggerComponent.cs 772 B · 5 downloads

Скрипт (поправленный):

Spoiler

using System;
using System.Collections;
using System.Collections.Generic;
using Unigine;

[Component(PropertyGuid = "Ваш ID скрипта")]
public class WorldTriggerComponent : Component
{
	private WorldTrigger trigger = null;

	private void Init()
	{
		if (Unigine.Console.GetInt("show_messages") == 0)
			Unigine.Console.SetInt("show_messages", 1);

		Log.Message("Have begun. Script on the object = {0} \n", trigger.Name);

		trigger = node as WorldTrigger;
		if (!trigger)
		{
			Log.Error("WorldTriggerComponent error: can't cast node to WorldTrigger\n");
			return;
		}
		else
		{
			Log.Message("Trigger found and converted = {0} \n", trigger.Name);
		}

		Log.Message("Adding Callback. trigger = {0} \n", trigger.Name);

		trigger.AddEnterCallback(OnEnter);
		trigger.AddLeaveCallback(OnLeave);

		Log.Message("Turn on visualization. trigger = {0} \n", trigger.Name);
		Visualizer.Enabled = true;
	}
	
	private void Update()
	{
		if (!trigger)
			return;

		trigger.RenderVisualizer();
	}

	private void OnEnter(Node n)
	{
		Log.Message($"Trigger fired {trigger.Name}. OnEnter: {n.Name}\n");
	}

	private void OnLeave(Node n)
	{
		Log.Message($"Trigger fired {trigger.Name}. OnLeave: {n.Name}\n");
	}
}

 

 

Node Trigger

Честно говоря слабость документации и практически тотальное отсутствие примеров уже начинает вызывать головную боль. Обратите внимание что версия странички 2.12 не содержит гифку куда пихать этот триггер. Trigger 2.12.  Гифка тут - Triggers 2.6.1, NodeTrigger Class.

Это пожалуй самый странный триггер который я когда либо видел. Можно предположить что это что-то типа mesh триггера, но нет. Не имеет вызова LeaveCallback, но зато реагирует на смену позиции что кстати очень оригинально и может быть весьма полезно, если бы... Это был обычный триггер. Должен быть прописан Unigine script:

Quote

Функции обратного вызова enabled и position должны быть реализованы в мировом скрипте.

Функция обратного вызова также может принимать 2 дополнительных аргумента . Однако вы можете установить такие обратные вызовы только через код. Через UnigineEditor вы можете указать только функции обратного вызова, которые получают 0 или 1 в качестве аргумента.

 Сложно представить зачем он вообще такой нужен. В документации что-то говорится о молнии и громе, что странно - если я сам же создаю молнию, в чем проблема мне же создать звук грома? Разве что если молния ударит в предмет, то воспроизвести звук взрыва или что там произойдет. В общем, будем надеяться на комментарии разработчиков.

 

Physical Trigger

Пожалуй наиболее полная информация в документации среди существующих триггеров. Правда, до скрипта который будет представлен ниже берущий за основу скрипт представленный выше, там конечно еще не дошли. Так же традиционное тотальное отсутствие примеров для каждого свойства/метода, но есть таки целых три примера с кодом - основной и для вызовов. Очевидно это по тому что этот тип триггеров относительно молодой (первая версия документации о нем датируется версией 2.2), так что разработчики уделили внимание как с ним работать более полно. Итак ссылки - Physical TriggerPhysicalTrigger Class.

Алгоритм в общем такой же как и у WorldTrigger, с небольшими отличиями. Однако, баг (или таки фича?) с физическими объектами у которых была убрана физика так же остался. Опять же, возможно убирать физику надо особым способом, а не просто переключить флаг на none в поле Physics.

Важно! Если вы будете работать с триггером из скрипта, то поля Enter Callback / Leave Callback должны оставаться пустыми! Объекты без физики с этим триггером не реагируют (немного не понятно зачем такое разделение на физику и без, однако разработчикам виднее).

Внимание! Возвращаемое значение Body. К примеру если вы напишите - void OnEnter(Body n),  а затем n.Name, то вам вернет имя не объекта (objeck.Name), а имя из поля Physic.

Внимание! Любопытно, что 

void OnEnter(Body n)
{
	Log.Message($"Call OnEnter of PhysicalTrigger. node.Name: {node.Name}\n"); //вернет имя триггера
	Log.Message($"Call OnEnter of PhysicalTrigger. node.ObjectBody.Object.Name: {node.ObjectBody.Object.Name}\n");  //вернет имя объекта в котором этот триггер
	Log.Message($"Call OnEnter of PhysicalTrigger. n.Object.Name: {n.Object.Name}\n"); //вернет имя объекта попавшего в триггер
	Log.Message($"Call OnEnter of PhysicalTrigger. n.Object.Parent.Name: {n.Object.Parent.Name}\n"); //вернет имя родителя объекта попавшего в триггер
	Log.Message($"Call OnEnter of PhysicalTrigger. n.Parent.Name: {n.Parent.Name}\n"); //вернет ошибку 'Object reference not set to an instance of an object.'
}

1) Создаете на сцене (World) PhysicalTrigger

2) На него кидаете скрипт TestScriot приведенный ниже

3) Здесь не нужно на объекте (нодах) который должен взаимодействовать с триггером ставить галочку Triggers Interaction которая находится в поле Node

Скрипт:

Spoiler

using System;
using System.Collections;
using System.Collections.Generic;
using Unigine;

[Component(PropertyGuid = "Ваш ID script")]
public class TestScriot : Component
{
	private PhysicalTrigger trigger = null;

	private void Init()
	{
		Log.Message("Testing started PhysicalTrigger. Script on the object = {0} \n", node.Name);

		trigger = node as PhysicalTrigger;

		if (!trigger)
		{
			Log.Error("PhysicalTriggerComponent error: can't cast node to PhysicalTrigger \n");
			return;
		}
		else
		{
			Log.Message("Found PhysicalTrigger = {0} \n", trigger.Name);
		}
      
		Log.Message("Adding Callback. trigger = {0} \n", trigger.Name);
		trigger.AddEnterCallback(OnEnter);
		trigger.AddLeaveCallback(OnLeave);
	
		Log.Message("Turn on visualization. trigger = {0} \n", trigger.Name);
		Visualizer.Enabled = true;
	}
	
	private void Update()
	{
		if (!trigger)
			return;

		trigger.RenderVisualizer();
	}

	private void OnEnter(Body n)
	{
		Log.Message($"Call OnEnter of PhysicalTrigger. Body: {node.Name}\n");
	}

	private void OnLeave(Body n)
	{
		Log.Message($"Call OnLeave of PhysicalTrigger. Body: {node.Name}\n");
	}
}

 

 

Edited by nikolay.sykharev

Share this post


Link to post

Привет, nikolay.sykharev

Спасибо за ваш интерес к тригерам.

Хотелось бы немного прояснить про World Trigger. За взаимодействие ноды с этим триггером отвечает чекбокс Triggers Interaction. Здесь не важно есть ли у ноды Body и Shape (физический ли объект или нет). Взаимодействие рассчитывается с помощью Bounding Box. Также обратите внимание на наличие чекбокса Touch, который позволяет фиксировать пересечение объема тригера с Bounding Box ноды даже в случае частичного пересечения этих объемов (по умолчанию фиксируются только полные вхождения Bounding Box в тригер).

Мы планируем и дальше улучшать документацию, в том числе и на основе ваших впечатлений о ней.

Share this post


Link to post
9 hours ago, stockyspark said:

Здесь не важно есть ли у ноды Body и Shape (физический ли объект или нет)

Это очень странно, потому что у меня World Trigger, объекты с физикой напрочь игнорировал. Я могу за это поручиться, поскольку алгоритм был следующий:

1) Создаю триггер

2) Добавляю ему компонент скрипта

3) Проверяю работу с объектом на который должен реагировать триггер (работает)

4) Добавляю физику объекту на который ранее триггер реагировал

4) Проверяю работу (не работает)

5) Убираю физику

6) Проверяю работу (не работает)

7) Создаю новый объект который должен реагировать с триггером без физики

8) Проверяю работу (работает)

Share this post


Link to post

Здравствуёте Николай,

У нас сходу не получилось воспроизвести проблему с отсутсвием реакции триггера на объекты с физикой. С WorldTrigger и обычным примитивом с BodyRigid всё работает нормально. Может дело в каких-то дополнительных параметрах сцены, или спецефичной настройкой физики. Если есть возможность - прикрепите, пожалуйста, минимальную тестовую сцену в которой триггер не срабатывает. 

Спасибо

Share this post


Link to post