UnigineEditor
Interface Overview
Assets Workflow
Settings and Preferences
Working With Projects
Adjusting Node Parameters
Setting Up Materials
Setting Up Properties
Landscape Tool
Using Editor Tools for Specific Tasks
Extending Editor Functionality
Программирование
Fundamentals
Setting Up Development Environment
Usage Examples
UnigineScript
C++
C#
UUSL (Unified UNIGINE Shader Language)
File Formats
Rebuilding the Engine and Tools
GUI
Double Precision Coordinates
API
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

11. Implementing Game Logic and Using Properties

<< RETURN TO THE PREVIOUS SECTION

Best Practice
This section covers low-level game logic implementation using Properties. The recommended workflow is Component System which is available for C++ and C# API.

Properties are used as "materials" for application logic, they contain user-defined parameters and can be assigned to nodes. In order to use custom properties you should:

  • Make a manual property file — an xml-file which defines your property and all necessary parameters.
    Source code (XML)
    <?xml version="1.0" encoding="utf-8"?>
    <property version="2.10.0.0" name="my_node_base" parent="node_base" manual="1">
    		<parameter name="selected">0</parameter>
    		<parameter name="material" type="string">sometext</parameter>
    </property>
  • Manage properties (states, parameter values, etc.) using the Property class and assign them to objects.
Source code (C++)
// finding the manual property
PropertyPtr my_node_base = Properties::findManualProperty("my_node_base");

// inheriting a new property to create a hierarchy of properties
my_node_base->inherit("new_property");

// getting pointer to the property named "new_property"
PropertyPtr new_prop1 = Properties::findProperty("new_property");

// setting the values of property parameters by getting pointers to them
new_prop1->getParameterPtr("my_param1")->setValue(0);
new_prop1->getParameterPtr("my_param2")->setValue("text 1");

// setting the values of property parameters by using the parameters ids
new_prop1->setParameterInt(new_prop1->findParameter("my_param1"), 0);
new_prop1->setParameterString(new_prop1->findParameter("my_param2"), "text 1");

// assigning the property to a node
// a new internal child property is created and inherits all parameters of the parent one
object1->addProperty(new_prop1);

// getting a pointer to the internal property assigned to the node at the first index
PropertyPtr internal_prop = object1->getProperty(0);

//getting the parameters of the property assigned to the node
int int_param = internal_prop->getParameterPtr("my_param1")->getValueInt();
const char *string_param = internal_prop->getParameterString(internal_prop->findParameter("my_param_2"));

Additional information:

Project Progress#

In our project we are going to use properties to select objects and highlight them by changing their material. Here's when we are going to utilize our mouse input handler, getObjectUnderMouseCursor and selectObject methods from previous sections.

First, we are going to inherit a property from the standard node_base and add 2 parameters:

  • selected - to indicate if the object is currently selected and we must highlight it.
  • material - to store the name of material assigned to the surface of the object in order to reset it when selection changes.
So, please use the following code and save it as "my_property.prop" in the data folder of your application.
Source code (XML)
<?xml version="1.0" encoding="utf-8"?>
<property version="2.10.0.0" name="my_node_base" parent="node_base" manual="1">
		<parameter name="selected">0</parameter>
		<parameter name="material" type="string">sometext</parameter>
</property>

In the AppWorldLogic.h file, we add a pointer to store previously selected object (to reset back its material).

Source code (C++)
// AppWorldLogic.h
	
/* .. */

class AppWorldLogic : public Unigine::WorldLogic {
	
public:

/* .. */

private:


/* .. */

	Unigine::ObjectPtr old_selection;	// pointer to previously selected object

/* .. */


};

In the AppWorldLogic.cpp file let us:

  • make some changes to our addMeshToScene method to initialize properties of created object
  • make some changes to our selectObject function to manage previously selected object
  • add second parameter when calling the selectObject function in the AppWorldLogic::update() method.
  • add some code to our updateObjects method in order to highlight currently selected object.
  • change the removeMeshFromScene in order to check if we remove currently selected object to handle the situation correctly.
Source code (C++)
// AppWorldLogic.cpp

/* .. */

