【Unity UIToolkit】UIBuilder基础教程-制作简易的对话系统编辑器 3步教你玩转Unity编辑器扩展工具

这篇具有很好参考价值的文章主要介绍了【Unity UIToolkit】UIBuilder基础教程-制作简易的对话系统编辑器 3步教你玩转Unity编辑器扩展工具。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1.前言

随着Unity开发的深入,基本的Unity编辑器界面并不能满足大部分玩家高阶开发的要求。为了提高开发的效率,有针对性的定制化扩展编辑器界面是提高开发效率的不错选择。
今天就给大家带来Unity官方提高的编辑器扩展工具UIToolkit(集成了UIBuilder和UI Debugger等插件)的使用教程。本次的案例会以游戏中最常用的对话系统作为编辑器管理的内容-制作一个对话系统的编辑器界面。

如果觉得图文教程不够详细的便宜已经直接观看视频教程,更加直观详细哦!
合集·Unity官方编辑器扩展工具UI ToolKit】UI Builder 制作简易对话系统编辑器

下图为使用UIToolkit制作的对话系统编辑器界面(使用节点树管理界面)
unity uitoolkit 教程,Unity,UIToolkit,UIBuilder,1024程序员节,unity,编辑器,游戏引擎,c#,游戏程序

2.UIToolkit安装

UI Toolkit 的历史可以追溯到 Unity 2018 年发布的 UIElement,起初主要用于 Editor 编辑面板中的 UI 开发,自 Unity 2019 起,它开始支持运行时 UI,并更名为 UIToolkit,它以 Package 包(com.unity.ui)的形式存在,并在 Unity 2021.2 版本后被官方内置在Unity编辑器中。

因此Unity2021.2之前的版本要使用UIToolkit的话需要在Package Manager中引入UIToolkit包 (旧名UIBuilder)
1.在Unity编辑器顶部栏点击 Window > Package Manager 来打开 Package Manager 窗口
2.然后左上角点击+号,在下拉选项中选择 Add package from git URL…,
unity uitoolkit 教程,Unity,UIToolkit,UIBuilder,1024程序员节,unity,编辑器,游戏引擎,c#,游戏程序
3.分别通过输入 com.unity.ui 和 com.unity.ui.builder 来获取 UI Toolkit 包和 UI Builder 包。unity uitoolkit 教程,Unity,UIToolkit,UIBuilder,1024程序员节,unity,编辑器,游戏引擎,c#,游戏程序
而在Unity2021.2之后的版本则可以直接在编辑器顶部栏点击Window>UI Toolkit>选择对应的工具使用
unity uitoolkit 教程,Unity,UIToolkit,UIBuilder,1024程序员节,unity,编辑器,游戏引擎,c#,游戏程序

3.编写运行时对话脚本

在日常游戏对话系统中,并不是每次对话都是一模一样的 在玩家进行不同的选择时 输出的对话都是不相同的,因此对话系统一般都是以节点树的形式来编写。
因此我们运行时脚本需要以下的类构成

1.对话节点(每一句对话内容存储的载体)
2.对话节点树(每次对话中都包含了许多句对话内容 所有对话内容都以树的形式存储下来)
3.对话节点树运行器(对话发生的触发器)

3-1.对话内容节点

基类节点-此节点为所有节点的父类包含了所有节点的基础属性与方法

using UnityEngine;

public abstract class Node : ScriptableObject
{
    // 对话节点状态枚举值为运行和等待两种状态
    public enum State{ Running , Waiting }
    // 对话节点当前状态
    public State state = State.Waiting;
    // 是否已经开始当前对话节点判断指标
    public bool started = false;
    // 每个对话节点的描述
    [TextArea] public string description;
    public Node OnUpdate(){
        // 判断该节点首次调用OnUpdate时调用一次OnStart方法
        if(!started){
            OnStart();
            started =true;
        }
        Node currentNode = LogicUpdate();
        // 判断该节点结束时调用一次OnStop方法
        if(state != State.Running){
            OnStop();
            started =false;
        }
        return currentNode;
    } 
    public abstract Node LogicUpdate();
    protected abstract void OnStart();
    protected abstract void OnStop();
}

