This page has been translated automatically.
Видеоуроки
Интерфейс
Основы
Продвинутый уровень
Подсказки и советы
Основы
Программирование на C#
Рендеринг
Профессиональный уровень (SIM)
Принципы работы
Свойства (properties)
Компонентная Система
Рендер
Физика
Редактор UnigineEditor
Обзор интерфейса
Работа с ассетами
Контроль версий
Настройки и предпочтения
Работа с проектами
Настройка параметров ноды
Setting Up Materials
Настройка свойств
Освещение
Sandworm
Использование инструментов редактора для конкретных задач
Расширение функционала редактора
Встроенные объекты
Ноды (Nodes)
Объекты (Objects)
Эффекты
Декали
Источники света
Geodetics
World-ноды
Звуковые объекты
Объекты поиска пути
Player-ноды
Программирование
Настройка среды разработки
Примеры использования
C++
C#
UnigineScript
UUSL (Unified UNIGINE Shader Language)
Плагины
Форматы файлов
Материалы и шейдеры
Rebuilding the Engine Tools
Интерфейс пользователя (GUI)
VR Development
Двойная точность координат
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
Учебные материалы

Функции обратного вызова для обработки событий

Callback is a function wrapper representing a pointer to static and member functions which are expected to be executed with specified parameters at a certain moment. A callback can be passed as an argument to a function. Обратный вызов (коллбэк) - это обертка функции, представляющая собой указатель на статические функции и функции-члены, которые, как ожидается, будут выполнены с указанными параметрами в определенный момент. Функция обратного вызова может быть передана как аргумент другой функции.

Примечание
Callbacks are guaranteed to be reentrant and provide safe multi-threaded execution. Коллбэки гарантированно реентерабельны и обеспечивают безопасное многопоточное выполнение.

In Unigine C++ API, the CallbackBase is the base class to represent callbacks with variable number of arguments from 0 to 5. To create a callback, the MakeCallback() function is used: В Unigine C ++ API CallbackBase является базовым классом для представления функций обратного вызова с переменным числом аргументов от 0 до 5. Для создания функции обратного вызова используется функция MakeCallback():

Исходный код (C++)
void callback_function() {
	/* .. */
}
CallbackBase *callback = MakeCallback(callback_function);

A callback to a member function of either the current class or another is created as follows: Коллбэк для функции-члена текущего или другого класса создается следующим образом:

Исходный код (C++)
void ThisClass::callback_function() {
	/* .. */
}
/* .. */
// the first argument is an instance of a class, the second one is the pointer to a member function
CallbackBase *callback = MakeCallback(this, &ThisClass::callback_function);

The CallbackBase classes are used to create a callback with fixed number of arguments. Depending on the number of arguments the corresponding class should be used. In this case you should provide template arguments: Классы CallbackBase.. используются для создания обратного вызова с фиксированным количеством аргументов. В зависимости от количества аргументов следует использовать соответствующий класс. В этом случае вы должны предоставить аргументы шаблона:

Исходный код (C++)
void ThisClass::callback_function(NodePtr, int) {
	/* .. */
}
// create a callback with no predefined parameters
CallbackBase2<NodePtr, int> *callback = MakeCallback(this, &ThisClass::callback_function);

// create a callback with predefined parameters
CallbackBase2<NodePtr, int> *callback2 = MakeCallback(this, &ThisClass::callback_function, NodeDummy::create()->getNode(), 1);

// create a callback with parameters from lambda
CallbackBase2<NodePtr, int> *callback = MakeCallback([](NodePtr node, int value) { /* .. */ });

// create a callback with parameters from generic lambda
CallbackBase2<NodePtr, int> *callback = MakeCallback([](auto node, auto value) { /* .. */ });

To use overloaded functions and methods as callbacks, provide the template parameters:
MakeCallback< Class, ReturnType, Callback Parameters Types >
Для использования перегруженных функций и методов в качестве обратных вызовов необходимо указать параметры шаблона:
MakeCallback< Class, ReturnType, Callback Parameters Types >

Исходный код (C++)
void ThisClass::callback_method()
{
	/* .. */
}

void ThisClass::callback_method(WidgetPtr w, WidgetPtr w2, int i)
{
	/* .. */
}

CallbackBase *callback = MakeCallback<ThisClass, void, WidgetPtr, WidgetPtr, int>(this, &ThisClass::callback_method);

To raise a custom callback, the run() function of one of the CallbackBase classes is used. Для создания пользовательского обратного вызова используется функция run() класса CallbackBase...

Исходный код (C++)
// run the callback with no parameters or with default predefined parameters
callback->run();

// run the callback with the specified parameters
callback->run(node, 2);

You can also use lambda expressions for callbacks:Вы также можете использовать лямбда-выражения для определения функций обратного вызова:

Исходный код (C++)
// create a callback from lambda
int value = 5;
CallbackBase* callback = MakeCallback([value](){ /* .. */ });

// or std function
std::function<void()> callable_obj = [value]() { /* .. */ };
CallbackBase* callback = MakeCallback(callable_obj);

// or any other type of callable
struct Callable
{
void operator()() const { /* .. */ }
int value;
} callable_obj = { /* .. */ };

CallbackBase* callback = MakeCallback(callable_obj);

Usage ExampleПример использования#

The following section contains the complete source code of a simple callback usage example. В следующем разделе содержится полный исходный код простого примера использования обратного вызова.

AppWorldLogic.h
#ifndef __APP_WORLD_LOGIC_H__
#define __APP_WORLD_LOGIC_H__

#include <UnigineLogic.h>
#include <UnigineStreams.h>
#include <UnigineCallback.h>

using namespace Unigine;
using namespace Math;

class AppWorldLogic: public Unigine::WorldLogic
{

public:

	int init() override;

	int update() override;
	int postUpdate() override;
	int updatePhysics() override;

	int shutdown() override;

	int save(const Unigine::StreamPtr &stream) override;
	int restore(const Unigine::StreamPtr &stream) override;
};

#endif // __APP_WORLD_LOGIC_H__
AppWorldLogic.cpp
#include "AppWorldLogic.h"

class SomeClass
{
public:
	// a member function to be called on the action
	void callback_method(int a, int b)
	{
		Log::message("\tcallback_method has been called %d %d\n", a, b);
	}

	void create_callbacks()
	{
		Log::message("Create a callback with no predefined parameters\n");
		CallbackBase * callback = MakeCallback(this, &SomeClass::callback_method);

		// run the callback with two parameters
		callback->run(73, 37);
		// run the callback with no parameters.
		// if the callback function has arguments, this will lead to unsafe behaviour
		callback->run();

		Log::message("Create a callback with predefined parameters\n");
		CallbackBase * callback2 = MakeCallback(this, &SomeClass::callback_method, 1, 2);

		// run the callback with no parameters. In this case, the predefined parameters will be used
		callback2->run();
		// run the callback with parameters. The predefined ones will be ignored
		callback2->run(351, 153);
		// run the callback with only 1 parameter.
		// the second predefined parameter will be used as the second argument
		callback2->run(118);
	}
};

// a callback function to be called on the action
void callback_function(int a, int b)
{
	Log::message("\tcallback_function has been called %d %d\n", a, b);
}

int AppWorldLogic::init()
{
	SomeClass *some = new SomeClass();
	// call the SomeClass member function
	some->create_callbacks();

	Log::message("Create a callback in the other instance\n");
	// use the callback function of the SomeClass to create a callback
	CallbackBase * callback3 = MakeCallback(some, &SomeClass::callback_method, 5, 25);
	callback3->run();

	Log::message("Create callback functions\n");
	CallbackBase * callback4 = MakeCallback(&callback_function);
	callback4->run(20, 70);
	CallbackBase * callback5 = MakeCallback(&callback_function, 50, 25);
	callback5->run();

	return 1;
}

int AppWorldLogic::update()
{

	return 1;
}

int AppWorldLogic::postUpdate()
{
	return 1;
}

int AppWorldLogic::updatePhysics()
{
	return 1;
}

int AppWorldLogic::shutdown()
{
	return 1;
}

int AppWorldLogic::save(const Unigine::StreamPtr &stream)
{
	UNIGINE_UNUSED(stream);
	return 1;
}

int AppWorldLogic::restore(const Unigine::StreamPtr &stream)
{
	UNIGINE_UNUSED(stream);
	return 1;
}

Практическое использование#

Обратные вызовы широко используются при обработке событий. У ряда членов Unigine API есть несколько предопределенных событий, которые в определенных случаях можно обрабатывать с помощью обратных вызовов.

Триггеры#

