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结束

The end widget should be visible when the game is over. The user will be able to restart the game or exit the application via the corresponding buttons.当游戏结束时,结束部件应该是可见的。用户可以通过相应的按钮重新启动游戏或退出应用程序。

Step 1. Make the World Widget Controller
步骤1。制作World Widget Controller#

The widget controller node will specify the handlers for different types of UI elements and show the UI at the end of the game.widget控制器节点将为不同类型的UI元素指定处理程序,并在游戏结束时显示UI。

  1. Create a new C# component and call it UiElement. This component handles the selection and button functions calls. Open the UiElement component in your IDE and copy the code below. Don't forget to save your code.创建一个新的 c#组件,命名为UiElement。这个组件处理选择和按钮函数调用。在IDE中打开UiElement组件并复制下面的代码。不要忘记保存代码。

    UiElement.csUiElement.cs

    UiElement.cs
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using Unigine;
    
    #if UNIGINE_DOUBLE
    using Vec3 = Unigine.dvec3;
    #else
    	using Vec3 = Unigine.vec3;
    #endif 
    [Component(PropertyGuid = "AUTOGENERATED_GUID")] // <-- this line is generated automatically for a new component
    public class UiElement : Component
    {
    	[ShowInEditor][Parameter(Tooltip = "Type of UI element")]
    	private Element uiType = Element.None;
    
    	[ShowInEditor][ParameterMask(Tooltip = "Mask for detecting mouse intersection")]
    	private int uiMask = 1;
     
    	[ShowInEditor][Parameter(Tooltip = "Scale on hover")]
    	private float selectScale = 1;
    
    	[ShowInEditor][ParameterColor(Tooltip = "Emission color on hover")]
    	private vec4 selectEmission = vec4.ONE;
    
    	static public event Action<Element> onClick;
    
    	public enum Element { Restart, Exit, None }
    
    	public uint Id { get; private set; }
    
    	static public bool AnyIsSelect
    	{
    		get
    		{
    			if (selectedObjects == 0)
    				return false;
    
    			return true;
    		}
    	}
    
    	// ID of UI element
    	static private uint idCount = 0;
    
    	// count of selected objects
    	static private int selectedObjects = 0;
    
    	private WorldIntersection intersection = null;
    	private bool isSelect = false;
    
    	Unigine.Object uiObject = null;
    
    	private vec3 sourceScale = vec3.ONE;
    	private vec4 sourceEmission = vec4.ONE;
    
    	void Init()
    	{
    		// set ID
    		Id = idCount;
    		++idCount;
    
    		selectedObjects = 0;
    
    		// get the UI element
    		uiObject = node as Unigine.Object;
    
    		// remember the source scale and emission color
    		sourceScale = node.Scale;
    		sourceEmission = uiObject.GetMaterialParameterFloat4("emission_color", 0);
    
    		intersection = new WorldIntersection();
    	}
    
    	protected override void OnDisable()
    	{
    		// deselect an object
    		if (isSelect)
    		{
    			--selectedObjects;
    			if (selectedObjects < 0)
    				selectedObjects = 0;
    
    			isSelect = false;
    			OnLeave();
    		}
    	}
    
    	void Update()
    	{
    		// getting direction from the current mouse position
    		ivec2 mouse = Input.MousePosition;
    		vec3 dir = Game.Player.GetDirectionFromMainWindow(mouse.x, mouse.y);
    		
    		// get points for intersection
    		Vec3 p0 = Game.Player.WorldPosition;
    		Vec3 p1 = p0 + dir * 25.0f;
    
    		// find the intersection
    		Unigine.Object obj = World.GetIntersection(p1, p0, uiMask, intersection);
    		if (obj != null)
    		{
    			// try to get the UI element component and select/deselect it
    			UiElement uiElement = ComponentSystem.GetComponent<UiElement>(obj);
    			if (uiElement != null && uiElement.Id == Id)
    			{
    				if (!isSelect)
    				{
    					OnEnter();
    					isSelect = true;
    					++selectedObjects;
    				}
    			}
    			else if (isSelect)
    			{
    				OnLeave();
    				isSelect = false;
    				--selectedObjects;
    			}
    		}
    		else
    		{
    			if (isSelect)
    			{
    				OnLeave();
    				isSelect = false;
    				--selectedObjects;
    			}
    		}
    
    		// invoke the mouse click event
    		if (isSelect && Input.IsMouseButtonDown(Input.MOUSE_BUTTON.LEFT))
    			OnClick();
    	}
    
    	private void OnEnter()
    	{
    		// set a visual effect on selection
    		node.Scale = sourceScale * selectScale;
    		uiObject.SetMaterialParameterFloat4("emission_color", selectEmission, 0);
    	}
    
    	private void OnLeave()
    	{
    		// remove a visual effect when the UI element is not selected anymore
    		node.Scale = sourceScale;
    		uiObject.SetMaterialParameterFloat4("emission_color", sourceEmission, 0);
    	}
    
    	private void OnClick()
    	{
    		onClick?.Invoke(uiType);
    	}
    }
  2. Next, add a win condition check, end widget text, and a delegate call to the LevelManager class. To do so, open the LevelManager component in an IDE and add the following code. Save your code in an IDE to ensure it's automatic compilation on switching back to UnigineEditor.接下来,向 LevelManager 添加一个获胜条件 check、结束小部件 text 和一个委托 call类。 为此,请在 IDE 中打开 LevelManager 组件并添加以下代码。 将您的代码保存在 IDE 中,以确保在切换回 UnigineEditor 时自动编译。

    LevelManager.cs
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using Unigine;
     
    [Component(PropertyGuid = "AUTOGENERATED_GUID")] // <-- this line is generated automatically for a new component
    public class LevelManager : Component
    {
    //========================== NEW - BEGIN ===============================
    	public event Action endGameEvent;
    
    	ObjectText endText;
    //=========================== NEW - END ================================
    	// level timer
    	public float timer = 100.0f; 
    
    	bool isCounting = true;
    
    	int physicalObjectsNum;
    	
    	WidgetLabel widget_timer, widget_goal;
    
    	void Init()
    	{
    		InitGUI();
    //========================== NEW - BEGIN ===============================
    		// find the object text node of the widget
    		endText = Game.Player.FindNode("header_text", 1) as ObjectText;
    //=========================== NEW - END ================================
    		// count physical objects in the level
    		physicalObjectsNum = node.NumChildren;
    	}
    
    	void InitGUI()
    	{
    		// getting a GUI pointer
    		Gui gui = Gui.GetCurrent();
    
    		// creating a label widget and setting up its parameters
    		widget_timer = new WidgetLabel(gui, "Time Left:");
    		widget_timer.SetPosition(10, 10);
    		widget_timer.FontColor = vec4.RED;
    
    		widget_goal = new WidgetLabel(gui, "Objects Left: ");
    		widget_goal.SetPosition(10, 30);
    		widget_goal.FontColor = vec4.BLUE; 
    
    		// add widgets to the GUI
    		gui.AddChild(widget_timer, Gui.ALIGN_OVERLAP);
    		gui.AddChild(widget_goal, Gui.ALIGN_OVERLAP);
    	}
    
    	void Update()
    	{
    		// decrease the timer
    		if (isCounting)
    		{
    			timer -= Game.IFps;
    			if (timer <= 0)
    			{
    				//end game
    //========================== NEW - BEGIN =============================
    				endText.Text = "Game Over";
    				endGameEvent?.Invoke();
    //========================== NEW - END ===============================
    				isCounting = false;
    			}
    		}
    
    		//win
    		if (physicalObjectsNum <= 0)
    		{
    //========================== NEW - BEGIN =============================
    			endText.Text = "Success!";
    			endGameEvent?.Invoke();
    //========================== NEW - END ===============================
    			isCounting = false;
    		}
    
    		// show the current time and objects left to clear
    		if (isCounting)
    		{
    			widget_timer.Text = "Time Left: " + timer.ToString("0.0") + " s";
    			widget_goal.Text = "Objects Left: " + physicalObjectsNum.ToString();
    		}
    		//hide the widgets on end game
    		else
    		{
    			widget_timer.Enabled = false;
    			widget_goal.Enabled = false;
    		}
    	}
    
    	void Shutdown()
    	{
    		widget_timer.DeleteLater();
    		widget_goal.DeleteLater();
    	}
    
    	public void DecPhysicalObjectsNum()
    	{
    		physicalObjectsNum--;
    	}
    }
  3. Create a new C# component and call it EndWidget. Open the component in your IDE and copy the code below. Save your code in an IDE to ensure it's automatic compilation on switching back to UnigineEditor.创建一个新的 c#组件,命名为EndWidget。在IDE中打开组件并复制下面的代码。将你的代码保存在IDE中,以确保它在切换回UnigineEditor时自动编译。

    EndWidget.cs
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using Unigine;
     
    [Component(PropertyGuid = "AUTOGENERATED_GUID")] // <-- this line is generated automatically for a new component
    public class EndWidget : Component
    {
    	// object with the end game message
    	public Node endGameWidget;
    
    	LevelManager levelManager;
    
    	void Init()
    	{
    		// set the end game event handler
    		levelManager = ComponentSystem.FindComponentInWorld<LevelManager>();
    		
    		if (levelManager != null)
    		{
    			levelManager.endGameEvent += EndGameEventHandler;
    		}
    
    		// set the mouse click handler for UI elements (Restart/Exit)
    		UiElement.onClick += OnClickHandler;
    
    		// hide the end UI
    		endGameWidget.Enabled = false;
    	}
    
    	void EndGameEventHandler()
    	{
    		// set gui and input
    		Input.MouseHandle = Input.MOUSE_HANDLE.USER;
    
    		// show the end UI
    		endGameWidget.Enabled = true;
    	}
    	
    	void 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.Quit();
    	}
    
    	void Shutdown()
    	{
    		// remove handlers
    		if (levelManager != null)
    			levelManager.endGameEvent -= EndGameEventHandler;
    		
    		UiElement.onClick -= OnClickHandler;
    	}
    }
  4. Switch to the UnigineEditor, create a new Dummy Node, call it "widgets_controller" and assign the EndWidget component to it.切换到UnigineEditor,创建一个新的Dummy Node,命名为"widgets_controller",并将EndWidget组件分配给它。