/// method adding a Dynamic Mesh Object to the scene. 
/// if an empty filename is passed the method creates a default box; 
/// otherwise, loads a mesh-file with a given name.
int AppWorldLogic::addMeshToScene(const char *file_name, const char *mesh_name, const char *material_name, Math::Vec3 position)
{
	MeshPtr mesh = Mesh::create();
	ObjectMeshDynamicPtr omd;
	
	if (file_name){				// loading a mesh from a specified file
		if (!mesh->load(file_name))
		{
			Log::error("\nError opening .mesh file!\n");
			mesh.clear();
			
			return 0;
		}
		else omd = ObjectMeshDynamic::create(mesh);
	}
	else						//creating a default box
	{
		mesh->addBoxSurface("box_surface", Math::vec3(0.5f));

		omd = ObjectMeshDynamic::create(mesh);
	}
	
	// setting object's material, name and position
	omd->setMaterial(material_name, "*");
	omd->setName(mesh_name);
	omd->setWorldPosition(position);

	// finding the "my_node_base" property
	PropertyPtr my_node_base = Properties::findManualProperty("my_node_base");

	// assigning the property to the node so a new internal child property is created and inherits all parameters of the parent one
	omd->addProperty(my_node_base);
	omd->getProperty(0)->getParameterPtr("material")->setValue(material_name);
	omd->getProperty(0)->getParameterPtr("selected")->setValue(0);

	// enabling intersection detection for the first surface (0)
	omd->setIntersection(1, 0);
	
	// updating the list of scene objects
	Objects.append(omd);

	// reporting progress to the console
	Log::message("-> Object %s added to the scene.\n", mesh_name);

	// clearing the mesh
	mesh.clear();

	return 1;
}

/* .. */

/// function setting new object as selected and updating previous selection
int selectObject(ObjectPtr new_selected_object, ObjectPtr &old_selected_object)
{
	// checking if we already have the object selected previously
	if (old_selected_object == new_selected_object)
		return 0;
	// checking if we already have a previously selected object and setting its "selected" parameter of the property to 0
	if (old_selected_object)
	{
		// checking if the my_node_base property is assigned to the object
		int property_id = old_selected_object->findProperty("my_node_base");
		if (property_id >= 0)
		{
			PropertyPtr my_node_base = old_selected_object->getProperty(property_id);
			my_node_base->setParameterInt(my_node_base->findParameter("selected"), 0);
			my_node_base->setParameterString(my_node_base->findParameter("material"), "text");
		}
	}
	// checking if new selected object is not NULL and it has a property with parameter "selected" assigned
	if (new_selected_object)
	{
		int property_id = new_selected_object->findProperty("my_node_base");
		if (property_id >= 0)
		{
			PropertyPtr my_node_base = new_selected_object->getProperty(property_id);
			my_node_base->setParameterInt(my_node_base->findParameter("selected"), 1);

			old_selected_object = new_selected_object;
		}
		return 1;
	}
	return 0;
}
/* .. */

/// method deleting a Dynamic Mesh Object with a given number from the scene
int AppWorldLogic::removeMeshFromScene(const char *node_name)
{
	// getting a pointer to the node with a given name and downcasting it to ObjectMeshDynamicPtr
	ObjectMeshDynamicPtr object = checked_ptr_cast<ObjectMeshDynamic>(World::getNodeByName(node_name));

	if (object)
	{
		// checking if the node to be removed was previously selected
		if (old_selection && old_selection == object)
		{
			// resetting old_selection pointer to NULL
			old_selection.clear();
		}
		
		// reporting node deletion to the console
		Log::message("Removing %s node named %s from the scene.\n", object->getTypeName(), node_name);

		// removing the node with a given name from the list of scene objects
		for (int i = 0; i < Objects.size();i++)
		{
			if (strcmp(Objects[i]->getName(), node_name) == 0)
			{
				Objects.remove(i);

				break;
			}
		}

		// removing the node from the scene
		object->deleteLater();
		
		return 1;
	}

	return 0;
}
/* .. */

