Adding Interactive Area
In games and VR applications, some actions are performed when you enter a specific area in the scene (for example, music starts, sound or visual effects appear). Let's implement this in our project: when you enter or teleport to a certain area, it rains inside it.
In UNIGINE, the World Trigger node is used to track when any node (collider or not) gets inside or outside of it (for objects with physical bodies, the Physical Trigger node is used).
-
First of all, create a trigger to define the rain area. On the Menu bar, choose Create -> Logic -> World Trigger and place the trigger near the Material Ball, for example. Set the trigger size to (2, 2, 2).
-
Create a new TriggerZone component that will turn the rain node on and off (in our case, it is a particle system simulating rain), depending on the trigger state. Add the following code to the component and then assign it to the World Trigger node:
#pragma once #include <UnigineComponentSystem.h> #include <UnigineWorlds.h> class TriggerZone : public Unigine::ComponentBase { public: COMPONENT(TriggerZone, Unigine::ComponentBase); COMPONENT_INIT(init); // property name PROP_NAME("TriggerZone"); // node to be controlled by the trigger PROP_PARAM(Node, controlledNode); protected: void init(); // event handlers for the trigger void trigger_enter(const Unigine::NodePtr &player); void trigger_leave(const Unigine::NodePtr &player); private: // trigger node Unigine::WorldTriggerPtr trigger; // link to trigger event connections (all event connections will be removed on shutdown) Unigine::EventConnections conns; };
#include "TriggerZone.h" using namespace Unigine; REGISTER_COMPONENT(TriggerZone); void TriggerZone::init() { // check if the component is assigned to WorldTrigger if (node->getType() != Node::WORLD_TRIGGER) { Log::error("Node %s (TriggerZone) error: this component can only be assigned to a WorldTrigger.\n", node->getName()); ComponentSystem::get()->removeComponent<TriggerZone>(node); return; } // check if controlledNode is specified if (controlledNode.nullCheck()) { Log::error("Node %s (TriggerZone) error: 'controlledNode' is not assigned.\n", node->getName()); ComponentSystem::get()->removeComponent<TriggerZone>(node); return; } // add event handlers to be executed when a node gets inside and outside the trigger trigger = checked_ptr_cast<WorldTrigger>(node); trigger->getEventEnter().connect(conns, this, &TriggerZone::trigger_enter); trigger->getEventLeave().connect(conns, this, &TriggerZone::trigger_leave); } // handler function that enables ControlledNode when a Player enters the trigger void TriggerZone::trigger_enter(const NodePtr &player) { if (!player->isPlayer()) return; controlledNode->setEnabled(true); } // handler function that disables ControlledNode when a Player leaves the trigger void TriggerZone::trigger_leave(const NodePtr &player) { if (!player->isPlayer()) return; controlledNode->setEnabled(false); }
-
Now, let's add the rain effect. Drag the rain_effect.node asset from the vr/particles folder of the UNIGINE Starter Course Project add-on to the scene, add it as the child to the trigger node and turn it off (the component will turn it on later).
-
Drag the rain_effect node from the World Hierarchy window to the Controlled Node field of the TriggerZone (in the Parameters window).
Save changes (Ctrl+S) you've made to the world.
-
We also have to enable the Triggers Interaction option for the VR Player to make the trigger react on contacting it. Simply add the following line to the init_player() method of the VRPlayerSpawner component (Framework\Components\VRPlayerSpawner.cpp):
void VRPlayerSpawner::init_player(const PlayerPtr &player) { // copy transform player->setWorldTransform(node->getWorldTransform()); ${#HL}$player->setTriggerInteractionEnabled(true); ${HL#}$ if (node->getType() >= Node::PLAYER_BEGIN && node->getType() <= Node::PLAYER_END) { PlayerPtr player_ref = checked_ptr_cast<Player>(node); // copy basic parameters player->setFov(player_ref->getFov()); player->setZNear(player_ref->getZNear()); player->setZFar(player_ref->getZFar()); for (int i = 0 ; i < player_ref->getNumScriptableMaterials(); i++) player->addScriptableMaterial(player_ref->getScriptableMaterial(i)); } // unparent current node // (cause vr_group can be our parent and we don't want to turn off // components that are children to us) node->setWorldParent(NodePtr()); }
-
Save changes (Ctrl+S), rebuild the project, and run it via SDK Browser, then try to enter the area defined by the trigger — it should raininside.