Триггеры используются для обнаружения изменений положения или состояния узлов. Unigine предлагает три типа встроенных триггеров:

Вот простой пример использования WorldTrigger:

Исходный код (C++)
WorldTriggerPtr trigger;
void *enter_callback_id;

// implement the enter callback
void AppWorldLogic::enter_callback(NodePtr node)
{
	Log::message("\nA node named %s has entered the trigger\n", node->getName());
}

// implement the leave callback
void AppWorldLogic::leave_callback(NodePtr node)
{
	Log::message("\nA node named %s has left the trigger\n", node->getName());
}

int AppWorldLogic::init()
{

	// create a world trigger node
	trigger = WorldTrigger::create(Math::vec3(3.0f));

	// add the enter callback to be fired when a node enters the world trigger
	// and keep its id to be used to remove the callback when necessary
	enter_callback_id = trigger->addEnterCallback(MakeCallback(this, &AppWorldLogic::enter_callback));
	// add the leave callback to be fired when a node leaves the world trigger
	trigger->addLeaveCallback(MakeCallback(this, &AppWorldLogic::leave_callback));

	return 1;
}

Чтобы удалить обратные вызовы, используйте следующий код:

Исходный код (C++)
// remove the callback by using its id
trigger->removeEnterCallback(enter_callback_id);
// clear all leave callbacks
trigger->clearLeaveCallbacks();
Смотрите также
  • C++ API сэмпл ( <UnigineSDK>/source/samples/Api/Nodes/NodeTrigger ).
  • C++ API сэмпл ( <UnigineSDK>/source/samples/Api/Nodes/WorldTrigger ).
  • C++ API сэмпл ( <UnigineSDK>/source/samples/Api/Nodes/PhysicalTrigger ).

Виджеты#

Базовый класс виджетов Widget позволяет регистрировать обратные вызовы для событий, определенных в классе GUI. В следующем примере показано, как создать WidgetButton и зарегистрировать функцию обратного вызова для события CLICKED:

Исходный код (C++)
// event handler function
int AppWorldLogic::onButtonClicked()
{
	Log::message("\nThe widget button has been clicked\n");

	return 1;
}

int AppWorldLogic::init()
{

	// get a pointer to the system GUI
	GuiPtr gui = Gui::getCurrent();
	// create a button widget and set its caption
	WidgetButtonPtr widget_button = WidgetButton::create(gui, "Press me");
	// set a tooltip
	widget_button->setToolTip("Click this button");
	// rearrange a button size
	widget_button->arrange();
	// set a button position
	widget_button->setPosition(10, 10);
	// set the onButtonClicked function to handle the CLICKED event
	widget_button->addCallback(Gui::CLICKED, MakeCallback(this, &AppWorldLogic::onButtonClicked));
	// add the created button widget to the system GUI
	gui->addChild(widget_button, Gui::ALIGN_OVERLAP | Gui::ALIGN_FIXED);

	return 1;
}
Смотрите также

Физика#

Вы можете отслеживать определенные события связанных с физикой Bodies и Joints :

  • Body::addFrozenCallback() для отслеживания события, когда тело замерзает.
  • Body::addPositionCallback() для отслеживания события, когда тело меняет свое положение.
  • Body::addContactEnterCallback() для отслеживания события, когда возникает контакт (тело начинает касаться другого тела или поверхности, подверженной столкновению).
  • Body::addContactLeaveCallback() для отслеживания события, когда контакт заканчивается (тело перестает касаться другого тела или поверхности, подверженной столкновению).
  • Body::addContactsCallback(), чтобы получить все контакты тела, включая новые ( enter ) и конечные ( leave ). Оставленные контакты удаляются после этапа выполнения обратного вызова, поэтому это единственная точка, где вы все еще можете их получить.
  • Joint::addBrokenCallback() для отслеживания события при разрыве сустава.

В следующем примере показан способ регистрации обратных вызовов для BodyRigid и изменения цвета меша в зависимости от его состояния:

Исходный код (C++)
// set the node's albedo color to red on the freezing event
int AppWorldLogic::frozen_callback(BodyPtr body)
{
	body->getObject()->setMaterialParameterFloat4("albedo_color", vec4(1.0f, 0.0f, 0.0f, 1.0f), 0);

	return 1;
}

// set the node's albedo color to blue on the position change event
int AppWorldLogic::position_callback(BodyPtr body)
{
	body->getObject()->setMaterialParameterFloat4("albedo_color", vec4(0.0f, 0.0f, 1.0f, 1.0f), 0);

	return 1;
}