/// method updating the initial set of scene objects
int AppWorldLogic::updateObjects(float ifps)
{
	ObjectMeshDynamicPtr object;

	// changing transformation for all scene objects named "my_meshdynamic_*" (initial set)
	for (auto it = Objects.begin(); it != Objects.end(); it++)
	{
		object = it.get();

		// searching for the property assigned to the object 
		int property_id = object->findProperty("my_node_base");

		// checking if such property exists and has a "selected" parameter
		if (property_id >= 0)
		{
			PropertyPtr p = object->getProperty(property_id);
			PropertyParameterPtr param = p->getParameterPtr("selected");
			if (param)
				if (param->getValueInt() == 1)
				{
					// if "selected" parameter value is 1 assigning "mesh_base" material to the object to highlight it
					object->setMaterial("mesh_base", "*");
				}
				else
				{
					// if "selected" parameter value is 0 assigning the material that is stored in the "material" parameter of its property
					object->setMaterial(p->getParameterPtr("material")->getValueString(), "*");
				}
		}

		// if a node is named "my_meshdynamic_*" (it belongs to the initial set) change its transformation
		if (strstr(object->getName(), "my_meshdynamic_"))
		{
			// transform the node
			transformNode(object, ifps);
		}
	}

	return 1;
}

/* .. */


int AppWorldLogic::shutdown() 
{
/* .. */

	// resetting old_selection pointer
	old_selection.clear();

	// clearing all created properties
	clearProperties();

/* .. */

}

Source Files#

You can copy the code below and paste it to the corresponding source files of your project:

AppWorldLogic.h

Source code (C++)
#ifndef __APP_WORLD_LOGIC_H__
#define __APP_WORLD_LOGIC_H__

#include <UnigineLogic.h>
#include <UnigineStreams.h>
#include <UnigineObjects.h>
#include <UnigineGame.h>
#include <UnigineLights.h>
#include <UnigineMaterials.h>
#include <UnigineWorld.h>
#include <UnigineApp.h>
#include <UnigineConsole.h>
#include <UnigineInput.h>
#include <UnigineProperties.h>

using namespace Unigine;

// auxiliary constants
const float DELTA_ANGLE = 60.0f;		// delta angle of objects rotation
const float MOVING_SPEED = 3.0f;		// speed of objects movement
const float CHANGE_INTERVAL = 1.0f;		// the interval between changes of objects' parameters, in seconds
const float SUN_ROTATION_RATE = 10.0f;	// rotation rate of the sun

class AppWorldLogic : public WorldLogic {
	
public:
	AppWorldLogic();
	virtual ~AppWorldLogic();
	
	virtual int init();
	
	virtual int update();
	virtual int postUpdate();
	virtual int updatePhysics();
	
	virtual int shutdown();
	virtual int destroyRenderResources();
	
	virtual int save(const StreamPtr &stream);
	virtual int restore(const StreamPtr &stream);
private:
	PlayerSpectatorPtr player;


	// pointers to light sources
	LightWorldPtr thesun;
	LightOmniPtr light_omni;
	LightProjPtr projector;

	// auxiliary functions
	int addMeshToScene(const char *file_name, const char *mesh_name, const char *material_name, Math::Vec3 position);
	int removeMeshFromScene(const char *node_name);
	int transformNode(NodePtr node);

	// initialization functions
	int initObjects();
	int initPlayer();
	int initLights();
	int initMaterials();

	// update functions
	int updateLights();
	int updateObjects();

	// shutdown functions
	int clearMaterials();
	int clearProperties();
	int removeObjects();

	// scene objects vector
	Vector <ObjectMeshDynamicPtr> Objects;
	
	ObjectPtr old_selection;												// pointer to previously selected object
	Math::vec3 current_objects_scale = Math::vec3(1.0f);			// current scaling vector for objects
	Math::Vec3 forward_direction = Math::Vec3(0.0f, -1.0f, 0.0f);	// current forward direction vector for objects
	float elapsed_time = CHANGE_INTERVAL;											// current time left to change current scale and forward direction of our objects
	float sun_angle = 0.0f;															// current sun position
};

#endif // __APP_WORLD_LOGIC_H__

AppWorldLogic.cpp

Source code (C++)
#include "AppWorldLogic.h"
// World logic, it takes effect only when the world is loaded.
// These methods are called right after corresponding world script's (UnigineScript) methods.