单向节点-此类节点只能单对单的进行内容关联

public abstract class SingleNode : Node
{
	// 只有一个子类
    public Node child;
}

复合节点-此类节点可以多对多的进行内容关联

using System.Collections.Generic;
public abstract class CompositeNode : Node
{
	// 有多个子节点构成的列表
    public List<Node> children = new List<Node>();
}

上述都为抽象类节点 因此还需要编写继承了对应抽象节点的实体对话类来才可以使用

普通对话节点

using UnityEngine;

// 普通对话节点 后续只会返回一种情况的对话内容
public class NormalDialogue : SingleNode
{
    [TextArea] public string dialogueContent;
    public override Node LogicUpdate()
    {
        // 判断进入下一节点条件成功时 需将节点状态改为非运行中 且 返回对应子节点
        if(Input.GetKeyDown(KeyCode.Space)){
            state = State.Waiting;
            if(child != null){
                child.state = State.Running;
                return child;
            }
        }
        return this;
    }
    //首次进入该节点时打印对话内容
    protected override void OnStart()
    {
        Debug.Log(dialogueContent);
    }
	// 结束时打印OnStop
    protected override void OnStop()
    {
        Debug.Log("OnStop");
    }
}

分支对话节点

using System.Collections.Generic;
using UnityEngine;

public class BranchDialogue : CompositeNode
{
    [TextArea] public string dialogueContent;
    public int nextDialogueIndex = 0;
    public override Node LogicUpdate()
    {
    	// 判断进入哪个对话节点
        if(Input.GetKeyDown(KeyCode.A)){
            nextDialogueIndex = 0;
        }
        if(Input.GetKeyDown(KeyCode.B)){
            nextDialogueIndex = 1;
        }
        // 判断进入下一节点条件成功时 需将节点状态改为非运行中 且 返回对应子节点
        if(Input.GetKeyDown(KeyCode.Space)){
            state = State.Waiting;
            if(children.Count > nextDialogueIndex){
                children[nextDialogueIndex].state = State.Running;
                return children[nextDialogueIndex];
            }
        }
        return this;
    }
    //首次进入该节点时打印对话内容
    protected override void OnStart()
    {
        Debug.Log(dialogueContent);
    }
	// 结束时打印OnStop
    protected override void OnStop()
    {
        Debug.Log("OnStop");
    }
}

3-2.对话树

基类节点树

using System.Collections.Generic;
using UnityEngine;
using UnityEditor;

/* 继承脚本数据化结构对象 ScriptableObject */
public class NodeTree : ScriptableObject
{
    // 当前正在播放的对话
    public RootNode rootNode;
    // 当前正在播放的对话
    public Node runningNode;
    // 对话树当前状态 用于判断是否要开始这段对话
    public Node.State treeState = Node.State.Waiting;
    // 所有对话内容的存储列表
    public List<Node> nodes = new List<Node>();

    // 判断当前对话树和对话内容都是运行中状态则进行OnUpdate()方法更新
    public virtual void Update() {
        if(treeState == Node.State.Running && runningNode.state == Node.State.Running){
            runningNode = runningNode.OnUpdate();
        }
    }
    // 对话树开始的触发方法
    public virtual void OnTreeStart(){
        treeState = Node.State.Running;
    }
    // 对话树结束的触发方法
    public virtual void OnTreeEnd(){
        treeState = Node.State.Waiting;
    }
}

实体类对话节点树

using UnityEngine;

[CreateAssetMenu()]
public class DialogueTree : NodeTree{
    public override void OnTreeStart(){
        base.OnTreeStart();
        runningNode.state = Node.State.Running;
    }
}

3-3.对话树启动器

using UnityEngine;

public class DialogueRunner : MonoBehaviour
{
    public DialogueTree tree;

    private void Start() {
    
    }
    void Update()
    {
        if(Input.GetKeyDown(KeyCode.P)){
            tree.OnTreeStart();
        }
        if(tree != null){
            tree.Update();
        }
        if(Input.GetKeyDown(KeyCode.D)){
            tree.OnTreeEnd();
        }
    }
}