Step 2. Set Up the World Widget
步骤2。建立世界小部件#

The end widget provides button functionality and additional information about the current game outcome. To properly display the end widget, position it in front of the camera.最后小部件提供关于当前游戏按钮功能和附加信息的结果。正确显示小部件,位置在镜头面前。

  1. Drag the programming_quick_start\ui\ui_plane.node from the Asset Browser to the world. programming_quick_start\ui\ui_plane.nodeAsset Browser拖到世界。
  2. Parent it to the PlayerDummy camera. Set the position of the ui_plane node to the following values.父母到PlayerDummy相机。ui_plane节点的位置设置为以下值。

  3. Click the Edit for the ui_plane NodeReference and expand the hierarchy.单击Edit以获得ui_plane NodeReference并展开层次结构。

  4. Assign a UiElement component to the child restart_button node.将一个UiElement组件分配给子节点restart_button
  5. Set the Ui Type to Restart, check the 6th bit option for the Ui Mask (matching the button's Intersection Mask) to correctly process selection intersections and set the Select Scale to 1.05 in order to make buttons bigger on cursor hover. Also, set the Select Emission to #505050 to make the button change its color. 设置Ui TypeRestart,检查 6日强位选择Ui Mask(匹配按钮的十字路口面具)正确流程选择十字路口和设置选择规模1.05为了使光标悬停按钮更大。同时,设置选择发射#505050使按钮改变其颜色。

  6. Set up a new UiElement component the same way for the exit_button, but set the Ui Type to Exit. 用同样的方法为exit_button设置一个新的UiElement组件,但是将Ui Type设置为Exit
  7. Confirm the node reference editing by clicking Apply in the Parameters window of the ui_plane node.确认节点引用编辑在参数窗口中点击Apply ui_plane节点。
  8. Assign the ui_plane node to the End Game Widget field under the EndWidget component of the widgets_controller node.ui_plane节点分配给widgets_controller节点的EndWidget组件下的End Game Widget字段。

  9. Save changes to the world, go to File->Save World or press Ctrl+S hotkey. Build and run the game to see the UI in action.拯救世界的变化,去File->Save World或者按Ctrl+S热键。构建和运行游戏的UI。
最新更新: 2024-04-19
Build: ()