//-----------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------- AUXILIARY FUNCTIONS AND METHODS ----------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------------

/// method adding a Dynamic Mesh Object to the scene. If an empty filename is passed the method creates a default box; otherwise, loads a mesh-file with a given name.
int AppWorldLogic::addMeshToScene(const char *file_name, const char *mesh_name, const char *material_name, Math::Vec3 position)
{
	MeshPtr mesh = Mesh::create();
	ObjectMeshDynamicPtr omd;

	if (file_name){				// loading a mesh from a specified file
		if (!mesh->load(file_name))
		{
			Log::error("\nError opening .mesh file!\n");
			mesh.clear();
			
			return 0;
		}
		else omd = ObjectMeshDynamic::create(mesh);
	}
	else						// creating a default box
	{
		mesh->addBoxSurface("box_surface", Math::vec3(0.5f));

		omd = ObjectMeshDynamic::create(mesh);
	}

	// setting object's material, name and position
	omd->setMaterial(material_name, "*");
	omd->setName(mesh_name);
	omd->setWorldPosition(position);

	// finding the "my_node_base" property
	PropertyPtr my_node_base = Properties::findManualProperty("my_node_base");

	// assigning the property to the node so a new internal child property is created and inherits all parameters of the parent one
	omd->addProperty(my_node_base);
	PropertyPtr internal_property = omd->getProperty(0);
	internal_property->setParameterString(internal_property->findParameter("material"), material_name);
	internal_property->getParameterPtr("selected")->setValue(0);

	// enabling intersection detection for the first surface (0)
	omd->setIntersection(1, 0);

	// updating the list of scene objects
	Objects.append(omd);

	// reporting progress to the console
	Log::message("-> Object %s added to the scene.\n", mesh_name);

	// clearing the mesh
	mesh.clear();

	return 1;

}
//-----------------------------------------------------------------------------------------------------------------------------
/// method deleting a Dynamic Mesh Object with a given name from the scene
int AppWorldLogic::removeMeshFromScene(const char *node_name)
{
	// getting a pointer to the node with a given name and downcasting it to ObjectMeshDynamicPtr
	ObjectMeshDynamicPtr object = checked_ptr_cast<ObjectMeshDynamic>(World::getNodeByName(node_name));

	if (object)
	{
		// checking if the node to be removed was previously selected
		if (old_selection && old_selection == object)
		{
			// resetting old_selection pointer to NULL
			old_selection.clear();
		}

		// reporting node deletion to the console
		Log::message("Removing %s node named %s from the scene.\n", object->getTypeName(), node_name);

		// removing the node with a given name from the list of scene objects
		for (int i = 0; i < Objects.size(); i++)
		{
			if (strcmp(Objects[i]->getName(), node_name) == 0) {
				Objects.remove(i);
				break;
			}
		}

		// removing the node from the scene
		object->deleteLater();

		return 1;
	}

	return 0;
}
//-----------------------------------------------------------------------------------------------------------------------------
/// method performing node transformations 
int AppWorldLogic::transformNode(NodePtr node)
{
	// getting current node transformation matrix
	Math::Mat4 transform = node->getTransform();

	// calculating delta rotation around an arbitrary axis
	Math::quat delta_rotation = Math::quat(rand() % 2, rand() % 2, rand() % 2, DELTA_ANGLE * Game::getIFps());

	// setting node's scale, rotation and position
	node->setWorldScale(current_objects_scale);
	node->setWorldRotation(node->getWorldRotation() * delta_rotation);
	node->setWorldPosition(node->getWorldPosition() + forward_direction * MOVING_SPEED * Game::getIFps());

	return 1;
}
//-----------------------------------------------------------------------------------------------------------------------------
/// function getting an object under the mouse cursor
ObjectPtr getObjectUnderMouseCursor(const PlayerPtr &player, int mouse_x, int mouse_y, float max_dist)
{
	// setting start point (p0) at the center of player's screen
	Math::Vec3 p0 = player->getWorldPosition();

	// setting end point (p1) according to the position of the mouse cursor
	Math::Vec3 p1 = p0 + Math::Vec3(player->getDirectionFromScreen(mouse_x, mouse_y)) * max_dist;

	WorldIntersectionPtr intersection = WorldIntersection::create();

	// returning the pointer to the first intersected object if any or NULL
	return World::getIntersection(p0, p1, 1, intersection);
}
//-----------------------------------------------------------------------------------------------------------------------------
/// function setting new object as selected and updating previous selection
int selectObject(ObjectPtr new_selected_object, ObjectPtr &old_selected_object)
{
	// checking if we already have the object selected previously
	if (old_selected_object == new_selected_object)
		return 0;
	// checking if we already have a previously selected object and setting its "selected" parameter of the property to 0
	if (old_selected_object)
	{
		int property_id = old_selected_object->findProperty("my_node_base");
		if (property_id >= 0)
		{
			PropertyPtr my_node_base = old_selected_object->getProperty(property_id);
			my_node_base->setParameterInt(my_node_base->findParameter("selected"), 0);
		}
	}
	// checking if new selected object is not NULL and it has a property with parameter "selected" assigned
	if (new_selected_object)
	{
		int property_id = new_selected_object->findProperty("my_node_base");
		if (property_id >= 0)
		{
			PropertyPtr my_node_base = new_selected_object->getProperty(property_id);
			my_node_base->setParameterInt(my_node_base->findParameter("selected"), 1);

			old_selected_object = new_selected_object;
		}
		return 1;
	}
	return 0;
}

