This page has been translated automatically.
Видеоуроки
Интерфейс
Основы
Продвинутый уровень
Подсказки и советы
Основы
Программирование на C#
Рендеринг
Профессиональный уровень (SIM)
Принципы работы
Свойства (properties)
Компонентная Система
Рендер
Режимы вывода изображения
Физика
Браузер SDK 2
Лицензирование и типы лицензий
Дополнения (Add-Ons)
Демонстрационные проекты
API Samples
Редактор UnigineEditor
Обзор интерфейса
Работа с ассетами
Контроль версий
Настройки и предпочтения
Работа с проектами
Настройка параметров ноды
Setting Up Materials
Настройка свойств
Освещение
Sandworm
Использование инструментов редактора для конкретных задач
Расширение функционала редактора
Встроенные объекты
Ноды (Nodes)
Объекты (Objects)
Эффекты
Декали
Источники света
Geodetics
World-ноды
Звуковые объекты
Объекты поиска пути
Player-ноды
Программирование
Основы
Настройка среды разработки
C++
C#
UnigineScript
Унифицированный язык шейдеров UUSL (Unified UNIGINE Shader Language)
Плагины
Форматы файлов
Материалы и шейдеры
Rebuilding the Engine Tools
Интерфейс пользователя (GUI)
Двойная точность координат
API
Animations-Related Classes
Containers
Common Functionality
Controls-Related Classes
Engine-Related Classes
Filesystem Functionality
GUI-Related Classes
Math Functionality
Node-Related Classes
Objects-Related Classes
Networking Functionality
Pathfinding-Related Classes
Physics-Related Classes
Plugins-Related Classes
IG Plugin
CIGIConnector Plugin
Rendering-Related Classes
VR-Related Classes
Работа с контентом
Оптимизация контента
Материалы
Визуальный редактор материалов
Material Nodes Library
Miscellaneous
Input
Math
Matrix
Textures
Art Samples
Учебные материалы

Обработка контактов при столкновении

Sometimes you may need to implement your own contact handler for colliding physical bodies. In this example, you will learn how to visualize contact points, display debug information, and add a hit effect (sparks) at the point of impact. Иногда вам может потребоваться реализовать собственный обработчик контактов для сталкивающихся физических тел. В этом примере вы узнаете, как визуализировать точки контакта, отображать отладочную информацию и добавлять эффект удара (искры) в точке столкновения.

Preparing the content
Подготовка контента#