以上就是所有的运行时脚本了
unity uitoolkit 教程,Unity,UIToolkit,UIBuilder,1024程序员节,unity,编辑器,游戏引擎,c#,游戏程序
此时在项目内点击右键,便可以看到我们刚刚编写的可创建资产化的对话节点树和对话节点了
unity uitoolkit 教程,Unity,UIToolkit,UIBuilder,1024程序员节,unity,编辑器,游戏引擎,c#,游戏程序

4.启动运行时对话脚本

4-1.创建实例话脚本对象

右键创建5个实例话脚本对象,分别为:
1个对话节点树
3个普通对话节点
1个分支对话节点

并且按照父子节点顺序关系命名
unity uitoolkit 教程,Unity,UIToolkit,UIBuilder,1024程序员节,unity,编辑器,游戏引擎,c#,游戏程序

4-2.管理对话节点树对应属性

1.选择对对话节点树并在属性面板中创建4个子对话节点
unity uitoolkit 教程,Unity,UIToolkit,UIBuilder,1024程序员节,unity,编辑器,游戏引擎,c#,游戏程序
2.选择对应初始运行节点
unity uitoolkit 教程,Unity,UIToolkit,UIBuilder,1024程序员节,unity,编辑器,游戏引擎,c#,游戏程序

3.将对应实例化对话节点按照对话顺序拖动到对应位置
unity uitoolkit 教程,Unity,UIToolkit,UIBuilder,1024程序员节,unity,编辑器,游戏引擎,c#,游戏程序

4-3.管理各个对话节点对应属性

普通对话实例
unity uitoolkit 教程,Unity,UIToolkit,UIBuilder,1024程序员节,unity,编辑器,游戏引擎,c#,游戏程序
分支对话实例
unity uitoolkit 教程,Unity,UIToolkit,UIBuilder,1024程序员节,unity,编辑器,游戏引擎,c#,游戏程序
后续的对话实例也以此类推管理其对应的属性
1.填写对话内容
2.将对应的子对话内容关联到子节点当中(PS : 如果是最后的节点则无需关联)

4-4.创建对话启动器

1.在场景中创建一个对象
2.将对话启动器脚本挂载到该对象上
3.将创建好的对话树挂载到该启动器脚本的对话树属性上
unity uitoolkit 教程,Unity,UIToolkit,UIBuilder,1024程序员节,unity,编辑器,游戏引擎,c#,游戏程序

此时我们点击运行启动脚本便可以,按照启动器Update()与对话节点LogicUpdate()中所写好的操作方法触发播放对应的对话内容了。
unity uitoolkit 教程,Unity,UIToolkit,UIBuilder,1024程序员节,unity,编辑器,游戏引擎,c#,游戏程序

5.UIToolkit创建对话系统编辑器

5-1.补充完善Runtime脚本

在上一章节当中我们编写的Runtime脚本仅仅从运行时的角度出发,并没有考虑到可视化编辑相关的逻辑,因此我们需要在之前的脚本当中补充对应代码逻辑
1.需要在Node抽象类中补充一个guid和position属性

    [HideInInspector]public string guid;
    [HideInInspector]public Vector2 position;

2.需要在NodeTree类中补充添加节点和删除节点的方法

#if UNITY_EDITOR
        public Node CreateNode(System.Type type){
            Node node = ScriptableObject.CreateInstance(type) as Node;
            node.name =type.Name;
            node.guid = GUID.Generate().ToString();
         
            nodes.Add(node);
            if(!Application.isPlaying){
                AssetDatabase.AddObjectToAsset(node,this);
            }
            AssetDatabase.SaveAssets();
            return node;
        }
        public Node DeleteeNode(Node node){
            nodes.Remove(node);
            AssetDatabase.RemoveObjectFromAsset(node);
            // Undo.DestroyObjectImmediate(node);
            AssetDatabase.SaveAssets();
            return node;
        }
#endif

5-2.创建NodeEditor窗口