//-----------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------- INITIALIZATION METHODS -------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------------
/// method performing initialization of the set of 4 boxes
int AppWorldLogic::initObjects()
{
	int index = 0;

	for (int x = 0; x < 2; x++)
	{
		for (int y = 0; y < 2; y++)
		{
			addMeshToScene(NULL, String::format("my_meshdynamic_%d", index), String::format("my_mesh_base%d", index), Math::Vec3(x, y, 1.0f));
			index++;
		}
	}

	// reporting progress to the console
	Log::warning("Objects generation OK!\n\n");

	return 1;
}
//-----------------------------------------------------------------------------------------------------------------------------
/// method performing initialization of the player
int AppWorldLogic::initPlayer()
{
	// creating a new PlayerSpectator instance
	player = PlayerSpectator::create();

	// setting player's FOV, ZNear, ZFar
	player->setFov(90.0f);
	player->setZNear(0.1f);
	player->setZFar(10000.0f);

	// setting player's view direction vector and position
	player->setPosition(Math::Vec3(3.0f));
	player->setDirection(Math::vec3(-1.0f), Math::vec3(0.0f, 0.0f, -1.0f));

	// setting the player as a default one via the Game singleton instance
	Game::setPlayer(player);

	//reporting progress to the console
	Log::warning("\nPlayer initialization OK!\n\n");

	return 1;
}
//-----------------------------------------------------------------------------------------------------------------------------
/// method performing initialization of lights
int AppWorldLogic::initLights()
{
	// creating an omni light and setting up its parameters
	light_omni = LightOmni::create(Math::vec4(1.0f, 1.0f, 1.0f, 1.0f), 10.0f, "");
	light_omni->setWorldPosition(Math::Vec3(0.0f, 0.0f, 5.0f));
	light_omni->setIntensity(0.1f);

	// reporting progress to the console
	Log::message("-> Created a %s light source.\n", light_omni->getName());

	// creating a world light and setting up its parameters
	thesun = LightWorld::create(Math::vec4(1.0f, 1.0f, 1.0f, 1.0f));
	thesun->setName("Sun");
	thesun->setDisableAngle(90.0f);
	thesun->setIntensity(1.0f);
	thesun->setScattering(LightWorld::SCATTERING_SUN);
	thesun->setWorldRotation(Math::quat(86.0f, 30.0f, 300.0f));

	// reporting progress to the console
	Log::message("-> Created a %s light source.\n", thesun->getName());

	// creating a proj light and setting up its parameters
	projector = LightProj::create(Math::vec4(1.0f, 1.0f, 0.5f, 1.0f), 10.0f, 60.0f, "");
	projector->setWorldPosition(Math::Vec3(2.5f, 2.5f, 3.0f));
	projector->setName("projector");
	projector->setRotation(Math::quat(-45.0f, 45.0f, 0.0f));
	projector->setPenumbra(0.425f);
	projector->setIntensity(1.0f);

	// reporting progress to the console
	Log::message("-> Created a %s light source.\n", projector->getName());
	Log::warning("Lights initialization OK!\n");

	return 1;
}
//-----------------------------------------------------------------------------------------------------------------------------
/// method performing initialization of materials
int AppWorldLogic::initMaterials()
{
	// creating a new child material of the mesh_base and setting its color
	MaterialPtr mesh_base = Materials::findMaterial("mesh_base");
	MaterialPtr my_mesh_base = mesh_base->inherit("my_mesh_base0");
	my_mesh_base->setParameterFloat4("albedo_color", Math::vec4(255, 0, 0, 255));

	// reporting progress to the console
	Log::message("\n-> Generated %s material.\n", my_mesh_base->getName());

	// creating a new child material of the mesh_base and setting its color
	my_mesh_base = mesh_base->inherit("my_mesh_base1");
	my_mesh_base->setParameterFloat4("albedo_color", Math::vec4(0, 255, 0, 255));

	// reporting progress to the console
	Log::message("-> Generated %s material.\n", my_mesh_base->getName());

	//creating a new child material of the mesh_base and setting its color
	my_mesh_base = mesh_base->inherit("my_mesh_base2");
	my_mesh_base->setParameterFloat4("albedo_color", Math::vec4(0, 0, 255, 255));

	// reporting progress to the console
	Log::message("-> Generated %s material.\n", my_mesh_base->getName());

	//creating a new child material of the mesh_base and setting its color
	my_mesh_base = mesh_base->inherit("my_mesh_base3");
	my_mesh_base->setParameterFloat4("albedo_color", Math::vec4(255, 255, 0, 255));

	// reporting progress to the console
	Log::message("-> Generated %s material.\n", my_mesh_base->getName());
	Log::warning("Material generation OK!\n\n");

	// clearing material pointer
	my_mesh_base.clear();

	return 1;
}
//-----------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------- UPDATE METHODS ---------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------------
/// method updating the position of the sun
int AppWorldLogic::updateLights()
{
	// updating the Sun rotation angle
	sun_angle += SUN_ROTATION_RATE * Game::getIFps();
	if (sun_angle > 360.0f) sun_angle = 0.0f;

	// changing the Sun position using the new angle
	thesun->setWorldRotation(Math::quat(Math::vec3(0.5f, 0.0f, 0.5f), 180.0f - sun_angle));

	return 1;
}
//-----------------------------------------------------------------------------------------------------------------------------
/// method updating the initial set of scene objects
int AppWorldLogic::updateObjects()
{
	ObjectMeshDynamicPtr object;

	// changing transformation for all scene objects named "my_meshdynamic_*" (initial set)
	for (auto it = Objects.begin(); it != Objects.end(); it++)
	{
		object = it.get();

		// searching for the property assigned to the object 
		int property_id = object->findProperty("my_node_base");

		// checking if such property exists and has a "selected" parameter
		if (property_id >= 0)
		{
			PropertyPtr p = object->getProperty(property_id);
			if (p->getParameterPtr("selected")->getValueInt() == 1)
			{
				// if "selected" parameter value is 1 assigning "mesh_base" material to the object to highlight it
				object->setMaterial("mesh_base", "*");
			}
			else
			{
				// if "selected" parameter value is 0 assigning the material that is stored in the "material" parameter of its property
				object->setMaterial(p->getParameterString(p->findParameter("material")), "*");
			}
		}

		// if a node is named "my_meshdynamic_*" (it belongs to the initial set) change its transformation
		if (strstr(object->getName(), "my_meshdynamic_"))
		{
			// transform the node
			transformNode(object);
		}
	}

	return 1;
}
//-----------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------- SHUTDOWN METHODS -------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------------
/// method removing all created materials
int AppWorldLogic::clearMaterials()
{
	Materials::removeMaterial(Materials::findMaterial("my_mesh_base0")->getGUID());
	Materials::removeMaterial(Materials::findMaterial("my_mesh_base1")->getGUID());
	Materials::removeMaterial(Materials::findMaterial("my_mesh_base2")->getGUID());
	Materials::removeMaterial(Materials::findMaterial("my_mesh_base3")->getGUID());

	return 1;
}
//-----------------------------------------------------------------------------------------------------------------------------
/// method removing all  created objects
int AppWorldLogic::removeObjects()
{
	while (Objects.size() > 0)
	{
		removeMeshFromScene(Objects.begin()->get()->getName());
	}

	return 1;
}
//-----------------------------------------------------------------------------------------------------------------------------
AppWorldLogic::AppWorldLogic() {
	
}