To create sparks, we are going to use the VFX add-on (you can download it on https://store.unigine.com).Для создания искр будет использоваться дополнение VFX (его можно скачать на https://store.unigine.com).

Create a new project in UNIGINE SDK Browser and import the VFX add-on to it.Создайте новый проект в браузере UNIGINE SDK и импортируйте в него дополнение VFX.

When you open the project in the UnigineEditor, you will see the default scene containing some dynamic objects. Let's create another box and get some information about the contacts it will have with other objects.Когда вы откроете проект в UnigineEditor, то увидите сцену по умолчанию, содержащую некоторые динамические объекты. Давайте создадим еще один кубик и получим информацию о его контактах с другими объектами.

Making the Objects Collidable
Создание объектов, с которыми возможно столкновение#

The box is a dynamic object, so to be able to collide it needs a body and a collision shape. Add a Rigid body and a shape via the Physics tab of the Parameters window.Кубик является динамическим объектом, поэтому для того чтобы он мог с чем-нибудь столкнуться, ему требуется тело и коллизионная форма. Добавьте Rigid body и форму на вкладке Physics окна Parameters.

Collisions are available for static objects as well (like buildings or ground) — simply enable the Collision option for the corresponding surface.Коллизии доступны и для статических объектов (например, зданий или земли) — просто включите опцию Collision для соответствующей поверхности.

Enabling High Priority Contacts
Включение контактов с высоким приоритетом#

On collision, contacts are distributed randomly between the interacting bodies to optimize performance: some are handled by the first body, others by the second. For a body, contacts that it handles itself are internal (access to them is fast), and contacts handled by other bodies are external.При столкновении контакты случайным образом распределяются между взаимодействующими телами для оптимизации производительности: некоторые обрабатываются первым телом, другие — вторым. Для тела контакты, которые оно обрабатывает само, являются внутренними (доступ к ним быстрый), а контакты, обрабатываемые другими телами, являются внешними.

Примечание
You can iterate through all contacts for a body, but for better performance it is recommended to process only internal ones.Вы можете перебирать все контакты для тела, но для повышения производительности рекомендуется обрабатывать только внутренние.

The box is a high-priority body for us and we want to track its collisions with maximum efficiency. We can make the box handle most of its contacts itself (so that most of them are internal). To do so, select the box and check High Priority Contacts in the Physics tab (or do it via code).Кубик является для нас высокоприоритетным телом, и мы хотим отслеживать его столкновения с максимальной эффективностью. Мы можем сделать так, чтобы кубик самостоятельно обрабатывал большинство своих контактов (так, чтобы большинство из них были внутренними). Для этого выберите кубик и включите опцию High Priority Contacts на вкладке Physics (или сделайте это через код).

Creating a Hit Effect Node
Создание ноды эффекта попадания#

We will use a Particle System to create a node that simulates sparks.Мы будем использовать систему частиц для создания ноды, имитирующей искры.

  1. In the UnigineEditor, click Create -> Particle System -> Particles. Place the object somewhere in the world, rename it to sparks, and adjust its parameters:В UnigineEditor нажмите Create -> Particle System -> Particles. Поместите объект где-нибудь в мире, переименуйте его в sparks и измените его параметры:

    • Number Per Spawn = 10
    • Radius = 0.02
    • Life Time = 0.2
    • Period = inf
    • Duration = 0
  2. In the Surface Material section, assign library_spark1.mat material (it is located in the data -> vfx -> materials -> library_vfx folder of your project).В разделе Surface Material назначьте материал library_spark1.mat (он находится в папке data -> vfx -> materials -> library_vfx вашего проекта).
  3. Switch to the data folder in the Asset Browser. Right-click the sparks node and select Create a Node Reference. A sparks.node file will be generated in the data folder.Перейдите в папку data в браузере ассетов. Щелкните правой кнопкой мыши на ноде sparks и выберите Create a Node Reference. В папке data будет создан файл sparks.node.
  4. Delete the sparks object from the scene, we no longer need it since it will be loaded via code.Удалите объект sparks из сцены, он нам больше не нужен, так как он будет загружен с помощью кода.

Algorithm Description
Описание алгоритма#

The algorithm we are going to use can be described as follows:Алгоритм, который мы собираемся использовать, можно описать следующим образом:

  1. We create three variables (lastContactTime, lastContactPoint, lastContactInfo) to keep the time and position of the last occurred contact and some info about it.Мы создаем три переменные (lastContactTime, lastContactPoint, lastContactInfo), чтобы сохранить время и местоположение последнего произошедшего контакта и некоторую информацию о нем.
  2. We subscribe for an event to perform some actions when each contact emerges. The handler function (OnContactEnter()) takes the body and the index of the contact.Мы подписываемся на событие, чтобы выполнять некоторые действия при возникновении каждого контакта. Функция обработчика (OnContactEnter()) принимает тело и индекс контакта.
  3. If the contact is internal, we save its time and position.Если контакт внутренний, мы сохраняем его время и местоположение.
  4. We get both physical bodies participating in this contact (body0, body1). We check if our box has hit another physical object.Мы получаем оба физических тела, участвующих в этом контакте (body0, body1). Мы проверяем, ударил ли наш кубик другой физический объект.

    • If any of body0 and body1 exists (and it is not the body of our box), then we have found this object. We get details about this body and render it in the viewport using Visualizer.Если какой-либо из body0 и body1 существует (и это не тело нашего кубика), то мы нашли этот объект. Мы получаем подробную информацию об этом теле и отображаем его в окне просмотра, используя Визуализатор.
    • Otherwise, the box has hit some static object (a surface with the Collision option enabled). We make this surface highlighted in the viewport as well.В противном случае поле попало на какой-либо статический объект (поверхность с включенной опцией Collision). Мы также выделяем эту поверхность в окне просмотра.
  5. We add details we are interested in (e.g., the contact impulse).Мы добавляем интересующие нас детали (например, импульс контакта).
  6. We spawn a hit effect if the impulse is strong enough. Physics event handlers are called in the main thread, so it is safe to create nodes inside the OnContactEnter() function.Мы создаем эффект удара, если импульс достаточно силен. Обработчики физических событий вызываются в основном потоке, поэтому безопасно создавать ноды внутри функции OnContactEnter().
  7. Finally, in the Update() method we display the info and create a slow motion effect for one second.Наконец, в методе Update() мы отображаем информацию и создаем эффект замедленной съемки на одну секунду.

Component Code
Код компонента#

Create a new C# component, call it ContactsHandler, and open it in your IDE.Создайте новый компонент C#, назовите его ContactsHandler и откройте его в своей IDE.

Внимание
Do not change the PropertyGuid value in the ContactsHandler.cs file!
Исходный код
[Component(PropertyGuid = "YOUR_COMPONENT_GUID")]
Не меняйте значение PropertyGuid в файле ContactsHandler.cs!
Исходный код
[Component(PropertyGuid = "YOUR_COMPONENT_GUID")]

Copy the source code below and save it to the ContactsHandler.cs file.Скопируйте приведенный ниже исходный код и сохраните его в файле ContactsHandler.cs.

ContactsHandler.cs

Исходный код (C#)
using System;
using System.Collections;
using System.Collections.Generic;
using Unigine;
#region Math Variables
#if UNIGINE_DOUBLE
using Vec3 = Unigine.dvec3;
#else
using Vec3 = Unigine.vec3;
#endif
#endregion
// DO NOT CHANGE THE PropertyGuid VALUE
[Component (PropertyGuid = "YOUR_GUID")]

public class ContactsHandler : Component
{
	// For debugging
	public bool debug = true; 
	// A node that will be loaded on contact (a hit effect in our case)
	public AssetLinkNode contactEffect; 

	// Time, position and some info of the last occurred contact
	private DateTime lastContactTime; 
	private Vec3 lastContactPoint;
	private string lastContactInfo;

	private void Init()
	{
		Body body = node.ObjectBody;
		if (body)
		{
			// For debug purposes, we can render certain contacts depending on their type
			body.EventContacts.Connect((b) => b.RenderInternalContacts()); 
			// A handler to be fired when each contact emerges
			body.EventContactEnter.Connect(OnContactEnter);
		}
	}

	// This function takes the body and the index of the contact
	private void OnContactEnter(Body body, int num)
	{
		// Enable Visualizer to see the rendered contact points
		Visualizer.Enabled = true;
		
		if(body.IsContactInternal(num))
		{
			if (debug)
			{
				// The time of the contact
				lastContactTime = DateTime.Now; 
				// The position of the contact
				lastContactPoint = body.GetContactPoint(num); 

				// We get both physical bodies participating in this contact
				Body body0 = body.GetContactBody0(num);
				Body body1 = body.GetContactBody1(num);

				Body touchedBody = null;

				// We check if our object has hit another physical object.
				// If any of the bodies exists and it's not the body of our object
				// then we have found another physics-driven object that hit it
				if (body0 && body0 != body) touchedBody = body0;  
				if (body1 && body1 != body) touchedBody = body1;

				if (touchedBody)
				{
					// Our object has touched a physics-driven object.
					// We save the info about the body
					lastContactInfo = $"body {touchedBody.Name} of {touchedBody.Object.Name}";
					// Render it in the viewport
					Visualizer.RenderObject(touchedBody.Object, vec4.BLUE, 0.5f); 
				}
				else
				{
					// It has touched a surface with Collision enabled
					lastContactInfo = $"surface #{body.GetContactSurface(num)} of {body.GetContactObject(num).Name}";
					// Highlighting the surface
					Visualizer.RenderObjectSurface(body.GetContactObject(num), body.GetContactSurface(num), vec4.BLUE, 0.5f);
				}

				// You can add details you are interested in (e.g., the contact impulse)
				lastContactInfo += $"\nimpulse: {body.GetContactImpulse(num):0.0}";
			}

			// We spawn a hit effect if the impulse is strong enough
			if (body.GetContactImpulse(num) > 0.3f && !contactEffect.IsNull)
			{
				contactEffect.Load(body.GetContactPoint(num), MathLib.RotationFromDir(body.GetContactNormal(num) * MathLib.RotateY(90)));
			}
		}
	}

	private void Update()
	{
		// Here we display the info and create a slow motion effect for one second
		if (debug)
		{
			if((DateTime.Now - lastContactTime).Seconds < 1.0f)
			{
				// Slow motion effect
				Game.Scale = 0.4f; 
				Visualizer.RenderMessage3D(lastContactPoint, vec3.ONE, $"last contact: \n{lastContactInfo}", vec4.GREEN, 2, 24);
			}
			else
			{
				// All the other time the speed will be normal
				Game.Scale = 1.0f;
			}
		}
	}
}

Applying Logic to the Object
Применение логики к объекту#

Switch to the UnigineEditor and assign the ContactsHandler component to the box node.Переключитесь на UnigineEditor и назначьте компонент ContactsHandler ноде кубика.

Specify the sparks.node in the Contact Effect field.Укажите значение sparks.node в поле Contact Effect.

Примечание
You might need to increase the physics FPS and the number of iterations for better quality during slowdown. You can do this in the Settings tab of the UnigineEditor.Возможно, вам потребуется увеличить FPS физики и количество итераций для улучшения качества во время замедления. Вы можете сделать это на вкладке Settings в UnigineEditor.

Adjust the position/rotation of the first_person_controller node to get a better initial view of the scene.Отрегулируйте положение/поворот ноды first_person_controller, чтобы начальная сцена выглядела лучше.

Click Run to see the result. As the box is rolling around, the physics-driven objects and collidable surfaces it hits along the way are highlighted, and contact details are displayed near the contact point. Whenever a collision occurs, it triggers an asset spawning and a slow motion effect.Нажмите Run, чтобы увидеть результат. Когда кубик вращается, объекты, управляемые физикой, и поверхности, с которыми он сталкивается по пути, подсвечиваются, а информация о контактах отображается рядом с точкой контакта. Всякий раз, когда происходит столкновение, это запускает запуск ассета и эффект замедленной съемки.

Примечание
All manipulations with physical bodies should belong to the UpdatePhysics() method.Все манипуляции с физическими телами должны принадлежать методу UpdatePhysics().

To disable the debug information, uncheck the Debug box under Node Components And Properties.Чтобы отключить отладочную информацию, снимите флажок Debug в разделе Node Components And Properties.

This is how you can easily track collisions and run necessary logic on time: spawn particles, play sounds, and destroy fracture objects.Таким образом, вы можете легко отслеживать столкновения и вовремя запускать необходимую логику: создавать частицы, воспроизводить звуки и убирать разрушаемые объекты.

Последнее обновление: 13.12.2024
Build: ()