This page has been translated automatically.
视频教程
界面
要领
高级
实用建议
专业(SIM)
UnigineEditor
界面概述
资源工作流程
版本控制
设置和首选项
项目开发
调整节点参数
Setting Up Materials
设置属性
照明
Sandworm
使用编辑器工具执行特定任务
如何擴展編輯器功能
嵌入式节点类型
Nodes
Objects
Effects
Decals
光源
Geodetics
World Nodes
Sound Objects
Pathfinding Objects
Players
编程
基本原理
搭建开发环境
使用范例
C++
C#
UnigineScript
UUSL (Unified UNIGINE Shader Language)
Plugins
File Formats
材质和着色器
Rebuilding the Engine Tools
GUI
双精度坐标
应用程序接口
Animations-Related Classes
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
VR-Related Classes
创建内容
内容优化
材质
Material Nodes Library
Miscellaneous
Input
Math
Matrix
Textures
Art Samples
Tutorials

创建UI结束

当游戏结束时,结束部件应该是可见的。用户可以通过相应的按钮重新启动游戏或退出应用程序。

步骤1。制作World Widget Controller#

widget控制器节点将为不同类型的UI元素指定处理程序,并在游戏结束时显示UI。

  1. 创建一个新的 c++组件并将其命名为UiElement。这个组件处理选择和按钮函数调用。编写以下代码并将代码保存在IDE中。

    UiElement.h (C++)
    #pragma once
    #include <UnigineComponentSystem.h>
    
    #include <UnigineGame.h>
    
    class UiElement : public Unigine::ComponentBase
    {
    public:
    	// declare constructor and destructor for our class and define a property name. 
    	COMPONENT_DEFINE(UiElement, ComponentBase)
    	// declare methods to be called at the corresponding stages of the execution sequence
    	COMPONENT_INIT(init);
    	COMPONENT_UPDATE(update);
    
    	enum Element { Restart, Exit, None };
    
    	// default type of a UI element
    	Element uiType = Element::None;
    
    	// scale on cursor hover
    	float selectScale = 1;
    
    	// emission color on cursor hover
    	Unigine::Math::vec4 selectEmission = Unigine::Math::vec4_black;
    
    	// default mask for the mouse intersection detection
    	int uiMask = 1;
    
    	static void setOnClickCallback(Unigine::CallbackBase *callback) { onClickCallback = callback; }
    
    protected:
    	void init();
    	void update();
    
    	void onWindowResize();
    	void onDisable();
    	void onLeave();
    	void onEnter();
    
    private:
    	static Unigine::CallbackBase *onClickCallback;
    
    	// ID of the UI element
    	int Id; 
    
    	// ID counter for initialization  
    	static int idCount;
    
    	// counter of selected objects
    	int selectedObjects = 0;
    
    	Unigine::WorldIntersectionPtr intersection;
    
    	bool isSelect = false;
    
    	Unigine::ObjectPtr uiObject = nullptr;
    
    	Unigine::Math::vec3 sourceScale = Unigine::Math::vec3_one;
    	Unigine::Math::vec4 sourceEmission = Unigine::Math::vec4_one;
    };
    UiElement.cpp (C++)
    #include "UiElement.h"
    
    using namespace Unigine;
    using namespace Math;
    
    REGISTER_COMPONENT(UiElement);
    
    CallbackBase *UiElement::onClickCallback = nullptr;
    
    int UiElement::idCount = 0;
    
    void UiElement::init()
    {
    	// set ID
    	Id = idCount;
    	++idCount;
    
    	selectedObjects = 0;
    
    	// get the UI element
    	uiObject = checked_ptr_cast<Object>(node);
    
    	// remember the source scale and emission color
    	sourceScale = node->getScale();
    	if (uiObject)
    		sourceEmission = uiObject->getMaterialParameterFloat4("emission_color", 0);
    
    	intersection = WorldIntersection::create();
    }
    
    void UiElement::update()
    {
    	// taking into account main window position to obtain correct direction
    	Math::ivec2 mouse = Input::getMousePosition();
    
    	// get points for intersection
    	vec3 dir = Game::getPlayer()->getDirectionFromMainWindow(mouse.x, mouse.y);
    	Vec3 p0 = Game::getPlayer()->getWorldPosition();
    	Vec3 p1 = p0 + Vec3(dir * 25.0f);
    
    	// find the intersection
    	ObjectPtr obj = World::getIntersection(p1, p0, uiMask, intersection);
    	if (obj)
    	{
    		// try to get the UI element component and select/deselect it
    		UiElement *uiElement = ComponentSystem::get()->getComponent<UiElement>(obj);
    		if (uiElement && uiElement->Id == Id)
    		{
    			if (!isSelect)
    			{
    				UiElement::onEnter();
    				isSelect = true;
    				++selectedObjects;
    			}
    		}
    		else if (isSelect)
    		{
    			UiElement::onLeave();
    			isSelect = false;
    			--selectedObjects;
    		}
    	}
    	else
    	{
    		if (isSelect)
    		{
    			UiElement::onLeave();
    			isSelect = false;
    			--selectedObjects;
    		}
    	}
    
    	// run the mouse click callback
    	if (isSelect && Input::isMouseButtonDown(Input::MOUSE_BUTTON::MOUSE_BUTTON_LEFT) && onClickCallback)
    		onClickCallback->run(uiType);
    }
    
    void UiElement::onDisable()
    {
    	// deselect an object
    	if (isSelect)
    	{
    		--selectedObjects;
    		if (selectedObjects < 0)
    			selectedObjects = 0;
    
    		isSelect = false;
    		UiElement::onLeave();
    	}
    }
    
    void UiElement::onEnter()
    {
    	// set the visual effect on selection
    	node->setScale(sourceScale * selectScale);
    	uiObject->setMaterialParameterFloat4("emission_color", selectEmission, 0);
    }
    
    void UiElement::onLeave()
    {
    	// remove the visual effect when the UI element is not selected anymore
    	node->setScale(sourceScale);
    	uiObject->setMaterialParameterFloat4("emission_color", sourceEmission, 0);
    }
  2. 创建一个新的 c++组件并将其命名为EndWidget。复制下面的代码并将其粘贴到项目中的相应文件中,并将其保存到IDE中。

    EndWidget.h (C++)
    #pragma once
    #include <UnigineComponentSystem.h>
    
    #include "LevelManager.h"
    #include "UiElement.h"
    #include <UnigineConsole.h>
    
    class EndWidget : public Unigine::ComponentBase
    {
    public:
    	// declare constructor and destructor for our class and define a property name. 
    	COMPONENT_DEFINE(EndWidget, ComponentBase)
    	// declare methods to be called at the corresponding stages of the execution sequence
    	COMPONENT_INIT(init);
    	
    	// object with the end game message
    	PROP_PARAM(Node, endGameWidget);
    
    protected:
    	void init();
    
    	void endGameEventHandler();
    	void onClickHandler(UiElement::Element uiType);
    
    private:
    	LevelManager *levelManager;
    };
    EndWidget.cpp (C++)
    #include "EndWidget.h"
    
    using namespace Unigine;
    
    REGISTER_COMPONENT(EndWidget);
    
    void EndWidget::init()
    {
    	levelManager = ComponentSystem::get()->getComponent<LevelManager>(World::getNodeByName("level_manager"));
    
    	if (levelManager)
    		levelManager->setEndGameCallback(MakeCallback(this, &EndWidget::endGameEventHandler));
    
    	// set the mouse click handler for UI elements (Restart/Exit)
    	UiElement::setOnClickCallback(MakeCallback(this, &EndWidget::onClickHandler));
    
    	if (endGameWidget)
    	{
    		// hide the end UI
    		endGameWidget->setEnabled(false);
    	}
    }
    
    void EndWidget::endGameEventHandler()
    {
    	// set gui and input
    	Input::setMouseHandle(Input::MOUSE_HANDLE::MOUSE_HANDLE_USER);
    
    	// show the end UI
    	endGameWidget->setEnabled(true);
    }
    
    void EndWidget::onClickHandler(UiElement::Element uiType)
    {
    	// restart the level by reloading the world
    	if (uiType == UiElement::Element::Restart)
    	{
    		Unigine::Console::run("world_reload");
    	}
    
    	// exit the game
    	if (uiType == UiElement::Element::Exit)
    		Engine::get()->quit();
    }
  3. 在IDE中构建并运行解决方案以重新生成属性。
  4. 切换到UnigineEditor并创建一个新的Dummy Node"widgets_controller"调用它。
  5. EndWidget属性分配给widgets_controller节点。