// set the node's albedo color to yellow on each contact
int AppWorldLogic::contact_enter_callback(BodyPtr body, int num)
{
	body->getObject()->setMaterialParameterFloat4("albedo_color", vec4(1.0f, 1.0f, 0.0f, 1.0f), 0);

	return 1;
}

int AppWorldLogic::init()
{

	// create a box
	ObjectMeshStaticPtr meshStatic = ObjectMeshStatic::create("core/meshes/box.mesh");
	meshStatic->setPosition(Vec3(0, 0, 5.0f));
	// add a rigid body to the box
	BodyRigidPtr body = BodyRigid::create(meshStatic);
	// register callbacks for events
	body->addFrozenCallback(MakeCallback(this, &AppWorldLogic::frozen_callback));
	body->addPositionCallback(MakeCallback(this, &AppWorldLogic::position_callback));
	body->addContactEnterCallback(MakeCallback(this, &AppWorldLogic::contact_enter_callback));
	// add a shape to the body
	ShapeBoxPtr shape = ShapeBox::create(body, vec3(1.0f));

	return 1;
}
Примечание
Обратные вызовы на основе физики выполняются в основном потоке, поскольку они в основном используются для создания, уничтожения или модификации других объектов.
Смотрите также

Сэмпл C ++ API, расположенный в папке <UnigineSDK>/source/samples/Api/Physics/BodyCallbacks.

Свойства (Properties)#

Функции обратного вызова могут использоваться для определения действий, которые должны выполняться при добавлении или удалении свойств (properties) узла и поверхности, а также при замене свойств узла. Вот пример, демонстрирующий, как отслеживать добавление свойства узла с помощью обратных вызовов:

Исходный код (C++)
void AppWorldLogic::node_property_added(NodePtr node, PropertyPtr property)
{
	Log::message("Property \"%s\" was added to the node named \"%s\".\n", property->getName(), node->getName());
}

int AppWorldLogic::init()
{

	NodeDummyPtr node = NodeDummy::create();

	// search for a property named "new_property_0"
	PropertyPtr property = Properties::findProperty("new_property_0");

	// set the callback function on adding a node property
	node->addCallback(Node::CALLBACK_PROPERTY_NODE_ADD, MakeCallback(this, &AppWorldLogic::node_property_added));

	// add the property named "new_property_0" to the node
	node->addProperty("new_property_0");

	return 1;
}

Вы можете добавить обратные вызовы, чтобы отслеживать любые изменения, внесенные в свойство и его параметры, и выполнять определенные действия.

В приведенном ниже примере показано, как добавить обратный вызов для отслеживания изменений параметров свойства и сообщить имя свойства и измененный параметр (предположим, что у нас есть ручное свойство с именем my_prop с целочисленным параметром с именем my_int_param).

Исходный код (C++)
void AppWorldLogic::parameter_changed(PropertyPtr property, int num)
{
	Log::message("Parameter \"%s\" of the property \"%s\" has changed its value.\n", property->getParameterPtr(num)->getName(), property->getName());	
}

int AppWorldLogic::init()
{

	// set the callback function on parameter change
	property->addCallback(Property::CALLBACK_PARAMETER_CHANGED, MakeCallback(this, &AppWorldLogic::parameter_changed));

	// change the value of the "my_int_param" parameter
	property->getParameterPtr("my_int_param")->setValueInt(3);

	return 1;
}

Вы также можете добавить обратные вызовы диспетчеру Properties для отслеживания любых изменений, внесенных в любое свойство, и выполнения определенных действий:

Исходный код (C++)
void AppWorldLogic::property_removed(PropertyPtr property)
{
	Log::message("Property \"%s\" was removed.\n", property->getName());
}

int AppWorldLogic::init()
{

	// inherit a new property named "new_property_1" from the base property "surface_base"
	Properties::findManualProperty("surface_base")->inherit("new_property_1");

	// set the callback function on property removal
	Properties::addCallback(Properties::CALLBACK_REMOVED, MakeCallback(this, &AppWorldLogic::property_removed));

	// remove the property named "new_property_1"
	Properties::removeProperty(Properties::findProperty("new_property_1")->getGUID());

	return 1;
}
Последнее обновление: 19.12.2023
Build: ()