Функции обратного вызова для обработки событий
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. Обратный вызов (коллбэк) - это обертка функции, представляющая собой указатель на статические функции и функции-члены, которые, как ожидается, будут выполнены с указанными параметрами в определенный момент. Функция обратного вызова может быть передана как аргумент другой функции.
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():
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: Коллбэк для функции-члена текущего или другого класса создается следующим образом:
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.. используются для создания обратного вызова с фиксированным количеством аргументов. В зависимости от количества аргументов следует использовать соответствующий класс. В этом случае вы должны предоставить аргументы шаблона:
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 raise a custom callback, the run() function of one of the CallbackBase classes is used. Для создания пользовательского обратного вызова используется функция run() класса CallbackBase...
// 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:Вы также можете использовать лямбда-выражения для определения функций обратного вызова:
// 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
#include <UnigineLogic.h>
#include <UnigineStreams.>
#include <UnigineCallback.h>
using namespace Unigine;
class AppWorldLogic : public WorldLogic {
public:
AppWorldLogic();
virtual ~AppWorldLogic();
virtual int init();
virtual int update();
virtual int postUpdate();
virtual int updatePhysics();
virtual int shutdown();
}
#endif // __APP_WORLD_LOGIC_H__
AppWorldLogic.cpp
#include "AppWorldLogic.h"
AppWorldLogic::AppWorldLogic()
{
}
AppWorldLogic::~AppWorldLogic()
{
}
int AppWorldLogic::update()
{
return 1;
}
class SomeClass
{
public:
// a member function to be called on 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 like in this case, 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 new parameters. The predefined ones will be ignored
callback2->run(351, 153);
// run the callback with only one first parameter.
// the second predefined parameter will be used as the second argument
callback2->run(118);
}
};
// a callback function to be called on 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();
a->create_callbacks();
Log::message("create a callback in other instance\n");
// use a member function of another class 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::postUpdate()
{
return 1;
}
int AppWorldLogic::updatePhysics()
{
return 1;
}
int AppWorldLogic::shutdown()
{
return 1;
Practical UseПрактическое использование#
Callbacks are widely used in event handling. A number of Unigine API members have several predefined events which can be handled by using callbacks in certain cases. Обратные вызовы широко используются при обработке событий. У ряда членов Unigine API есть несколько предопределенных событий, которые в определенных случаях можно обрабатывать с помощью обратных вызовов.
TriggersТриггеры#
Triggers are used to detect changes in nodes position or state. Unigine offers three types of built-in triggers: Триггеры используются для обнаружения изменений положения или состояния узлов. Unigine предлагает три типа встроенных триггеров:
- NodeTrigger fires callbacks when the trigger node is enabled or the trigger node position has changed. NodeTrigger запускает функцию обратного вызова, когда контролируемый им узел включается/выключается или изменяется его позиция.
- WorldTrigger fires callbacks when any node (collider or not) gets inside or outside of it. WorldTrigger запускает функцию обратного вызова, когда какой-либо узел (коллайдер или нет) входит внутрь или выходит из него.
- PhysicalTrigger fires callbacks when physical objects get inside or outside of it. PhysicalTrigger запускает функцию обратного вызова, когда физический объект входит внутрь или выходит из него.
Here is a simple WorldTrigger usage example: Вот простой пример использования WorldTrigger:
WorldTriggerPtr trigger;
int 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;
}
To remove the callbacks use the following code: Чтобы удалить обратные вызовы, используйте следующий код:
// 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 ).
WidgetsВиджеты#
The widgets base class Widget allows registering callbacks for events defined in the GUI class. The following example shows how to create a WidgetButton and register a callback function for the CLICKED event: Базовый класс виджетов Widget позволяет регистрировать обратные вызовы для событий, определенных в классе GUI. В следующем примере показано, как создать WidgetButton и зарегистрировать функцию обратного вызова для события CLICKED:
// 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;
}
Смотрите также
- A C++ API sample ( <UnigineSDK>/source/csharp/samples/Api/Widgets/WidgetCallbacks ). Пример C++ API (<UnigineSDK>/source/csharp/samples/Api/Widgets/WidgetCallbacks).
- An example of Creating User Interface. Пример Создания пользовательского интерфейса .
PhysicsФизика#
You can track certain events of the physics-related Bodies and Joints: Вы можете отслеживать определенные события связанных с физикой Bodies и Joints :
- Body::addFrozenCallback() to track an event when a body freezes. Body::addFrozenCallback() для отслеживания события, когда тело замерзает.
- Body::addPositionCallback() to track an event when a body changes its position. Body::addPositionCallback() для отслеживания события, когда тело меняет свое положение.
- Body::addContactEnterCallback() to track an event when a contact emerges (body starts touching another body or collidable surface). Body::addContactEnterCallback() для отслеживания события, когда возникает контакт (тело начинает касаться другого тела или поверхности, подверженной столкновению).
- Body::addContactLeaveCallback() to track an event when a contact ends (body stops touching another body or collidable surface). Body::addContactLeaveCallback() для отслеживания события, когда контакт заканчивается (тело перестает касаться другого тела или поверхности, подверженной столкновению).
- Body::addContactsCallback() to get all contacts of the body including new ones (enter) and the ending ones (leave). Leave contacts are removed after the callback execution stage, so this is the only point where you can still get them. Body::addContactsCallback(), чтобы получить все контакты тела, включая новые ( enter ) и конечные ( leave ). Оставленные контакты удаляются после этапа выполнения обратного вызова, поэтому это единственная точка, где вы все еще можете их получить.
- Joint::addBrokenCallback() to track an event when a joint breaks. Joint::addBrokenCallback() для отслеживания события при разрыве сустава.
The following sample shows the way of registering callbacks for a BodyRigid and change the color of a mesh depending on its state: В следующем примере показан способ регистрации обратных вызовов для BodyRigid и изменения цвета меша в зависимости от его состояния:
/* .. */
// set the node's albedo color to red on 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 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
MeshPtr mesh = Mesh::create();
mesh->addBoxSurface("box", vec3(1.0f));
ObjectMeshStaticPtr node = ObjectMeshStatic::create(mesh);
node->setMaterial("mesh_base", "*");
node->setPosition(Vec3(0, 0, 5.0f));
// add a rigid body to the box
BodyRigidPtr body = BodyRigid::create(node);
// 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;
}
/* .. */
Смотрите также
A C++ API sample located in the <UnigineSDK>/source/samples/Api/Physics/BodyCallbacks folder. Сэмпл C ++ API, расположенный в папке <UnigineSDK>/source/samples/Api/Physics/BodyCallbacks.
PropertiesСвойства (Properties)#
Callback functions can be used to determine actions to be performed when adding or removing node and surface properties as well as when swapping node properties. Here is an example demonstrating how to track adding a node property via callbacks: Функции обратного вызова могут использоваться для определения действий, которые должны выполняться при добавлении или удалении свойств (properties) узла и поверхности, а также при замене свойств узла. Вот пример, демонстрирующий, как отслеживать добавление свойства узла с помощью обратных вызовов:
NodePtr node;
void node_property_added(NodePtr node, PropertyPtr property)
{
Log::message("Property \"%s\" was added to the node named \"%s\".\n", property->getName(), node->getName());
// ...
}
// somewhere in the code
// inheriting a new property named "my_prop" from the base property "node_base"
Properties::findManualProperty("node_base")->inherit("my_prop");
// setting our callback function on adding a node property
node->addCallback(Node::CALLBACK_PROPERTY_NODE_ADD, MakeCallback(node_property_added));
// adding the property named "my_prop" to the node
node->addProperty("my_prop");
You can add callbacks to track any changes made to a property and its parameters and perform certain actions. Вы можете добавить обратные вызовы, чтобы отслеживать любые изменения, внесенные в свойство и его параметры, и выполнять определенные действия.
The example below shows how to add a callback to track changes of property parameters and report the name of the property and the changed parameter. В приведенном ниже примере показано, как добавить обратный вызов для отслеживания изменений параметров свойства и сообщить имя свойства и измененный параметр (предположим, что у нас есть ручное свойство с именем my_prop с целочисленным параметром с именем my_int_param).
void parameter_changed(PropertyPtr property, int num)
{
Log::message("Parameter \"%s\" of the property \"%s\" has changed its value.\n", property->getParameterName(num), property->getName());
// ...
}
// somewhere in the code
// getting a manual property named "my_prop" via the Property Manager
PropertyPtr property = Properties::findManualProperty("my_prop");
// setting our callback function on parameter change
property->addCallback(Property::CALLBACK_PARAMETER_CHANGED, MakeCallback(parameter_changed));
// changing the value of the "my_int_param" parameter
property->setParameterInt(property->findParameter("my_int_param"), 3);
You can also add callbacks to the Properties manager to track any changes made to any property and perform certain actions: Вы также можете добавить обратные вызовы диспетчеру Properties для отслеживания любых изменений, внесенных в любое свойство, и выполнения определенных действий:
void property_removed(PropertyPtr property)
{
Log::message("Property \"%s\" was removed.\n", property->getName());
// ...
}
// somewhere in the code
// inheriting a new property named "my_prop" from the base property "surface_base"
PropertyPtr property = Properties::findManualProperty("surface_base")->inherit("my_prop");
// setting our callback function on property removal
Properties::addCallback(Property::CALLBACK_REMOVED, MakeCallback(property_removed));
// removing the property named "my_prop"
Properties::removeProperty(Properties::findProperty("my_prop")->getGUID());
See AlsoСмотрите также#
These are not all usage examples of event handling callbacks. The following list contains more API members supporting event handling: Это не все примеры использования обратных вызовов обработки событий. Следующий список содержит другие члены API, поддерживающие обработку событий:
- UserInterface - for handling events from widgets created by loading a UI file. UserInterface - для обработки событий от виджетов, созданных путем загрузки файла пользовательского интерфейса.
- Render - callback functions can be used to get access to buffers and matrices at intermediate stages of the rendering sequence. Render - функции обратного вызова могут использоваться для получения доступа к буферам и матрицам на промежуточных этапах последовательности рендеринга .
- Console supports adding a callback function that will be executed when a text is output to the console. Console поддерживает добавление функции обратного вызова, которая будет выполняться при выводе текста на консоль.
- EditorLogic - a set of editor callback functions can be overridden for certain purposes. EditorLogic - набор функций обратного вызова редактора может быть переопределен для определенных целей.
- ComponentBase - there may be performed certain actions on destroying a component. ComponentBase - могут быть выполнены определенные действия по уничтожению компонента.
- AsyncQueue - сallback functions can be used to determine actions to be performed when certain resources are loaded. AsyncQueue - функции обратного вызова могут использоваться для определения действий, выполняемых при загрузке определенных ресурсов.
- WorldSplineGraph provides a set of callbacks for handling actions on editing points and segments. WorldSplineGraph предоставляет набор обратных вызовов для обработки действий по редактированию точек и сегментов.
- Viewport - callback functions can be used to get access to buffers and matrices at intermediate stages of the rendering sequence. Viewport - функции обратного вызова могут использоваться для получения доступа к буферам и матрицам на промежуточных этапах последовательности рендеринга .
Плагины: