This page has been translated automatically.
视频教程
界面
要领
高级
实用建议
专业(SIM)
UnigineEditor
界面概述
资产工作流程
设置和首选项
项目开发
调整节点参数
Setting Up Materials
设置属性
照明
Landscape Tool
Sandworm
使用编辑器工具执行特定任务
如何擴展編輯器功能
嵌入式节点类型
Nodes
Objects
Effects
Decals
光源
Geodetics
World Nodes
Sound Objects
Pathfinding Objects
Players
编程
基本原理
搭建开发环境
使用范例
C++
C#
UnigineScript
UUSL (Unified UNIGINE Shader Language)
Plugins
File Formats
Materials and Shaders
Rebuilding the Engine Tools
GUI
双精度坐标
应用程序接口
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
创建内容
内容优化
Materials
Material Nodes Library
Miscellaneous
Input
Math
Matrix
Textures
Art Samples
Tutorials
注意! 这个版本的文档是过时的,因为它描述了一个较老的SDK版本!请切换到最新SDK版本的文档。
注意! 这个版本的文档描述了一个不再受支持的旧SDK版本!请升级到最新的SDK版本。

Adding Scripts to the Project

Warning
The scope of applications for UnigineScript is limited to implementing materials-related logic (material expressions, scriptable materials, brush materials). Do not use UnigineScript as a language for application logic, please consider C#/C++ instead, as these APIs are the preferred ones. Availability of new Engine features in UnigineScript (beyond its scope of applications) is not guaranteed, as the current level of support assumes only fixing critical issues.

Starting coding your project is simple with the use of UnigineScript language (no compilation is required).

For this tutorial we are going to get a primitive object (a box) from a script and add game logic to rotate it.

Step 1. Add The Primitive Object To The World#

  1. Run the project with the loaded UnigineEditor via the SDK Browser.

  2. In the Menu Bar, choose Create -> Primitive -> Box to create a box object.

  3. In Create Box window that opens, specify the size of the box and click OK.

  4. Place the box somewhere in the world.

  5. By default, the added node is named Cuboid. Right-click it in the World Hierarchy window and rename it box.

  6. In the Node tab of the Parameters window, change the position of the box to 0.0, 0.0, 1.0.

  7. In the Menu Bar, click File -> Save World or press CTRL + S to save the world.

Step 2. Add Script Logic#

There are two methods to add a script to the object:

Method 1: By Editing the .usc World Script File#

To add logic that will rotate the box, you should modify the <your_project_name>.usc world script file in a plain text editor.