1.我们需要在项目中右键 Create => UI Toolkit => Editor Window
2.输入对应的编辑器窗口名称
unity uitoolkit 教程,Unity,UIToolkit,UIBuilder,1024程序员节,unity,编辑器,游戏引擎,c#,游戏程序
3.点击Confirm成功创建出NodeEditor界面
unity uitoolkit 教程,Unity,UIToolkit,UIBuilder,1024程序员节,unity,编辑器,游戏引擎,c#,游戏程序
4.此时我需要把默认生成的NodeEditor脚本里的代码修改一下

using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
using UnityEditor.UIElements;


public class NodeEditor : EditorWindow
{
    NodeTreeViewer nodeTreeViewer;
    InspectorViewer inspectorViewer;
    [MenuItem("Window/UI Toolkit/NodeEditor")]
    public static void ShowExample()
    {
        NodeEditor wnd = GetWindow<NodeEditor>();
        wnd.titleContent = new GUIContent("NodeEditor");
    }

    public void CreateGUI()
    {
        VisualElement root = rootVisualElement;
        
        var nodeTree = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>("Assets/NodeEditor/Editor/UI/NodeEditor.uxml");
        // 此处不使用visualTree.Instantiate() 为了保证行为树的单例防止重复实例化,以及需要将此root作为传参实时更新编辑器状态
        nodeTree.CloneTree(root);

        var styleSheet = AssetDatabase.LoadAssetAtPath<StyleSheet>("Assets/NodeEditor/Editor/UI/NodeEditor.uss");
        root.styleSheets.Add(styleSheet);
        
        // 将节点树视图添加到节点编辑器中
        nodeTreeViewer = root.Q<NodeTreeViewer>();
        // 将节属性面板视图添加到节点编辑器中
        inspectorViewer = root.Q<InspectorViewer>();
    }
    private void OnSelectionChange() {
        // 检测该选中对象中是否存在节点树
        NodeTree tree = Selection.activeObject as NodeTree;
        // 判断如果选中对象不为节点树,则获取该对象下的节点树运行器中的节点树
        if(!tree){
            if(Selection.activeGameObject){
                NodeTreeRunner runner = Selection.activeGameObject.GetComponent<NodeTreeRunner>();
                if(runner){
                    tree = runner.tree;
                }
            }
        }
        if(Application.isPlaying){
            if(tree){
                if(nodeTreeViewer != null){
                    nodeTreeViewer.PopulateView(tree);
                }
            }
        }else{
            if(tree && AssetDatabase.CanOpenAssetInEditor(tree.GetInstanceID())){
                if(nodeTreeViewer != null){
                    nodeTreeViewer.PopulateView(tree);
                }
            }
        }
    }
}