步骤2。建立世界小部件#

结束小部件提供了按钮功能和有关当前游戏结果的附加信息。要正确显示结束小部件,请将其放置在相机前面。

  1. 从0 programming_quick_start\ui\ui_plane.node_phl拖到世界。
  2. 父属性为PlayerDummy相机。将ui_plane节点的位置设置为以下值。

  3. 拯救世界的变化,去File->Save World或者按Ctrl + S热键。
  4. 接下来,我们向LevelManager类添加一个获胜条件检查,结束小部件text,和一个回调运行。让我们也将UiElement组件分配给LevelManager类中的结束小部件的按钮。

    设置Ui Type Restart,检查 6 0 强一点选择_phl(匹配按钮的十字路口面具)正确流程选择十字路口和设置选择规模1.05为了使光标悬停按钮更大。同时,设置选择发射#505050使按钮改变其颜色。

    为此,在IDE中打开LevelManager组件,并用以下代码替换它。不要忘记保存代码。

    LevelManager.h (C++)
    #pragma once
    #include <UnigineComponentSystem.h>
    
    #include <UnigineWidgets.h>
    #include <UnigineGame.h>
    #include <UnigineString.h>
    //========================== NEW - BEGIN ===============================
    #include "UiElement.h"
    //=========================== NEW - END ================================
    
    class LevelManager : public Unigine::ComponentBase
    {
    public:
    	// declare constructor and destructor for our class and define a property name. 
    	COMPONENT_DEFINE(LevelManager, ComponentBase)
    	// declare methods to be called at the corresponding stages of the execution sequence
    	COMPONENT_INIT(init, 2); // 2nd initialization order
    	COMPONENT_UPDATE(update);
    	COMPONENT_SHUTDOWN(shutdown);
    	// level timer
    	PROP_PARAM(Float, timer, 100.0f);
    //========================== NEW - BEGIN ===============================
    	PROP_PARAM(Node, restartButton);
    	PROP_PARAM(Node, exitButton);
    //=========================== NEW - END ================================
    	void decPhysicalObjectsNum();
    	void setEndGameCallback(Unigine::CallbackBase *callback) { endGameEvent = callback; }
    
    protected:
    	void init();
    	void update();
    	void shutdown();
    
    	void initGUI();
    
    private:
    	Unigine::CallbackBase *endGameEvent = nullptr;
    
    	bool isCounting = true;
    
    	int physicalObjectsNum;
    
    	Unigine::WidgetLabelPtr widget_timer, widget_goal;
    
    	Unigine::ObjectTextPtr endText;
    };
    LevelManager.cpp (C++)
    #include "LevelManager.h"
    
    using namespace Unigine;
    using namespace Math;
    
    REGISTER_COMPONENT(LevelManager);
    
    void LevelManager::init()
    {
    	LevelManager::initGUI();
    
    	// find the object text node of the widget
    	endText = checked_ptr_cast<ObjectText>(Game::getPlayer()->findNode("header_text", 1));
    
    	// count dynamic objects in the level
    	physicalObjectsNum = node->getNumChildren();
    //========================== NEW - BEGIN ===============================
    	// set up the restart button as a UI element
    	if (restartButton)
    	{
    		UiElement* restart_component = ComponentSystem::get()->addComponent<UiElement>(restartButton);
    		restart_component->uiType = UiElement::Element::Restart;
    		restart_component->uiMask = 0x00000040; // 6th bit is set
    		restart_component->selectScale = 1.05f;
    	}
    
    	// set up the exit button as a UI element
    	if (exitButton)
    	{
    		UiElement* exit_component = ComponentSystem::get()->addComponent<UiElement>(exitButton);
    		exit_component->uiType = UiElement::Element::Exit;
    		exit_component->uiMask = 0x00000040; // 6th bit is set
    	}
    //=========================== NEW - END ================================
    }
    
    void LevelManager::initGUI()
    {
    	// get a GUI pointer
    	GuiPtr gui = Gui::getCurrent();
    
    	// create a label widget and set up its parameters
    	widget_timer = WidgetLabel::create(gui, "Time Left:");
    	widget_timer->setPosition(10, 10);
    	widget_timer->setFontColor(vec4_red);
    
    	widget_goal = WidgetLabel::create(gui, "Objects Left: ");
    	widget_goal->setPosition(10, 30);
    	widget_goal->setFontColor(vec4_blue);
    
    	// add widgets to the GUI
    	gui->addChild(widget_timer, Gui::ALIGN_OVERLAP);
    	gui->addChild(widget_goal, Gui::ALIGN_OVERLAP);
    }
    
    void LevelManager::update()
    {
    	// decrease the timer
    	if (isCounting)
    	{
    		timer = timer - Game::getIFps();
    		if (timer <= 0)
    		{
    			//set end game text
    			if (endText) endText->setText("Game Over");
    			if (endGameEvent) endGameEvent->run();
    			isCounting = false;
    		}
    	}
    
    	// show the current time and objects left to clear
    	if (isCounting)
    	{
    		widget_timer->setText(String::format("Time Left: %.2f s", timer.get()));
    		widget_goal->setText(String::format("Objects Left: %d", physicalObjectsNum));
    	}
    	//hide the widgets on endgame
    	else
    	{
    		widget_timer->setEnabled(false);
    		widget_goal->setEnabled(false);
    	}
    	
    	//win
    	if (physicalObjectsNum <= 0)
    	{
    		if (endText) endText->setText("Success!");
    		if (endGameEvent) endGameEvent->run();
    		isCounting = false;
    	}
    }
    
    void LevelManager::shutdown()
    {
    	widget_timer.deleteLater();
    	widget_goal.deleteLater();
    }
    
    void LevelManager::decPhysicalObjectsNum()
    {
    	physicalObjectsNum--;
    }
  5. 构建和运行的解决方案为LevelManager组件再生属性文件。
  6. 切换到UnigineEditor,在World Nodes窗口中选择ui_plane节点,并单击鼠标右键选择Unpack To Node Content,以将按钮节点链接到LevelManager组件。
  7. 然后拖动按钮(restart_buttonexit_button)的相应字段LevelManager财产。

  8. ui_plane节点拖到1下_igt场EndWidget widgets_controller节点的组件。

  9. 拯救世界的变化,去File->Save World或者按Ctrl + S热键。
  10. 切换到你的IDE,那么构建和运行游戏在IDE的UI。
最新更新: 2023-12-20
Build: ()