AppWorldLogic::~AppWorldLogic() {
	
}

int AppWorldLogic::init() {
	// Write here code to be called on world initialization: initialize resources for your world scene during the world start.
	
	// initializing pseudo-random number generator
	Game::setSeed(time(NULL));

	// creating materials
	initMaterials();
	
	// creating objects
	initObjects();

	// creating a player
	initPlayer();

	// creating lights
	initLights();
	
	return 1;
}

// start of the main loop
int AppWorldLogic::update() {
	// Write here code to be called before updating each render frame: specify all graphics-related functions you want to be called every frame while your application executes.

	// checking if it's time to change current scale and forward vector direction of our objects
	if (elapsed_time < 0.0f)
	{
		// change current scaling vector for objects
		current_objects_scale = Math::vec3(Game::getRandomFloat(0.8f, 1.2f));

		// change forward direction for objects
		forward_direction = forward_direction * Math::rotateZ(60.0f);

		// resetting elapsed time counter
		elapsed_time = CHANGE_INTERVAL;
	}
	
	// decreasing the time counter to the next change of current scale and forward vector direction
	elapsed_time -= Game::getIFps();

	// if right mouse button is clicked
	if (Input::isMouseButtonPressed(Input::MOUSE_BUTTON_RIGHT))
	{
		// get and select object under the mouse cursor
		Math::ivec2 mouse = Input::getMouseCoord();
		selectObject(getObjectUnderMouseCursor(Game::getPlayer(), mouse.x, mouse.y, 100.0f), old_selection);
	}

	// closing the application if a &#039;Q&#039; key is pressed, ignoring the key if the console is opened
	if (Input::isKeyDown(Input::KEY_Q) && !Console::getActivity())
	{
		App::exit();
	}

	// updating objects
	updateObjects();

	// updating lights
	updateLights();

	return 1;
}