5.此时我们需要把NodeEditor.uxml里面默认生成的一些元素删除,我们就可以得到一个崭新干净的编辑器界面了
unity uitoolkit 教程,Unity,UIToolkit,UIBuilder,1024程序员节,unity,编辑器,游戏引擎,c#,游戏程序
6.我们通过一些前端的技术手法将该NodeEditor分为左右两边的区域(左边为Inspector右边NodeTreeViewer
(图文难以说明,详细内容可以观看下面视频教程 )。
合集·Unity官方编辑器扩展工具UI ToolKit】UI Builder 制作简易对话系统编辑器

unity uitoolkit 教程,Unity,UIToolkit,UIBuilder,1024程序员节,unity,编辑器,游戏引擎,c#,游戏程序

5-3.创建NodeTreeViewer视图

1.在项目中右键创建一个名为NodeTreeViewer脚本
2.该脚本需要继承GraphView,并添加一些GraphView功能代码

using UnityEditor;
using UnityEditor.Experimental.GraphView;
using UnityEngine;
using UnityEngine.UIElements;
using System;

public class NodeTreeViewer : GraphView
{
    public Action<NodeView> OnNodeSelected;
    public new class UxmlFactory : UxmlFactory<NodeTreeViewer,GraphView.UxmlTraits>{}
    NodeTree tree;
    public NodeTreeViewer(){
        Insert(0, new GridBackground());
        // 添加视图缩放
        this.AddManipulator(new ContentZoomer());
        // 添加视图拖拽
        this.AddManipulator(new ContentDragger());
        // 添加选中对象拖拽
        this.AddManipulator(new SelectionDragger());
        // 添加框选
        this.AddManipulator(new RectangleSelector());
        var styleSheet = AssetDatabase.LoadAssetAtPath<StyleSheet>("Assets/NodeEditor/Editor/UI/NodeTreeViewer.uss");
        styleSheets.Add(styleSheet);
    }
    
    // NodeTreeViewer视图中添加右键节点创建栏
    public override void BuildContextualMenu(ContextualMenuPopulateEvent evt)
    {
        // 添加Node抽象类下的所有子类到右键创建栏中
        {
            var types = TypeCache.GetTypesDerivedFrom<Node>();
            foreach(var type in types){
                evt.menu.AppendAction($"{type.Name}", (a) => CreateNode(type));
            }
        }
    }

    void CreateNode(System.Type type){
        // 创建运行时节点树上的对应类型节点
        Node node = tree.CreateNode(type);
        CreateNodeView(node);
    }

    void CreateNodeView(Node node){
        // 创建节点UI
        NodeView nodeView = new NodeView(node);
        // 节点创建成功后 让nodeView.OnNodeSelected与当前节点树上的OnNodeSelected关联 让该节点属性显示在InspectorViewer上
        nodeView.OnNodeSelected = OnNodeSelected;
        // 将对应节点UI添加到节点树视图上
        AddElement(nodeView);
    }
    
    // 只要节点树视图发生改变就会触发OnGraphViewChanged方法
    private GraphViewChange OnGraphViewChanged(GraphViewChange graphViewChange)
    {
        // 对所有删除进行遍历记录 只要视图内有元素删除进行判断
        if(graphViewChange.elementsToRemove != null){
            graphViewChange.elementsToRemove.ForEach(elem =>{
                // 找到节点树视图中删除的NodeView
                NodeView nodeView = elem as NodeView;
                if(nodeView != null){
                    // 并将该NodeView所关联的运行时节点删除
                    tree.DeleteeNode(nodeView.node);
                }
            });
        }
        return graphViewChange;
    }
internal void PopulateView(NodeTree tree){
        this.tree = tree;
        // 在节点树视图重新绘制之前需要取消视图变更方法OnGraphViewChanged的订阅
        // 以防止视图变更记录方法中的信息是上一个节点树的变更信息
        graphViewChanged -= OnGraphViewChanged;
        // 清除之前渲染的graphElements图层元素
        DeleteElements(graphElements);
        // 在清除节点树视图所有的元素之后重新订阅视图变更方法OnGraphViewChanged
        graphViewChanged += OnGraphViewChanged;
    }
}

3.创建一个与NodeTreeViewer同名的USS文件unity uitoolkit 教程,Unity,UIToolkit,UIBuilder,1024程序员节,unity,编辑器,游戏引擎,c#,游戏程序
4.且将下列背景样式Copy到USS文件当

GridBackground{
    --grid-background-color: rgb(40,40,40);
    --line-color: rgba(193,196,192,0.1);
    --thick-line-color: rgba(193,196,192,0.1);
    --spacing: 15;
}

5.回到UI Builder的NodeEditor工程中,由于我们在NodeTreeViewer脚本当中添加了
“ public new class UxmlFactory : UxmlFactory<NodeTreeViewer,GraphView.UxmlTraits>{} ” 脚本
使用我们可以在组件库的Custom Controls当中找到我们刚刚写好的NodeTreeViewer视图,我们直接将该视图拖拽到uxml工程当中即可unity uitoolkit 教程,Unity,UIToolkit,UIBuilder,1024程序员节,unity,编辑器,游戏引擎,c#,游戏程序
6.在调整好了UXML每个元素的样式之后这(这里图文难以讲解,具体的看视频为主)就得到了一个可拖拽 可缩放的NodeTreeViewer网格视图了。

5-4.创建Node节点视图

1.创建一个NodeView脚本,且需要继承GraphView.Node

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEditor.Experimental.GraphView;
using UnityEngine;
using UnityEngine.UIElements;
using UnityEditor.UIElements;
using UnityEditor;

public class NodeView : UnityEditor.Experimental.GraphView.Node
{
    public Action<NodeView> OnNodeSelected;
    public Node node;
    public Port input;
    public Port output;
    public NodeView(Node node){
        this.node = node;
        this.title = node.name;
        // 将guid作为Node类中的viewDataKey关联进行后续的视图层管理
        this.viewDataKey = node.guid;
        style.left = node.position.x;
        style.top = node.position.y;

        CreateInputPorts();
        CreateOutputPorts();
    }

    private void CreateInputPorts()
    {
        /*将节点入口设置为 
            接口链接方向 横向Orientation.Vertical  竖向Orientation.Horizontal
            接口可链接数量 Port.Capacity.Single
            接口类型 typeof(bool)
        */
        // 默认所有节点为多入口类型
        input = InstantiatePort(Orientation.Vertical, Direction.Input, Port.Capacity.Multi, typeof(bool));
        
        if(input != null){
            // 将端口名设置为空
            input.portName = "";
            inputContainer.Add(input);
        }
    }

    private void CreateOutputPorts()
    {
       	output = InstantiatePort(Orientation.Vertical, Direction.Output, Port.Capacity.Multi, typeof(bool));
        if(output != null){
            output.portName = "";
            outputContainer.Add(output);
        }
    }
    // 设置节点在节点树视图中的位置
    public override void SetPosition(Rect newPos)
    {
        // 将视图中节点位置设置为最新位置newPos
        base.SetPosition(newPos);
        // 将最新位置记录到运行时节点树中持久化存储
        node.position.x = newPos.xMin;
        node.position.y = newPos.yMin;
        EditorUtility.SetDirty(node);
    }

    // 复写Node类中的选中方法OnSelected
    public override void OnSelected()
    {
        base.OnSelected();
        // 如果当前OnNodeSelected选中部位空则将该节点视图传递到OnNodeSelected方法中视为选中
        if(OnNodeSelected != null){
            OnNodeSelected.Invoke(this);
        }
    }
}

5-5.创建InspectorViewer面板视图

1.创建一个InspectorViewer脚本,且需要继承VisualElement

using UnityEngine.UIElements;
using UnityEditor;
using UnityEngine;

public class InspectorViewer : VisualElement
{
    public new class UxmlFactory : UxmlFactory<InspectorViewer,VisualElement.UxmlTraits>{}
    Editor editor;
    public InspectorViewer(){

    }
    internal void UpdateSelection(NodeView nodeView ){
        Clear();
        UnityEngine.Object.DestroyImmediate(editor);
        editor = Editor.CreateEditor(nodeView.node);
        IMGUIContainer container = new IMGUIContainer(() => { 
            if(editor.target){
            editor.OnInspectorGUI();
            }
        });
        Add(container);
    }   
}

5-6.在NodeEditor视窗中可视化创建节点

在完成了上述的所有工作之后,来尝试一下在我们自己制作的NodeEditor视窗中可视化创建节点把
1.我们在项目中重新创建一个NodeTree(一定要重新创建)
2.在顶部栏点击Window => UI Toolkit => NodeEditor打开编辑窗口
unity uitoolkit 教程,Unity,UIToolkit,UIBuilder,1024程序员节,unity,编辑器,游戏引擎,c#,游戏程序
3.此时需要在选中NodeTree脚本对象的情况下(一定要双击选中否则会报空指针异常)在NodeEditor编辑界面中右键选中我们需要创建的节点即可
unity uitoolkit 教程,Unity,UIToolkit,UIBuilder,1024程序员节,unity,编辑器,游戏引擎,c#,游戏程序
这样我们就成功的在NodeEditor视窗中可视化创建了一个节点

6.引用文献

【Unity UIBuilder】官方使用手册

【Unity UIToolkit】官方使用手册

【Unity3D】UI Toolkit简介 - 作者 : little_fat_sheep

以上就是本文章全部内容了,如果觉得实用可以点个收藏和关注。博主空间还有更多和Unity相关的实用技巧欢迎大家来一起相互学习。文章来源地址https://www.toymoban.com/news/detail-761589.html

到了这里,关于【Unity UIToolkit】UIBuilder基础教程-制作简易的对话系统编辑器 3步教你玩转Unity编辑器扩展工具的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • unity uitoolkit学习

    1、打开面板 2、找到元素 在UI Builder窗体,别忘了打开Preview再选择元素 3、可以选择不同类型的窗体 4、查看元素的样式 需要注意的是下面的样式会覆盖上面的 5、调试 1、找到PanelSettingsTheme Style Sheet的资源文件,然后新建uss样式文件 2、将uss文件拖拽到Style Sheets中, 需要注意

    2024年02月11日
    浏览(36)
  • unity如何制作简易倒计时器

    首先理清思路,计时器的核心要素是计时的总时长和时间间隔需要均匀一秒,要实现的功能是在总时长的基础上实现等时间间隔减秒,并且减到0后终止。 其中最为关键的问题就是怎么得到均匀的时间间隔1秒,所以我们需要知道: Time.time 表示从游戏开发到现在的时间,会随

    2024年02月16日
    浏览(24)
  • 【Unity】简易俄罗斯方块(Tetris)制作

    原视频:https://www.youtube.com/watch?v=T5P8ohdxDjo b站转载:【UNITY】13分钟制作出俄罗斯方块!(附下载)_哔哩哔哩_bilibili 一、背景及方块制作关键点 1、要将背景的左下角移到坐标(0,0)点 2、方块的旋转点设置 3、方块坐标需要在整数值 二、脚本 1、TetrisBlock

    2024年02月05日
    浏览(39)
  • Unity3d 制作一个简单的NPC对话系统

    ​ 最近在自己写一个比较小的项目,虽然自己是一个策划,但是程序方面我觉得也是很有必要学一学的。 ​ 经过了接近一年的学习,也终于是可以独自写一些小的系统了。 ​ 这次自己写了一个比较简单的NPC对话系统,供大家参考。 进入对话区域 开始对话 Inspector面板可调

    2023年04月08日
    浏览(37)
  • 安信可新品雷达模组Rd-03搭配STM32制作简易人体感应雷达灯教程

    - 安信可最新雷达模组Rd-03已经横空出世,为了方便大家使用该模组,本教程将使用STM32F103C8T6搭配Rd-03制作一个简易的人体检测雷达灯。 Rd-03共有五个管脚,以下是管脚功能定义表: 序号 引脚 说明 1 3.3V 输入电源 2 GND 接地 3 OT1 UART_TX 4 RX UART_RX 5 OT2 检测结果输出,感应时输出

    2024年03月14日
    浏览(49)
  • Excel与Unity工作流(二):基础对话框架

    本文将演示在unity中实现类似galgame的对话效果,并且通过Excel进行文本、图片、选项、赋值、音乐的配置 (该图主要是展示版面和大致目标效果,与本文关系不大) (来源:《无期迷途》) 每点击一次鼠标,就出现下一个对话/或者出现选项; 如果出现选项,点击选项,会有不同

    2024年04月14日
    浏览(38)
  • QT基础教程之五对话框QDialog

    对话框是 GUI 程序中不可或缺的组成部分。很多不能或者不适合放入主窗口的功能组件都必须放在对话框中设置。对话框通常会是一个顶层窗口,出现在程序最上层,用于实现短期任务或者简洁的用户交互。 Qt 中使用QDialog类实现对话框。就像主窗口一样,我们通常会设计一个

    2024年02月10日
    浏览(32)
  • Unity教程||Unity添加中文字体||Unity知识记录--制作UI粒子特效

    ## 1、拷贝字体文件 拷贝C:WindowsFonts文件夹下,华文细黑常规文件到项目中   ## 2、下载中文字库 链接: https://pan.baidu.com/s/1KW31KB5vEImZHUWvQ9PLEQ 提取码: bgug  3、添加字体字库 选择Window-TextMeshPro-Font Asset Creator   进入Font Asset Creator a、Source Font File 选择字体文件 b、Atlas Resolution 都

    2024年02月09日
    浏览(56)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包