15. Implementing Game Logic and Using Properties
<< RETURN TO THE PREVIOUS SECTION
As you already know properties are used as a "material" for applicaton logic. In order to use custom properties you should:
- Make a manual property file an xml-file which defines your property and all necessary parameters.
<?xml version="1.0" encoding="utf-8"?> <property version="2.7.3.0" name="my_node_base" parent="node_base" manual="1"> <parameter name="my_param1">1</parameter> <parameter name="my_param2" type="string" my_state1="1">sometext</parameter> </property>
- Manage properties (states, parameter values, etc.) using the Property class and assign them to objects.
// getting a pointer to the property manager properties = Properties::get(); // inheriting new properties properties->findManualProperty("my_node_base")->inherit("new_property_1"); properties->findManualProperty("my_node_base")->inherit("new_property_2"); // getting pointers to the property named "new_property_1" PropertyPtr new_prop1 = properties->findManualProperty("new_property_1"); //setting the values of property parameters new_prop1->getParameterPtr("my_param1")->setValue(0); new_prop1->getParameterPtr("my_param2")->setValue("text 1"); // adding the new_property_1 to a node (ObjectMeshDynamicPtr) object1->addProperty("new_property_1"); //changing the value of my_parameter of the property assigned to the node object1->getProperty(0)->getParameterPtr("my_param1")->setValue(1);
Additional information:
- For more information on managing property hierarchy via API, see the Properties class article.
- For more information on managing properties via API, see the Property class article.
- For more information on property file format, see the Property File Format article.
- For more information on using properties for accessing your assets, see the Accessing Nodes and Files via Properties article.
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.
<?xml version="1.0" encoding="utf-8"?>
<property version="2.7.3.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), declare our clearProperties method to perform properties cleanup.
// AppWorldLogic.h
/* .. */
class AppWorldLogic : public Unigine::WorldLogic {
public:
/* .. */
private:
Unigine::Properties *properties;
/* .. */
Unigine::ObjectPtr old_selection; // pointer to previously selected object
/* .. */
int clearProperties();
/* .. */
};
In the AppWorldLogic.cpp file let us:
- add a code getting a pointer to the Property Manager to the AppWorldLogic::init() method.
- implement clearProperties method and insert it into the AppWorldLogic::shutdown() method.
- 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.
// 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);
// inheriting a new property from "my_node_base"
String new_property_name = String::format("%s_property", mesh_name);
properties->findManualProperty("my_node_base")->inherit(new_property_name.get());
// assigning the new property to the node and setting values of its parameters
omd->addProperty(new_property_name.get());
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);
// passing node ownership to the editor as a runtime node
omd->release();
editor->addNode(omd->getNode(), 1);
// 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 new selected object is not NULL and it has a property with parameter "selected" assigned
if (new_selected_object){/// TODO: check if param exists
if (new_selected_object->getProperty(0)->getParameterPtr("selected")){
// checking if we already have a previously selected object and setting its "selected" parameter of the property to 0
if (old_selected_object){
old_selected_object->getProperty(0)->getParameterPtr("selected")->setValue(0);
}
// setting the "selected" parameter of the property to 1 for the new selected object
new_selected_object->getProperty(0)->getParameterPtr("selected")->setValue(1);
// remembering the object as selected
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 = ObjectMeshDynamic::cast(editor->getNodeByName(node_name));
if (object)
{
// checking if the node to be removed was previously selected
if (old_selection)
{
if (object->getNode() == old_selection->getNode())
{
// 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 using upcasting
editor->removeNode(object->getNode());
return 1;
}
return 0;
}
/* .. */
/// method performing properties cleanup
int AppWorldLogic::clearProperties()
{
// removing our "my_node_base" base proprety with all children
PropertyPtr my_node_base = properties->findManualProperty("my_node_base");
while (my_node_base->getNumChildren())
properties->removeProperty(my_node_base->getChild(0)->getGUID());
return 1;
}
/* .. */
/// method updating the initial set of scene objects
int AppWorldLogic::updateObjects(float ifps)
{
ObjectMeshDynamicPtr object;
for (auto it = Objects.begin(); it != Objects.end(); it++)
{
object = it.get();
// getting the first property assigned to the object
PropertyPtr p = object->getProperty(0);
// checking if such property exists and has a "selected" parameter
if (p)
{
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->getNode(), ifps);
}
}
return 1;
}
/* .. */
int AppWorldLogic::init()
{
/* .. */
// getting a pointer to the Property Manager
properties = Properties::get();
/* .. */
}
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
#ifndef __APP_WORLD_LOGIC_H__
#define __APP_WORLD_LOGIC_H__
#include <UnigineLogic.h>
#include <UnigineStreams.h>
#include <UnigineObjects.h>
#include <UnigineEditor.h>
#include <UnigineGame.h>
#include <UnigineLights.h>
#include <UnigineMaterials.h>
#include <UnigineApp.h>
#include <UnigineConsole.h>
// 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 Unigine::WorldLogic {
public:
AppWorldLogic();
virtual ~AppWorldLogic();
virtual int init();
virtual int update();
virtual int render();
virtual int flush();
virtual int shutdown();
virtual int destroy();
virtual int save(const Unigine::StreamPtr &stream);
virtual int restore(const Unigine::StreamPtr &stream);
private:
Unigine::Editor *editor;
Unigine::App *app;
Unigine::Materials *materials;
Unigine::Properties *properties;
Unigine::PlayerSpectatorPtr player;
// pointers to light sources
Unigine::LightWorldPtr thesun;
Unigine::LightOmniPtr light_omni;
Unigine::LightProjPtr projector;
// auxiliary functions
int addMeshToScene(const char *file_name, const char *mesh_name, const char *material_name, Unigine::Math::Vec3 position);
int removeMeshFromScene(const char *node_name);
int transformNode(Unigine::NodePtr node, float ifps);
// initialization functions
int initObjects();
int initPlayer();
int initLights();
int initMaterials();
// update functions
int updateLights(float ifps);
int updateObjects(float ifps);
// shutdown functions
int clearMaterials();
int clearProperties();
int removeObjects();
// scene objects vector
Unigine::Vector <Unigine::ObjectMeshDynamicPtr> Objects;
Unigine::ObjectPtr old_selection; // pointer to previously selected object
Unigine::Math::vec3 current_objects_scale = Unigine::Math::vec3(1.0f); // current scaling vector for objects
Unigine::Math::Vec3 forward_direction = Unigine::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
#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.
using namespace Unigine;
//-----------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------- 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);
// inheriting a new property from "my_node_base"
String new_property_name = String::format("%s_property", mesh_name);
properties->findManualProperty("my_node_base")->inherit(new_property_name.get());
// assigning the new property to the node and setting values of its parameters
omd->addProperty(new_property_name.get());
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);
// passing node ownership to the editor as a runtime node
omd->release();
editor->addNode(omd->getNode(), 1);
// 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 = ObjectMeshDynamic::cast(editor->getNodeByName(node_name));
if (object)
{
if (old_selection)
{
// checking if the node to be removed was previously selected
if (object->getNode() == old_selection->getNode())
{
// 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 using upcasting
editor->removeNode(object->getNode());
return 1;
}
return 0;
}
//-----------------------------------------------------------------------------------------------------------------------------
/// method performing node transformations
int AppWorldLogic::transformNode(NodePtr node, float ifps)
{
// 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 * ifps);
// 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 *ifps);
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::get()->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 new selected object is not NULL and it has a property with parameter "selected" assigned
if (new_selected_object){/// TODO: check if param exists
if (new_selected_object->getProperty(0)->getParameterPtr("selected")){
// checking if we already have a previously selected object and setting its "selected" parameter of the property to 0
if (old_selected_object){
old_selected_object->getProperty(0)->getParameterPtr("selected")->setValue(0);
}
// setting the "selected" parameter of the property to 1 for the new selected object
new_selected_object->getProperty(0)->getParameterPtr("selected")->setValue(1);
// remembering the object as selected
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).get(), String::format("my_mesh_base%d", index).get(), 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));
// releasing the player and setting it as a default one via the Game singleton instance
player->release();
Game::get()->setPlayer(player->getPlayer());
//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);
// passing node ownership to the editor
light_omni->release();
editor->addNode(light_omni->getNode());
// 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));
// passing node ownership to the editor
thesun->release();
editor->addNode(thesun->getNode());
// 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);
// passing node ownership to the editor
projector->release();
editor->addNode(projector->getNode());
// 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()
{
// getting a pointer to materials interface
materials = Materials::get();
// 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->setParameter(Material::PARAMETER_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->setParameter(Material::PARAMETER_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->setParameter(Material::PARAMETER_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->setParameter(Material::PARAMETER_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(float ifps)
{
// updating the Sun rotation angle
sun_angle += SUN_ROTATION_RATE * ifps;
if (sun_angle > 360.0f) sun_angle = 0.0f;
// changing the Sun position using the new angle
LightWorld::cast(editor->getNodeByName("Sun"))->setWorldRotation(Math::quat(Math::vec3(0.0f, 1.0f, 0.0f), 180.0f - sun_angle));
return 1;
}
//-----------------------------------------------------------------------------------------------------------------------------
/// 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();
// getting the first property assigned to the object
PropertyPtr p = object->getProperty(0);
// checking if such property exists and has a "selected" parameter
if (p)
{
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->getNode(), ifps);
}
}
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 properties
int AppWorldLogic::clearProperties()
{
// removing our "my_node_base" base proprety with all children
PropertyPtr my_node_base = properties->findManualProperty("my_node_base");
while (my_node_base->getNumChildren())
properties->removeProperty(my_node_base->getChild(0)->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.
// getting a pointer to the application
app = App::get();
// initializing pseudo-random number generator
Game::get()->setSeed(time(NULL));
// getting a pointer to the Property Manager
properties = Properties::get();
// getting a pointer to the Editor
editor = Editor::get();
// 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.
// getting an inverse FPS value (the time in seconds it took to complete the last frame)
float ifps = Game::get()->getIFps();
// 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::get()->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 -= ifps;
// if right mouse button is clicked
if (app->clearMouseButtonState(App::BUTTON_RIGHT))
{
// get and select object under the mouse cursor
selectObject(getObjectUnderMouseCursor(Game::get()->getPlayer(), app->getMouseX(), app->getMouseY(), 100.0f), old_selection);
}
// closing the application if a 'Q' key is pressed, ignoring the key if the console is opened
if (app->getKeyState('q') && !Console::get()->getActivity())
{
app->exit();
}
// updating objects
updateObjects(ifps);
// updating lights
updateLights(ifps);
return 1;
}
int AppWorldLogic::render() {
// 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::flush() {
// Write here code to be called before updating each physics frame: control physics in your application and put non-rendering calculations.
// The engine calls flush() 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.clear();
// clearing light sources
thesun.clear();
light_omni.clear();
projector.clear();
// clearing all created materials
clearMaterials();
// clearing all created properties
clearProperties();
// resetting old_selection pointer
old_selection.clear();
return 1;
}
int AppWorldLogic::destroy() {
// 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 Unigine::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 Unigine::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;
}