Notice
The .usc files do not require compilation, as they are interpreted by the Engine itself during its initialization.

  1. Open the project folder via the SDK Browser.

    Notice
    If there is no Open Folder button, choose Other Actions -> Open Folder.
  2. Open <your_project_name>.usc script file located in the data directory by using plain text editor.

    Source code (UnigineScript)
    #include <core/unigine.h>
    // This file is in UnigineScript language.
    // World script, it takes effect only when the world is loaded.
    
    int init() {
    	// Write here code to be called on world initialization: initialize resources for your world scene during the world start.
    	
    	Player player = new PlayerSpectator();
    	player.setPosition(Vec3(0.0f,-3.401f,1.5f));
    	player.setDirection(Vec3(0.0f,1.0f,-0.4f));
    	engine.game.setPlayer(player);
    	return 1;
    }
    
    // start of the main loop
    int 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.
    	
    	return 1;
    }
    
    int 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 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 shutdown() {
    	// Write here code to be called on world shutdown: delete resources that were created during world script execution to avoid memory leaks.
    	
    	return 1;
    }

    The world script contains the following functions by default:

    • init() function is used to create objects and initialize all other necessary resources on the world load.
    • update() function is used to code project logic and executed every frame.
    • postUpdate() function is used for correction purposes: it implements logic that is executed after updating the node's state.
    • updatePhysics() function is used to code physics simulation logic
    • shutdown() function is used to code project logic and executed when the world is unloaded.

    The following part of the init() function code creates a new free-flying game camera that collides with objects (but does not push or interact with them). Read more about the Engine functions.

    Source code (UnigineScript)
    // create a new spectator player
    Player player = new PlayerSpectator();
    
    // place it in the specified point
    player.setPosition(Vec3(0.0f,-3.401f,1.5f));
    
    // turn it in the specified direction
    player.setDirection(Vec3(0.0f,1.0f,-0.4f));
    
    // set the player as default one
    engine.game.setPlayer(player);
    Notice
    Comments were added to explain the meaning of each line of the code.
  3. Add a variable to handle the required box node before the init() function.
    Warning
    We do NOT recommend you to create global variables for the real project.
    Source code (UnigineScript)
    Node box; // add a box node
    
    int init() {
    	/* ... */
    	}
  4. Put this code into the init() function to get the box node.
    Source code (UnigineScript)
    Node box; // add a box node	
    
    int init() {
    	/* ... */
    
    	// get the node by the specified name
    	box = engine.world.getNodeByName("box");
    
    	return 1;
    }
    Notice
    Though nodes can be handled by any of the scripts (world, system or editor one) and UnigineEditor (that loads and stores all the nodes from the .world file), they should be owned only by one of them. Otherwise, such nodes can cause Engine crash or memory leak problems.
    See Memory Management article for details.
  5. Set the node transformation in the update() function. Note that it is necessary to scale the rotation angle each frame with the frame duration (because it's different for each individual frame) to get constant angular velocity.
    Source code (UnigineScript)
    /* ... */
    
    int update() {
    
    	// check whether the node exists
    	if(box != NULL) {
    
    		// get the frame duration
    		float ifps = engine.game.getIFps();
    
    		// set the angle of rotation
    		float angle = ifps * 90.0f;
    
    		// get the current transformation of the node and apply rotation
    		mat4 transform = box.getTransform() * rotateZ(angle);
    
    		// set new transformation to the node
    		box.setTransform(transform);
    	}
    	return 1;
    }
    Thus, the resulting script is:
    Source code (UnigineScript)
    #include <core/unigine.h>
    // This file is in UnigineScript language.
    // World script, it takes effect only when the world is loaded.
    
    Node box; // add a box node	
    
    int init() {
    	// Write here code to be called on world initialization: initialize resources for your world scene during the world start.
    
    	Player player = new PlayerSpectator();
    	player.setPosition(Vec3(0.0f,-3.401f,1.5f));
    	player.setDirection(Vec3(0.0f,1.0f,-0.4f));
    	engine.game.setPlayer(player);
    
    	// get the node by the specified name
    	box = engine.world.getNodeByName("box");
    
    	return 1;
    }
    
    // start of the main loop
    int 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.
    	// check whether the node exists
    	if(box != NULL) {
    
    		// get the frame duration
    		float ifps = engine.game.getIFps();
    
    		// set the angle of rotation
    		float angle = ifps * 90.0f;
    
    		// get the current transformation of the node and apply rotation
    		mat4 transform = box.getTransform() * rotateZ(angle);
    
    		// set new transformation to the node
    		box.setTransform(transform);
    	}
    	return 1;
    }
    
    int 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 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 shutdown() {
    	// Write here code to be called on world shutdown: delete resources that were created during world script execution to avoid memory leaks.
    
    	return 1;
    }
  6. Save all the changes in the <your_project_name>.usc world script file.
  7. In the Menu Bar of UnigineEditor, choose File -> Reload World or run the world_reload console command.

  8. Check the result.

Method 2: By Using WorldExpression Objects#

You can add the script to the box by using the WorldExpression object.

  1. In the Menu Bar, choose Create -> Logic -> Expression to create the WorldExpression object.

  2. Place the World Expression box somewhere in the world. The added World Expression node will appear in the World Hierarchy.

  3. Choose the added WorldExpression node in the World Hierarchy window and go to the Node tab of the Parameters window. Here change the position to 1.0, -1.0, 0.5.

    Now you have the primitive box and the World Expression object on a plane.

  4. Specify the Update Distance Limit for the WorldExpression node - it is the maximum distance from the camera up to which the expression shall be executed. Let's set it to 10 units.

  5. Choose the WorldExpression node in the World Hierarchy and go to the World Expression section of the Parameters window.
  6. Put the following code into the Source field.
    Source code (UnigineScript)
    {
    	// get the WorldExpression node via its internal function
    	Node worldExpression = getNode();
    	
    	// get the frame duration
    	float ifps = engine.game.getIFps();
    
    	// set the angle of rotation
    	float angle = ifps * 90.0f;
    
    	// get the current transformation of the node and apply rotation
    	mat4 transform = worldExpression.getTransform() * rotateZ(angle);
    
    	// set new transformation to the node
    	worldExpression.setTransform(transform);
    }
    Warning
    Curly braces are mandatory!

    Other ways of attaching scripts to the World Expression object you can read here.

  7. Make the box node a child of the WorldExpression node by dragging it in the World Hierarchy.

    Now the box node is the child of the WorldExpression node. It means that the box object inherits all expression transformations of the World Expression object.
    Notice
    All the child nodes of the WorldExpression node inherit expression transformations.
    Our expression shall be executed (i.e. the transformation shall be updated according to the script) as long as the distance from the camera to the WorldExpression node does not exceed the specified Update Distance Limit)
  8. Check the result.

If you reset the position of the box node to its parent position, you will get the same result as in the Method 1.

Last update: 2022-03-10
Build: ()