int AppWorldLogic::postUpdate() {
	// The engine calls this function before rendering each render frame: correct behavior after the state of the node has been updated.
	
	return 1;
}

int AppWorldLogic::updatePhysics() {
	// Write here code to be called before updating each physics frame: control physics in your application and put non-rendering calculations.
	// The engine calls updatePhysics() with the fixed rate (60 times per second by default) regardless of the FPS value.
	// WARNING: do not create, delete or change transformations of nodes here, because rendering is already in progress.
	
	return 1;
}
// end of the main loop

int AppWorldLogic::shutdown() {
// Write here code to be called on world shutdown: delete resources that were created during world script execution to avoid memory leaks.
		
	// deleting all created nodes
	removeObjects();

	// clearing the player pointer
	player->deleteLater();

	// clearing light sources
	thesun->deleteLater();
	light_omni->deleteLater();
	projector->deleteLater();

	// clearing all created materials
	clearMaterials();
	
	// resetting old_selection pointer
	old_selection.clear();

	return 1;
}

int AppWorldLogic::destroyRenderResources() {
	// Write here code to be called when the video mode is changed or the application is restarted (i.e. video_restart is called). It is used to reinitialize the graphics context.
	
	return 1;
}

int AppWorldLogic::save(const StreamPtr &stream) {
	// Write here code to be called when the world is saving its state (i.e. state_save is called): save custom user data to a file.
	
	UNIGINE_UNUSED(stream);
	return 1;
}

int AppWorldLogic::restore(const StreamPtr &stream) {
	// Write here code to be called when the world is restoring its state (i.e. state_restore is called): restore custom user data to a file here.
	
	UNIGINE_UNUSED(stream);
	return 1;
}


PROCEED TO THE NEXT SECTION >>

Last update: 12.03.2020