• unity3d中显示控件,代码可使用在Editor上,也可以使用在游戏场景中作为UI使用。【csdn上有个下载需要16分的,和我这个一模一样的,大家别下这个16的了】
  • 下载地址:https://assetstore.unity.com/packages/tools/gui/tree-view-65364。 2.新建场景,新建Canvas,将Assets\Battlehub\UIControls\Prefabs\TreeView.prefab拖入Canvas下。 3.点击【GameObject】【Create E...

    1.下载插件Tree View导入到工程中。下载地址:https://assetstore.unity.com/packages/tools/gui/tree-view-65364。
    2.新建场景,新建Canvas,将Assets\Battlehub\UIControls\Prefabs\TreeView.prefab拖入Canvas下。


    3.点击【GameObject】【Create Empty】,创建一个空实体,命名为LoadTreeviewData。
    4.创建LoadTreeviewData.cs脚本,打开编辑,将TreeViewDemo中的代码(类名除外)复制到脚本中(全部代码见后文)。
    5.自定义数据给大家MyCustomData。
    6.在LoadTreeviewData的Start()函数中添加Treeview数据,改写数据绑定ItemDataBinding和节点展开函数ItemExpanding。
    7.将TreeView拖入变量框,运行即可。

    using Battlehub.UIControls;
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Linq;
    using UnityEngine;
    using UnityEngine.UI;
    
    public class MyTreeview : MonoBehaviour {
    
        public TreeView TreeView;
    
        public static bool IsPrefab(Transform This)
        {
            if (Application.isEditor && !Application.isPlaying)
            {
                throw new InvalidOperationException("Does not work in edit mode");
            }
            return This.gameObject.scene.buildIndex < 0;
        }
    
        private void Start()
        {
            if (!TreeView)
            {
                Debug.LogError("Set TreeView field");
                return;
            }
    
            List<MyCustomData> dataItems = new List<MyCustomData>();
            dataItems.Add(new MyCustomData("宝成线", NodeType.RailwayLine));
    
            MyCustomData data = new MyCustomData("成昆线", NodeType.RailwayLine);
            data.childs.Add(new MyCustomData("成都段", NodeType.RailwaySection));
            data.childs.Add(new MyCustomData("云南段", NodeType.RailwaySection));
    
    
            dataItems.Add(data);
            dataItems.Add(new MyCustomData("京广线", NodeType.RailwayLine));
    
            //subscribe to events
            TreeView.ItemDataBinding += OnItemDataBinding;
            TreeView.SelectionChanged += OnSelectionChanged;
            TreeView.ItemsRemoved += OnItemsRemoved;
            TreeView.ItemExpanding += OnItemExpanding;
            TreeView.ItemBeginDrag += OnItemBeginDrag;
    
            TreeView.ItemDrop += OnItemDrop;
            TreeView.ItemBeginDrop += OnItemBeginDrop;
            TreeView.ItemEndDrag += OnItemEndDrag;
    
            //Bind data items
            TreeView.Items = dataItems;
        }
    
        private void OnItemBeginDrop(object sender, ItemDropCancelArgs e)
        {
            //object dropTarget = e.DropTarget;
            //if(e.Action == ItemDropAction.SetNextSibling || e.Action == ItemDropAction.SetPrevSibling)
            //{
            //    e.Cancel = true;
            //}
    
        }
    
        private void OnDestroy()
        {
            if (!TreeView)
            {
                return;
            }
    
    
            //unsubscribe
            TreeView.ItemDataBinding -= OnItemDataBinding;
            TreeView.SelectionChanged -= OnSelectionChanged;
            TreeView.ItemsRemoved -= OnItemsRemoved;
            TreeView.ItemExpanding -= OnItemExpanding;
            TreeView.ItemBeginDrag -= OnItemBeginDrag;
            TreeView.ItemBeginDrop -= OnItemBeginDrop;
            TreeView.ItemDrop -= OnItemDrop;
            TreeView.ItemEndDrag -= OnItemEndDrag;
        }
    
        private void OnItemExpanding(object sender, ItemExpandingArgs e)
        {
            MyCustomData dataItem = (MyCustomData)e.Item;
            if (dataItem.childs.Count > 0)
            {
                //Populate children collection
                e.Children = dataItem.childs;
            }
        }
    
        private void OnSelectionChanged(object sender, SelectionChangedArgs e)
        {
    #if UNITY_EDITOR
            //Do something on selection changed (just syncronized with editor's hierarchy for demo purposes)
            UnityEditor.Selection.objects = e.NewItems.OfType<GameObject>().ToArray();
    #endif
        }
    
        private void OnItemsRemoved(object sender, ItemsRemovedArgs e)
        {
            //Destroy removed dataitems
            for (int i = 0; i < e.Items.Length; ++i)
            {
                GameObject go = (GameObject)e.Items[i];
                if (go != null)
                {
                    Destroy(go);
                }
            }
        }
    
        /// <summary>
        /// This method called for each data item during databinding operation
        /// You have to bind data item properties to ui elements in order to display them.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnItemDataBinding(object sender, TreeViewItemDataBindingArgs e)
        {
            MyCustomData dataItem = e.Item as MyCustomData;
            if (dataItem != null)
            {
                //We display dataItem.name using UI.Text 
                Text text = e.ItemPresenter.GetComponentInChildren<Text>(true);
                text.text = dataItem.name;
    
                //Load icon from resources
                Image icon = e.ItemPresenter.GetComponentsInChildren<Image>()[4];
                icon.sprite = Resources.Load<Sprite>("cube");
    
                //And specify whether data item has children (to display expander arrow if needed)
                if (dataItem.name != "TreeView")
                {
                    e.HasChildren = dataItem.childs.Count > 0;
                }
            }
        }
    
        private void OnItemBeginDrag(object sender, ItemArgs e)
        {
            //Could be used to change cursor
        }
    
        private void OnItemDrop(object sender, ItemDropArgs e)
        {
            if (e.DropTarget == null)
            {
                return;
            }
    
            Transform dropT = ((GameObject)e.DropTarget).transform;
    
            //Set drag items as children of drop target
            if (e.Action == ItemDropAction.SetLastChild)
            {
                for (int i = 0; i < e.DragItems.Length; ++i)
                {
                    Transform dragT = ((GameObject)e.DragItems[i]).transform;
                    dragT.SetParent(dropT, true);
                    dragT.SetAsLastSibling();
                }
            }
    
            //Put drag items next to drop target
            else if (e.Action == ItemDropAction.SetNextSibling)
            {
                for (int i = e.DragItems.Length - 1; i >= 0; --i)
                {
                    Transform dragT = ((GameObject)e.DragItems[i]).transform;
                    int dropTIndex = dropT.GetSiblingIndex();
                    if (dragT.parent != dropT.parent)
                    {
                        dragT.SetParent(dropT.parent, true);
                        dragT.SetSiblingIndex(dropTIndex + 1);
                    }
                    else
                    {
                        int dragTIndex = dragT.GetSiblingIndex();
                        if (dropTIndex < dragTIndex)
                        {
                            dragT.SetSiblingIndex(dropTIndex + 1);
                        }
                        else
                        {
                            dragT.SetSiblingIndex(dropTIndex);
                        }
                    }
                }
            }
    
            //Put drag items before drop target
            else if (e.Action == ItemDropAction.SetPrevSibling)
            {
                for (int i = 0; i < e.DragItems.Length; ++i)
                {
                    Transform dragT = ((GameObject)e.DragItems[i]).transform;
                    if (dragT.parent != dropT.parent)
                    {
                        dragT.SetParent(dropT.parent, true);
                    }
    
                    int dropTIndex = dropT.GetSiblingIndex();
                    int dragTIndex = dragT.GetSiblingIndex();
                    if (dropTIndex > dragTIndex)
                    {
                        dragT.SetSiblingIndex(dropTIndex - 1);
                    }
                    else
                    {
                        dragT.SetSiblingIndex(dropTIndex);
                    }
                }
            }
        }
    
        private void OnItemEndDrag(object sender, ItemArgs e)
        {
        }
    
        private void Update()
        {
            if (Input.GetKeyDown(KeyCode.J))
            {
                TreeView.SelectedItems = TreeView.Items.OfType<object>().Take(5).ToArray();
            }
            else if (Input.GetKeyDown(KeyCode.K))
            {
                TreeView.SelectedItem = null;
            }
        }
    }
    
    enum NodeType { RailwayLine = 0, RailwaySection = 1, RailwaySegment = 2, RailwayStation = 3 }
    class MyCustomData
    {
        public List<MyCustomData> childs;
        public NodeType nodeType;
        public string name;
        public object tag;
    
        public MyCustomData(string na, NodeType nt)
        {
            childs = new List<MyCustomData>();
            name = na;
            nodeType = nt;
        }
    }

     

    展开全文
  • Unity为大家提供了一套很完整的图形化界面引擎,包括窗口、文本框、拖动条等。下面将为大家介绍主要的基本控件。 一、Label控件  Label控件(标签控件)以文本的形式来显示一串字符串信息,该控件不仅可以输入...

           Unity为大家提供了一套很完整的图形化界面引擎,包括窗口、文本框、拖动条等。下面将为大家介绍主要的基本控件。


    一、Label控件

           Label控件(标签控件)以文本的形式来显示一串字符串信息,该控件不仅可以输入字符串信息,还可以输入贴图。

    参数:
    position : Rect ——标签在屏幕上的矩形位置,(起点x坐标,起点y坐标,标签宽度,标签高度)。
    text : String ——在标签上显示的文本内容。
    image : Texture ——在标签上显示的纹理。
    content : GUIContent ——在标签上显示的文本、图片和信息提示。
    style : GUIStyle ——使用的样式,如果不使用,那么标签的样式使用的就是当前的GUISkin皮肤
    描述:
    在屏幕上创建一个文本或纹理的标签。

    标签没用用户交互,不捕捉鼠标点击,如果想创建响应用户输入的控件,可以使用Box控件。

    案例:绘制一个“Hello World!”标签和一个图片标签
           首先,在Project视图中的一个文件夹上右击→Create→C# Script,然后为其重命名为Label。在这里需要注意的是脚本文件的名称必须和脚本中pulic class XXX :MonoBehaviour一样,不然会出错的。双击打开脚本编写器,接着就是编写脚本,编写的内容如下:
    using UnityEngine;
    using System.Collections;
    
    public class Label : MonoBehaviour {
    
    	public Texture img;//图片/
    	
    	void OnGUI()
    	{
    		GUI.Label(new Rect(10,10,200,20),"Hello World!");
    		GUI.Label(new Rect(10,50,200,200),img);
    	}
    }
    
            在这个脚本中只用一个OnGUI方法,该方法为绘制界面的方法,所有GUI的绘制都需要在这个方法中实现。
            另外,脚本必须绑定到对象上才会执行自身的生命周期。绑定的方法很简单,就是在Project视图中将该脚本文件拖拽到Hierarchy视图中的一个对象上即可。在这里我们将Label.cs脚本绑定到Main Camera对象上。
           接着是图片变量的赋值,首先只用公有变量才能从Project中拖拽赋值或者手动输入赋值,即前面有public关键字。

    游戏视图:


    二、Button控件和RepeatButton控件

           Button控件(按钮控件)用来进行用户的行为判断,例如:确认,取消,退出等。按钮有3中状态:未点击,点击,点击后,在一般情况下,我们只用到未点击和点击这2种情况。

    Parameters(参数):
    position : Rect ——按钮在屏幕上的矩形位置,(起点x坐标,起点y坐标,按钮宽度,按钮高度
    text : String ——按钮上显示的文本内容
    image : Texture ——按钮上显示的图片纹理
    content : GUIContent ——按钮的文本,图片和提示。
    style : GUIStyle ——按钮使用的样式,如果不使用,则按钮的样式使用的就是当前的GUISkin皮肤


    Returns(返回):
    布尔值——当该按钮被点击时返回true

    Description(描述):
    创建一个单次按下按钮,当用户点击按钮时立即触发事件。

    RepeatButton(连续按钮)用于持续按下时触发事件的按钮,普通的Button按钮适用与单次按下。

    参数与普通的Button没什么大的区别。

    Returns返回值:
    布尔值——当用户按下该按钮时返回true。

    描述:
    创建一个按钮,只要用户按住不放,将一直被激活。
    从按下按钮到释放按钮的时间内重复触发其Click事件,也就是说他将连续不停的发送点击事件。

    案例:创建3个按钮,分别为普通文本按钮,普通图片按钮,连续按钮。再创建了3个标签,第一个标签用于显示用户按下的按钮是哪一个,第二个标签是用来显示普通图片按钮按下后,绘制一个图片出来,第三个标签用来记录连续按钮按下的时间。
    using UnityEngine;
    using System.Collections;
    
    public class Button : MonoBehaviour {
    
    	public Texture img;//公有变量图片/
    	private Texture img0;
    	private string info;//显示的信息/
    	private int frameTime;//记录按下的时间/
    	
    	void Start()
    	{
    		//初始化/
    		info = "请您点击按钮";
    		frameTime = 0;
    	}
    	
    	void OnGUI()
    	{
    		//标签/
    		GUI.Label(new Rect(50,10,200,20),info);		
    		//普通按钮,点击后显示Hello World
    		if(GUI.Button(new Rect(50,250,200,20),"Hello World"))
    		{
    			info = "Hello World";
    		}
    		//标签/
    		GUI.Label(new Rect(280,10,200,200),img0);
    		//图片按钮,点击后显示图片/
    		if(GUI.Button(new Rect(280,250,200,200),img))
    		{
    			img0 = img;
    			info = "您点击了图片按钮";
    		}
    		//标签/
    		GUI.Label(new Rect(500,10,200,20),"持续按下的时间:" + frameTime);
    		//连续按钮,点击后显示按下的时间/
    		if(GUI.RepeatButton(new Rect(500,250,200,20),"持续按下"))
    		{
    			frameTime ++ ;
    			info = "您按下了连续按钮";
    		}		
    		//每当鼠标按下时将frameTime重置,一遍进行下次记录/
    		if(Input.GetMouseButtonDown(0))
    		{
    			frameTime = 0;
    		}
    	}
    }
    
    在这里依旧需要将脚本绑定Main Camera上,并且将需要赋值的公有变量进行赋值,在Label控件中我已经介绍了,这里就不废话了~

    游戏视图:







    ———————————————
    参考文献:
    《Unity3D 游戏开发》宣玉松
     Unity Script Reference

    展开全文
  • 这是一个完整的Unity树形菜单项目工程,菜单可以进行折叠,点击某个节点,可以显示出所点击菜单的信息。
  • unity3d 各大插件评测

    2018-01-30 15:00:43
    原创文章如需转载请注明:转载自风宇冲Unity3D教程学院 引言:想用Unity3D制作优秀的游戏,插件是必不可少的。工欲善其事必先利其器。本文主旨是告诉使用Unity3D引擎的同学们如何根据需求选择适当的工具...

    原创文章如需转载请注明:转载自风宇冲Unity3D教程学院


    引言:想用Unity3D制作优秀的游戏,插件是必不可少的。工欲善其事必先利其器。本文主旨是告诉使用Unity3D引擎的同学们如何根据需求选择适当的工具。为此我写了插件的经验及理论讲解,涉及插件的 学习/辨别/选择/配合。也写了插件的 评测/教程/下载。关于评测,带有一定的主观性,仅供参考。关于教程,热门插件网上已经有很多教程了,本文提供链接,网上资料少的插件本文提供了使用方法的简单介绍。至于下载,主要是学习交流为主,下载速度还是比较快的。
    (PS:本文主要起一个抛砖引玉的作用。欢迎同学们积极留言交流,大牛不吝指教【风宇冲】Unity3D教程宝典之插件篇:Unity3D插件详细评测及教学下载 - 风宇冲 - 风宇冲Unity3D教程学院。本文用武侠功夫这个大家比较感兴趣的内容来描述游戏开发,借此描述Unity插件学习的道理,同时激发同学们的学习兴趣,没兴趣的可以跳过相关内容。我的新浪微博 @风宇冲

    本文一共分为三个部分,第一部分是插件的下载,第二部分是插件的评测,第三部分是插件的学习方法。

                                  第一部分 插件的下载

    下载所有插件 (下载时逐个下载比较快)
    注:所有付费插件下载仅用于学习和交流用途,请在下载后24小时内删除,商业用途请购买正版。(你懂的)


                                  第二部分 插件的评测

    Unity插件本文分以下九个类别介绍,后面跟的是风宇冲的推荐插件:
    一 界面制作 推荐:NGUI
    二 2D游戏制作 推荐:2D Toolkit
    三 可视化编程 推荐:PlayMaker
    四 插值插件 推荐:iTween,HOTween
    五 路径搜寻 推荐:Simple Path
    六 美术及动画制作 推荐:RageSpline,Smooth Moves
    七 画面增强    推荐:Bitmap2Material,Strumpy Shader Editor
    八 摄像机管理  推荐:Security Camera
    九 资源包  推荐:Nature Pack
    十 其他类
    一: 界面设计(UI) -  风宇冲推荐NGUI
    综述:所有UI插件可以实现的功能和效果最后都是差不多的,区别是最终游戏的运行效率和内存占用量不一样,开发的速度也不一样。 NGUI和EZGUI是属于一类,核心是将UI元件图合并到一张大图(atlase)上,再根据uv去找对应的小图,最后使用2D camera绘制。 iGUI是另外一种UI插件,它可以说是Unity自带UI的升级版,也就是OnGUI的延伸。了解OnGUI()的同学都知道,它的运行效率是比较低的,没有Drawcall合并,iGUI也一样。中文等字体制作一般是用Glyph Desginer 或者 Bmfont, 这点NGUI和EZGUI是通用的。总体来说, GUI插件的功能还是略微有限, 无论是什么GUI插件想做复杂点的功能就必须得用脚本。学习维护起来还是稍微有点麻烦的,故依然建议一个团队只一个人或几个人专门负责UI。
    【风宇冲】Unity3D教程宝典之插件篇:Unity3D插件详细评测及教学下载 - 风宇冲 - 风宇冲Unity3D教程学院

    【NGUI】
    【风宇冲】Unity3D教程宝典之插件篇:Unity3D插件详细评测及教学下载 - 风宇冲 - 风宇冲Unity3D教程学院
    细节功能  
    运行效率  
    内存占用   ★
    开发速度   
    掌握时间   
    跨越平台   
    文档教程  
    综合评价  

    优点:UI合成图(atlas)管理方便,字体RGB压缩,持续更新,支持Flash,支持语言本地化即多语言,支持图像高低清配置。
    缺点:卷屏界面(ScrollList)的实现稍微麻烦。
    介绍:目前Unity最好用的UI 插件。重点是 NGUI应该会一直更新,跟着Unity的脚步。 NGUI也更方便于管理atlas,至少每个Sprite在atlas中都有名字来管理可以很方便的添加删除共用,并且Sprite的位置大小信息可见也 可适当调整。
    使用注意:
    (1)一个界面,通常也就是一个panel,一定只能有一个atlase, 否则层级极易出现错乱。

    div STYLE="color: rgb(255, 0, 0);" >【FastGUI】
    【风宇冲】Unity3D教程宝典之插件篇:Unity3D插件详细评测及教学下载 - 风宇冲 - 风宇冲Unity3D教程学院
    细节功能  
    运行效率  与NGUI相同
    内存占用   与NGUI相同
    开发速度   
    掌握时间   
    跨越平台  与NGUI相同
    文档教程  
    综合评价  
    NGUI插件的补充,必须先在工程里导入FastGUI。主要用途为对Photoshop的支持,可以利用Photo的分层快速制作NGUI的UI部件,直接在Unity里使用psd即可。

    【EZGUI】
    【风宇冲】Unity3D教程宝典之插件篇:Unity3D插件详细评测及教学下载 - 风宇冲 - 风宇冲Unity3D教程学院
    细节功能 
    运行效率 
    内存占用 
    开发速度  
    掌握时间  
    跨越平台  
    文档教程 
    综合评价 
      比较经典的UI插件,目前已经基本不更新了。 
    优点:Unity的元老级UI插件,方便实现快速开发
    缺点:已基本不更新,UI合成图不能单图调整。
    使用中注意的几点:
    1:如果是Prefab中有EZGUI的东西的话,每次修改完最好Apply一下,然后点击Build Atlases
    2:如果贴图合成图(atlase)都默认在Sprite Atlases文件夹下,如果图错乱的话,直接删除贴图重新点击Build Atlases生成贴图合成图即可。
    3:位于scrolllist 下的一切物体必须为 EZGUI的组件 , 否则下拉的时候会不被切图。
    scroll item 显示不完整  : 调整scrollist视口x尺寸
    4:假如 点pixel perfect后 仍不显示尺寸则 点击运行则尺寸恢复正常
    5:Panel只 build atlas 精度不够:  把atlas的分辨率调高 然后删掉 重新build
    6:如果是移动平台开发切记EZ GUI组件选项不能钩 pixel perfect,因为其有auto resize会使在iphone 尺寸错误。
    7:EZ脚本里很多有用函数,其默认为protected,建议将有用函数改成public,方便调用。

    【iGUI】
    【风宇冲】Unity3D教程宝典之插件篇:Unity3D插件详细评测及教学下载 - 风宇冲 - 风宇冲Unity3D教程学院
    细节功能  
    运行效率  
    内存占用  
    开发速度   
    掌握时间   
    跨越平台   
    文档教程  
    综合评价  
    优点:快速开发,可视化
    缺点: 效率低
    iGUI是所有UI制作插件里最牛的可视化工具了。它的口号是 WSYIWYG(What you see is what you get),翻译成中文就是 所见即所得。其UI的实现核心是和Unity自带UI也就是OnGUI()是一样的。所以导致了做到后期一整套UI可能会有几十甚至上百的Drawcall。
    【风宇冲】Unity3D教程宝典之插件篇:Unity3D插件详细评测及教学下载 - 风宇冲 - 风宇冲Unity3D教程学院

    二:2D游戏制作 -  风宇冲推荐2D Toolkit
    综述:核心都是 2d精灵(Spritte)以及帧动画的管理和使用。个人觉得2D Toolkit 比Ex2d好些,更像是制作商业2D游戏的软件。
    【2D Toolkit 】
    【风宇冲】Unity3D教程宝典之插件篇:Unity3D插件详细评测及教学下载 - 风宇冲 - 风宇冲Unity3D教程学院
    细节功能  
    运行效率  
    内存占用  
    开发速度  
    掌握时间   
    跨越平台   
    文档教程  
    综合评价  
    优点:专业,靠谱
    缺点:精细的碰撞实现较麻烦
    你想做2D游戏?没错,就是它了!笔者也做过一些2D游戏,棋牌的飞行的RPG的都有,2D Toolkit还是很靠谱的。缺点是碰撞检测要么是简单的多边形(三角形四边形神马的)之间碰撞,或者是简单多边形和复杂多边形之间。复杂多边形和复杂多边形之间的碰撞是不支持的。而且复杂多边形的碰撞体需要自己去画。想做出类似像素碰撞检测的效果也是可以的,沿着图形本身的边缘去画,如果你不嫌麻烦的话。
    【风宇冲】Unity3D教程宝典之插件篇:Unity3D插件详细评测及教学下载 - 风宇冲 - 风宇冲Unity3D教程学院【风宇冲】Unity3D教程宝典之插件篇:Unity3D插件详细评测及教学下载 - 风宇冲 - 风宇冲Unity3D教程学院








    【Ex2d】
    【风宇冲】Unity3D教程宝典之插件篇:Unity3D插件详细评测及教学下载 - 风宇冲 - 风宇冲Unity3D教程学院

    笔者接触了一点,看了其官方提供的示例,感觉比较娱乐。不多评价了。


    三:可视化编程(Visual Scripting) -  风宇冲推荐PlayMaker
    综述:可视化编程在商业游戏开发里可以辅助编程开发而不是替代编程。PlayMaker可以用来做状态管理。uScript可以用来做简单游戏的开发。
    【PlayMaker】
    【风宇冲】Unity3D教程宝典之插件篇:Unity3D插件详细评测及教学下载 - 风宇冲 - 风宇冲Unity3D教程学院
    可视化程度
    细节功能  
    运行效率  
    开发速度   
    掌握时间   
    跨越平台   
    文档教程  
    综合评价  

    优点:状态管理
    缺点:实现其宣扬的无编程做游戏不靠谱,多状态功能难管理
    Asset Store上面很火的插件,官方说可实现无编程制作完整的游戏。这个个人感觉,你要做个类似俄罗斯方块或者弹弹球之类的小游戏是可以的,但是完全不编程制作商业级的游戏真心不靠谱。举个例子,游戏要赚钱你要嵌入广告sdk或者是IAP等付费sdk,那么你就得写脚本去实现。 不过PlayMaker也还是有可取的地方,其核心在于 将例如站立行走死亡等等状态通过状态机简称FSM(finite state machine)来管理。简单来说一个物体就是一个FSM,一个状态对应一个state。游戏过程中能在物体上方实时显示该物体的状态。并且有很方便的图表管理。缺点在于:所有功能必须对应状态。有很多共同状态都需要的功能用Playmaker做会极其麻烦,比方说,你有一个人物,有5个状态,还有行走攻击等控制输入,每个状态都要控制输入的话,同样的代码你就要有5份,很麻烦。而正常代码的话只需要简单的一段代码几个状态的与运算就可以了。
    【风宇冲】Unity3D教程宝典之插件篇:Unity3D插件详细评测及教学下载 - 风宇冲 - 风宇冲Unity3D教程学院



    【uScript】
    【风宇冲】Unity3D教程宝典之插件篇:Unity3D插件详细评测及教学下载 - 风宇冲 - 风宇冲Unity3D教程学院
    可视化程度
    细节功能  
    运行效率  
    开发速度   
    掌握时间   
    跨越平台   
    文档教程  
    综合评价  

    优点:流程清晰
    缺点:功能不够细致
    如其宣传的,uScript模仿了UDK和CE3的开发形式,注重逻辑流程,所见即所得,逻辑性直观紧凑。但是模块还不够全面功能不细致,例如你可以给材质赋贴图,但是要改变材质颜色就找不到对应功能了,类似情况挺多的。
    【风宇冲】Unity3D教程宝典之插件篇:Unity3D插件详细评测及教学下载 - 风宇冲 - 风宇冲Unity3D教程学院

    四:插值插件 (Tween tool)-  风宇冲推荐iTween / HOTween
    综述:iTween和HOTween各有各的优势,核心功能就是对位移,缩放,颜色等数值进行插值。iTween和HOTween并不冲突,可以同时在一个工程里使用。建议做路径的话最好用iTween, 做非位移,缩放,颜色的数值时只能用HOTween。其他情况最好用HOTween,因为管理更具有可操作性。
    【iTween】
    【风宇冲】Unity3D教程宝典之插件篇:Unity3D插件详细评测及教学下载 - 风宇冲 - 风宇冲Unity3D教程学院
    实用性    
    简易度    ★
    综合评价  
    优点:免费,通用,实用
    缺点:不够稳定,不能返回改变目标tweener
    介绍:免费的经典tween插件。Tween,包括位移,缩放,颜色变换等。NGUI,EZGUI,PlayMaker等很多插件都使用它来实现tween部分。缺点是tween的过程中,如果物体被销毁等情况,容易产生不可预制的错误。
    【iTweenPath】
    可视化    ★
    实用性    
    简易度    ★
    综合评价  
    优点:免费,路径清楚,实用
    介绍:iTween的补充插件,主要是可视化的绘制路径,然后在iTween里使用生成的路径。可以用于TD地图怪物的路径移动。
    使用方法:(1)导入插件后 (2)随便任何一个物体,把iTweenPath拖上去 (3)inspector里设置路径点数量 (4)在选中该物体的前提下,在Scene View里拖拽各个点绘制路径 (5)给路径起名例如 'xyz' (6)代码里使用即可,例如iTween.MoveTo(obj, iTween.Hash("path",iTweenPath.GetPath("xyz"),"time",10f));
    【风宇冲】Unity3D教程宝典之插件篇:Unity3D插件详细评测及教学下载 - 风宇冲 - 风宇冲Unity3D教程学院



    【HOTween】
    【风宇冲】Unity3D教程宝典之插件篇:Unity3D插件详细评测及教学下载 - 风宇冲 - 风宇冲Unity3D教程学院
    实用性    
    简易度    ★
    综合评价  
    优点:免费,管理比iTween更方便,使用范围更广
    缺点:可视化补充件HOTween Edtior作用position时不能像
    iTweenPath那样显示路径。
    介绍:类似iTween的 tween插件,功能更为强大。目标类型不再仅仅为position,color等固定类型,任何你在脚本里定义的public, non-static的 numeric 即 color/vector/int/float/double/string 变量都可以作为目标。并且调用函数后会返回tweener,如果储存tweener可以随时 监测/停止本次tween。
    使用方法:(1)导入插件
    (2)使用HOTween的脚本里添加using Holoville.HOTween;
    Start()里添加HOTween.Init();
    (3)   TweenParms tmp = new TweenParms();
            tmp.Prop("position",new Vector3(5,0,0));
            tmp.Ease(EaseType.Linear);
            HOTween.To(obj.transform,1,tmp);
     其中 position如果换成自定义变量,obj.transform就要换成对应的脚本对象即可。

    序列tween使用方法:
    (1)mySequence = new Sequence(new SequenceParms().Loops(3,LoopType.Yoyo));
    (2)
    mySequence.Append(HOTween.To(myGameObject1.transform, 1, new TweenParms().Prop("position", new Vector3(10,20,30)).Prop("rotation", new Vector3(0,720,0)).Prop("localScale", new Vector3(4,4,4)).Ease(EaseType.EaseOutBounce)));
    有Append /
     Prepend / Insert三种方法,Append是加在序列最后,Prepend是最前,Insert是即将到来的目标
    注意:(1)HOTween.To 等方法是低效的,储存返回的结果tweener,然后反复使用例如tweener.Play()更高效
    (2)Tweener及TweenParms相当于一个容器, 下面填的变量才是真正要改变的内容。
    【HOTween Editor】(要求Unity 3.5.6以上)
    【风宇冲】Unity3D教程宝典之插件篇:Unity3D插件详细评测及教学下载 - 风宇冲 - 风宇冲Unity3D教程学院
    可视化    ★
    实用性    
    简易度    ★
    综合评价  
    优点:高效,快捷
    缺点:插值作用于position时,无路径显示。
    使用方法:
    (1)选中目标物体 (2)Component->HOTween->HOTweenComponent  (3)在Inspector下的界面点击 蓝色的‘+Add Tween’(4)选择tween目标 (5)点击蓝色的‘+’,注意你想要改变的变量点这一步才会出来。(6)选择要插值的变量 (7)填Tween To等值即可
    (8) 关闭'AutoDestroy'和‘Autoplay ’ (9) 脚本加
    using Holoville.HOTween;
    using System.Collections.Generic;
    (10)调用该tween
        HOTweenComponent tweenComponent = myGameObject.GetComponent<HOTweenComponent>();
            if (tweenComponent != null)
            {
                // Do something with the Tweeners
                List<Tweener> tweeners = tweenComponent.generatedTweeners;
               
                if(tweeners[0].id == "tweenerName")
                {
                    tweeners[0].Play();
                }
            }
    【风宇冲】Unity3D教程宝典之插件篇:Unity3D插件详细评测及教学下载 - 风宇冲 - 风宇冲Unity3D教程学院








    五: 路径搜寻(Path Finding)-  风宇冲推荐SimplePath
    综述:路径搜寻主要用于怪物的AI行走,以及人物点击移动。这两个路径算法核心思想都是:先将地图划分成方格区域(像棋盘一样),然后根据方格内是否有障碍物对方格进行赋值,最后生成 单位位置 与 目标位置间的格子路径。想具体学习的童鞋可以百度 A star等算法。
    【SimplePath】
    【风宇冲】Unity3D教程宝典之插件篇:Unity3D插件详细评测及教学下载 - 风宇冲 - 风宇冲Unity3D教程学院


    运行效率  
    掌握时间   
    文档教程  
    综合评价  
    官方介绍说支持500+agent,即支持500个单位同时寻路,下方提供的对应插件中带有展示Demo。

    【A* Pathfinding Project】
    【风宇冲】Unity3D教程宝典之插件篇:Unity3D插件详细评测及教学下载 - 风宇冲 - 风宇冲Unity3D教程学院
    运行效率  
    掌握时间   
    文档教程  
    综合评价  
    使用标准的A star算法,下方提供的对应插件中带有展示Demo。



    六:美术及动画制作 -  风宇冲推荐RageSpline,Smooth Moves
    【Smooth Moves】
    【风宇冲】Unity3D教程宝典之插件篇:Unity3D插件详细评测及教学下载 - 风宇冲 - 风宇冲Unity3D教程学院
    实用性    
    简易度    
    掌握时间  
    文档教程  
    综合评价  
    介绍:神马?你们团队没有做动画的人?那么就用它吧!2D骨骼动画制作插件,不支持Flash。骨骼动画文件可以复用。比帧动画省空间占用。
    优点:动画文件复用,省空间
    缺点:
    使用简介:
    一:制作Atlase (1)Project栏下创建Smooth Moves Texture Atlase Data (2)选中atlase 文件,点击open atlase Editor (3)把素材图往里拖。
    二: 制作Animation  (1)Project栏下创建Smooth Moves Texture Atlase Data (2)选中animation文件,点击open animation Editor (3)点击Bone下面的 ‘+’图标,创建骨骼节点(腰,头,腿,足等等,支持中文)(4)点击Animation Clips下的‘+’,创建动画(站立,行走,攻击等)。(5)选中帧序列界面里的 黄色方块 (6)Type选择Image(Transform就是隐藏,所以通常设置为Image)(7)选择图 (8)选择任意同行的黑块,右键选择Duplicate First Key Frame (9)执行 6-7 (10)然后设置pivot,rotation等信息(11)搞定了!点击play看效果吧!
    【风宇冲】Unity3D教程宝典之插件篇:Unity3D插件详细评测及教学下载 - 风宇冲 - 风宇冲Unity3D教程学院

    【RageSpline】
    【风宇冲】Unity3D教程宝典之插件篇:Unity3D插件详细评测及教学下载 - 风宇冲 - 风宇冲Unity3D教程学院
    实用性   
    简易度   
    综合评价 
    介绍:矢量绘图工具,矢量的好处大家应该都知道,就是不会因为放大而损失质量。 适用于矢量风格的2D游戏以及2D UI的制作。程序会了这个美术就要失业了!
    使用方法: (1)新建一个空的GameObject (2)贴上RageSpline脚本,然后基本形状就出来了 (3)调整形状,具体是 鼠标双击=创建节点 N=圆滑和锋利的边角模式切换 K=削薄边缘 L= 增厚边缘 delete=删除节点 (4)调整边缘颜色outline color 以及填充颜色 Fill Color,大功告成!
    【风宇冲】Unity3D教程宝典之插件篇:Unity3D插件详细评测及教学下载 - 风宇冲 - 风宇冲Unity3D教程学院【风宇冲】Unity3D教程宝典之插件篇:Unity3D插件详细评测及教学下载 - 风宇冲 - 风宇冲Unity3D教程学院

    【Mega-Fiers】
    【风宇冲】Unity3D教程宝典之插件篇:Unity3D插件详细评测及教学下载 - 风宇冲 - 风宇冲Unity3D教程学院
    实用性   
    简易度   
    综合评价 
    介绍:模型变形工具,简单实用,可以用于3D字体的弯曲效果等等。
    使用方法:非常简单, (1)选中要变形的物体,(2)上方菜单Component->Modifiers->Modify Object (3)添加任何预制变形,例如弯曲则是 Component->Modifiers->Bend (4)之后在Inspector里调对应数值即可。

    七:画面增强 -  风宇冲推荐Bitmap2Material,Strumpy Shader Editor
    【Bitmap2Material】
    【风宇冲】Unity3D教程宝典之插件篇:Unity3D插件详细评测及教学下载 - 风宇冲 - 风宇冲Unity3D教程学院
    细节功能  
    运行效率  
    掌握时间   
    文档教程  
    综合评价  
    优点:方便,实用。
    缺点:尚未发现。价格过高【风宇冲】Unity3D教程宝典之插件篇:Unity3D插件详细评测及教学下载 - 风宇冲 - 风宇冲Unity3D教程学院
    使用方法:将包里的Bitmap2Material.sbsar拖进unity工程,然后直接将你的原图拖到下方例图的'Input'上去,它会自动生成法线贴图灰度图等效果图,效果还是不错的。并且支持将随便的一张图制作成Tile图,可以无缝拼接的哦。之后就自己在Insprector里微调吧!
    【风宇冲】Unity3D教程宝典之插件篇:Unity3D插件详细评测及教学下载 - 风宇冲 - 风宇冲Unity3D教程学院【风宇冲】Unity3D教程宝典之插件篇:Unity3D插件详细评测及教学下载 - 风宇冲 - 风宇冲Unity3D教程学院


    【UniSky】
    【风宇冲】Unity3D教程宝典之插件篇:Unity3D插件详细评测及教学下载 - 风宇冲 - 风宇冲Unity3D教程学院

    实用性   
    简易度   
    效果 
        
    兼容性
       
    综合评价 
    优点:云与日月层叠效果逼真,有云起云散
    缺点:缺少下雪等特效,有紫色斑点等BUG。
    介绍:24小时实时 天空盒+天气插件。天气主要是下雨和storm,不过效果一般,建议另外。画面效果不错,不过需要自己去配置, 例如大太阳的天气去下雨肯定不真实,下雨的时候至少要把天空调成阴暗的,有一种乌云密布的感觉。并且天气与地形与单位的互动,需要另外添加,比如溅射到地面的水花等等。月亮放大后在某些显卡下会有紫色斑点。
    使用建议:
    风:Unity的Windzone
    雨:Unity官方Demo《AngryBot》 里面的雨
    使用方法:链接

    【Strumpy Shader Editor】
    【风宇冲】Unity3D教程宝典之插件篇:Unity3D插件详细评测及教学下载 - 风宇冲 - 风宇冲Unity3D教程学院
    可视化   
    实用性   
    简易度   
    综合评价 ★★★★★
    优点:实用,免费
    介绍:渲染器Shader的可视化编辑器,可视化的界面和PlayMaker,uScript用起来差不多。顶点渲染,像素渲染和光照模型渲染三种模式都支持。使用前最好对 三种类型Shader的代码写法有所了解,再使用该工具能起到事半功倍的效果。
    使用方法:(1)插件载入到工程里 (2)菜单Shader Editor->Stumpet Shader Editor。 (3)点击New Graph (4)在图表界面Master右方,右键创建 Tex2D 以及 Sampler2D (4)连线如下 (5)点击Update Graph,之后能看见预览图了 (6)点击Export As,生成Shader文件
    【风宇冲】Unity3D教程宝典之插件篇:Unity3D插件详细评测及教学下载 - 风宇冲 - 风宇冲Unity3D教程学院

    注意:(1)每次改动完需要点Update Graph更新预览。 (2)删除连线:鼠标移动至线上,点击右键
    (3)UV x或y的单变化使用UV_Pan (4)图表视口的移动为 alt + 鼠标左键
    StrumpyShader详细教程

    八:摄像机管理 - 风宇冲推荐 Security Camera
    【Security Camera】
    【风宇冲】Unity3D教程宝典之插件篇:Unity3D插件详细评测及教学下载 - 风宇冲 - 风宇冲Unity3D教程学院
    实用性   
    简易度   
    综合评价 
    优点:简单,实用
    介绍:摄像机管理插。Unity里管理多相机很麻烦,Camera Preview不实用,来回启用禁用也繁琐。Security Camera能快速查看各个相机的实际效果。
    使用方法:插件载入到工程里后,直接把SecurityCamera.cs脚本拖到各个相机上,然后在Game View里就可以直接分开看单个相机的效果了。
    注意:(1)相机不能重名 (2)只有一个主相机,标签tag为'MainCamera'


    【Ultimate FPS Camera】
    【风宇冲】Unity3D教程宝典之插件篇:Unity3D插件详细评测及教学下载 - 风宇冲 - 风宇冲Unity3D教程学院
    介绍:FPS摄像机的控制插件,没什么好说的。工程里导入插件后直接按里面的文档做就行了。

    九:资源包类(Models & Particles)
    综述:这个就不用多说了,好多有用的资源啊,太省事了!
    【Nature Pack】
    介绍:大自然的树,花,草等模型
    【Ruin city】
    介绍:一个被破坏的城市的模型

    【CartoonSnow】
    介绍:卡通雪效果


    十:其他类
    【uniSWF】
    【风宇冲】Unity3D教程宝典之插件篇:Unity3D插件详细评测及教学下载 - 风宇冲 - 风宇冲Unity3D教程学院
    优点:支持元件经典动画(Classic Tween),无需转换成序列帧
    缺点:不支持图元(Shape)形变,转换成序列帧
    介绍:在unity里使用flash的元件(主要是MovieClip)来制作UI什么的,对有Flash开发经验或者Flash资源的可能比较有用。

    【ORK】(Okashi RPG Kit)
    【风宇冲】Unity3D教程宝典之插件篇:Unity3D插件详细评测及教学下载 - 风宇冲 - 风宇冲Unity3D教程学院
    介绍:看了看youtube上的教程视频,ORK没什么意思,它整套的UI包括商店,用的是Unity自带的UI,这整套东西你拿来改还不如自己做好,又快又准又能精确调整。就不评分了。这里仅供下载,没事可以看看,如果有兴趣做RPG的新手可以去下个RPG Maker XP看看它的框架是怎样的。做商业级RPG的还是根据需要自己搭框架吧。

    【Tower Defense ToolKit】
    【风宇冲】Unity3D教程宝典之插件篇:Unity3D插件详细评测及教学下载 - 风宇冲 - 风宇冲Unity3D教程学院
    介绍:不评价了,理由前文有提到过, 仅提供下载。


    还有下面一些主流插件没有找到,欢迎补充。
    【Mixamo】无下载
    介绍: 模型动画插件,500美刀,伤不起啊。不过Unity4的动画系统已经改进很多。所以这个插件不用也罢。
    【Audio Toolkit】无下载
    介绍:音频管理插件,可以提高音效质量。32.5美刀
    【FX Maker】
    介绍:粒子系统库。100美刀
    【Easy Water】
    介绍:水面模型。7.5美刀
    【Easy Touch】
    介绍:触屏控制插件。20美刀
    【MakeYourLevel】
    介绍: 环境模型库。 22.5美刀

                                    第三部分 插件的学习方法

    插件的学习: 学插件有如大侠学武功。先练内功根基,再练上乘武功。内功根基是指 线性代数,计算机图形学,编程基础,Unity基本API等等。基础不要求同学们要有多精通,至少基本的原理和使用要懂。上乘武功是指各种插件。如果内功 根基不扎实而强修秘籍的话,也许会像天龙八部里的鸠摩智一样走火入魔。在游戏开发里,通常表现为卡在一个地方,模模糊糊的怎么都过不去,各种纠结。假如你 遇到了类似情况,建议回过头静下心来温习下相关的基础知识,等过后头脑缓过来了再理理思绪,分析分析条理,一般问题在这个时候就解决了。

    插件的辨别:游戏开发如大侠比武,比的是游戏,武功(插件)不同,实力当然也不同。 好的武功能把你的特性发挥的淋漓尽致,PK有如行云流水。差的武功会让你瞬间被秒杀,无缘Grossing榜。好的插件能很好的和你的项目本身配合,达到 提高开发效率的目的。不好的插件你研究它得花费大量时间又还得花时间,又还得花时间修改调试,很有可能反而会降低效率。所以分辨插件的优劣很重要。我总结 了以下几点,能快速分辨插件的好坏:
    好的插件(1)首先,Asset Store上排名高的一般都好用,什么榜都行,当然还是Top Grossing 最有分量,不好的东西谁愿意付钱呢?如果没有排名就看评价数量和内容吧(2)国内相关介绍讨论比较多的一般都好 (3)教程详细的,特别是有语音高清教程的。
    不好的插件 (1)搜索到的相关信息极少的 (2)无排名,评价少 (3)教程粗糙

    插件的选择: 上乘武功需要专精,令狐冲专精剑法,独孤九剑笑傲江湖,郭靖专精掌法,降龙十八掌威震武林。你不可能把天下所有武功集于一身。Unity开发也是,不可能 所有插件你都精通,只能是选取一些对你用处比较大的插件重点学习使用。所以插件的选择就比较重要了、一般来说比较实用的是单个功能块的插件,比如做UI选 NGUI, 插值控制用iTween, 2D游戏用2D Toolkit等等。而综合类插件就不建议实用了。例如做塔防类游戏的 Tower Defense ToolKit, 做RPG游戏的Okashi RPG Kit,这类插件是专门为做一类游戏而生,集成了很多很多功能,但是每个功能又做不到很专业,所以假如你要用,还得自己改,而这类插件一般定制的调整空间 比较小,目前来说还达不到专业的级别。所以如果你做很专业领域的游戏,比如赛车,有个start kit能节省很多时间,毕竟一辆车有几十上百个参数,通常没有必要自己做物理模型。其他一般的游戏比如塔防,闯关什么的就没必要找个类似start kit的东西了。

    插件的配合:上乘武功则需要配合, 例如张无忌的太极拳+九阳真经+梯云纵+乾坤大挪移。招式太极,内功九阳,轻功梯云纵,能量转移则乾坤。配置组合插件道理也一样,使用什么样的组合就要看游戏本身的定位如何了。假如使用了与游戏定位不符合的插件,效果通常只能事与愿违。例如,做个2D游戏,自然用不到 Bitmap2Material,2D游戏也不需要法线贴图灰度图什么的吧。又如做一款商业级别的移动平台游戏用了iGUI制作UI的话,在 Android和iOS各自的低端机上的表现到最后会让你头疼不已。武侠的世界里,武功会有冲突,例如九阳神功九阴真经不能调和,插件同样也是有冲突的,不尽早发现的话后期面对一堆Bug会让你欲哭无泪的。后文中陆续提到了一些兼容或冲突,有些插件在Asset Store上的介绍也会有相关信息,例如某插件会在介绍里写明与NGUI兼容,与PlayMaker兼容。更多的需要同学们事先了解或者实验出来。本段下方举了插件组合的例子供大家参考。

    2D 横屏动作游戏 :2D Toolkit + NGUI
    3D 第一人称射击 :NGUI + Simple Path + Bitmap2Material + PlayMaker + Security Camera + Stumpy Shader Editor
    独立开发2D游戏:(1)Photoshop/Illustrator等外部绘图软件 + Smooth Moves + NGUI
    (2)RageSpline + 2D Toolkit + NGUI
    简易非商业开发:iGUI + iTween
    塔防游戏: iTween/ Simple Path + NGUI  +其他
                
    展开全文
  • 先上几张效果图: 如果你需要的也是这种效果,那你就来对地方了! ...目前,我们这个形菜单展现出来的功能如下: ...3、可以单独判断某一元素的复选框是否被勾选...4、形菜单统一控制其下所有子元素按钮的事件...

    先上几张效果图:

            

     

    如果你需要的也是这种效果,那你就来对地方了!

     

    目前,我们这个树形菜单展现出来的功能如下:

    1、可以动态配置数据源;

    2、点击每个元素的上下文菜单按钮(也就是图中的三角形按钮),可以收缩或展开它的子元素;

    3、可以单独判断某一元素的复选框是否被勾选,或者直接获取当前树形菜单中所有被勾选的元素;

    4、树形菜单统一控制其下所有子元素按钮的事件分发;

    5、可自动调节的滚动视野边缘,根据当前可见的子元素数量进行横向以及纵向的伸缩;

     

    一、首先,我们先制作子元素的模板(Template),也就是图中菜单的单个元素,用它来根据数据源动态克隆出多个子元素,这里的话,很显然我们的模板是由两个Button加一个Toggle和一个Text组成的,如下:

     

    ContextButton    TreeViewToggle     TreeViewButton(TreeViewText)

     

     

    图中的text是一个文本框,用于描述此元素的名称或内容,它们对应的结构就是这样:

     

     

    二、我们的每个子元素都会携带一个TreeViewItem脚本,用于描述自身在整个树形菜单中与其他元素的父子关系,而整个树形菜单的控制由TreeViewControl来实现,首先,TreeViewControl会根据提供的数据源来生成所有的子元素,当然,改变数据源之后进行重新生成的时候也是这个方法,干的事情很简单,就是用模板不停的创建元素,并给他们建立父子关系:

     

    /// <summary>
        /// 生成树形菜单
        /// </summary>
        public void GenerateTreeView()
        {
            //删除可能已经存在的树形菜单元素
            if (_treeViewItems != null)
            {
                for (int i = 0; i < _treeViewItems.Count; i++)
                {
                    Destroy(_treeViewItems[i]);
                }
                _treeViewItems.Clear();
            }
            //重新创建树形菜单元素
            _treeViewItems = new List<GameObject>();
            for (int i = 0; i < Data.Count; i++)
            {
                GameObject item = Instantiate(Template);
    
                if (Data[i].ParentID == -1)
                {
                    item.GetComponent<TreeViewItem>().SetHierarchy(0);
                    item.GetComponent<TreeViewItem>().SetParent(null);
                }
                else
                {
                    TreeViewItem tvi = _treeViewItems[Data[i].ParentID].GetComponent<TreeViewItem>();
                    item.GetComponent<TreeViewItem>().SetHierarchy(tvi.GetHierarchy() + 1);
                    item.GetComponent<TreeViewItem>().SetParent(tvi);
                    tvi.AddChildren(item.GetComponent<TreeViewItem>());
                }
    
                item.transform.name = "TreeViewItem";
                item.transform.FindChild("TreeViewText").GetComponent<Text>().text = Data[i].Name;
                item.transform.SetParent(TreeItems);
                item.transform.localPosition = Vector3.zero;
                item.transform.localScale = Vector3.one;
                item.transform.localRotation = Quaternion.Euler(Vector3.zero);
                item.SetActive(true);
    
                _treeViewItems.Add(item);
            }
        }

     

     

     

     

     

    三、树形菜单生成完毕之后此时所有元素虽然都记录了自身与其他元素的父子关系,但他们的位置都是在Vector3.zero的,毕竟我们的菜单元素在创建的时候都是一股脑儿的丢到原点位置的,创建君可不管这么多元素挤在一堆会不会憋死,好吧,之后规整列队的事情就交给刷新君来完成了,刷新君玩的一手好递归,它会遍历所有元素并剔除不可见的元素(也就是点击三角按钮隐藏了),并将它们一个一个的重新排列整齐,子排在父之后,孙排在子之后,以此类推......它会遍历每个元素的子元素列表,发现子元素可见便进入子元素列表,发现孙元素可见便进入孙元素列表:

     

    /// <summary>
        /// 刷新树形菜单
        /// </summary>
        public void RefreshTreeView()
        {
            _yIndex = 0;
            _hierarchy = 0;
    
            //复制一份菜单
            _treeViewItemsClone = new List<GameObject>(_treeViewItems);
    
            //用复制的菜单进行刷新计算
            for (int i = 0; i < _treeViewItemsClone.Count; i++)
            {
                //已经计算过或者不需要计算位置的元素
                if (_treeViewItemsClone[i] == null || !_treeViewItemsClone[i].activeSelf)
                {
                    continue;
                }
    
                TreeViewItem tvi = _treeViewItemsClone[i].GetComponent<TreeViewItem>();
    
                _treeViewItemsClone[i].GetComponent<RectTransform>().localPosition = new Vector3(tvi.GetHierarchy() * HorizontalItemSpace, _yIndex,0);
                _yIndex += (-(ItemHeight + VerticalItemSpace));
                if (tvi.GetHierarchy() > _hierarchy)
                {
                    _hierarchy = tvi.GetHierarchy();
                }
    
                //如果子元素是展开的,继续向下刷新
                if (tvi.IsExpanding)
                {
                    RefreshTreeViewChild(tvi);
                }
    
                _treeViewItemsClone[i] = null;
            }
    
            //重新计算滚动视野的区域
            float x = _hierarchy * HorizontalItemSpace + ItemWidth;
            float y = Mathf.Abs(_yIndex);
            transform.GetComponent<ScrollRect>().content.sizeDelta = new Vector2(x, y);
    
            //清空复制的菜单
            _treeViewItemsClone.Clear();
        }
        /// <summary>
        /// 刷新元素的所有子元素
        /// </summary>
        void RefreshTreeViewChild(TreeViewItem tvi)
        {
            for (int i = 0; i < tvi.GetChildrenNumber(); i++)
            {
                tvi.GetChildrenByIndex(i).gameObject.GetComponent<RectTransform>().localPosition = new Vector3(tvi.GetChildrenByIndex(i).GetHierarchy() * HorizontalItemSpace, _yIndex, 0);
                _yIndex += (-(ItemHeight + VerticalItemSpace));
                if (tvi.GetChildrenByIndex(i).GetHierarchy() > _hierarchy)
                {
                    _hierarchy = tvi.GetChildrenByIndex(i).GetHierarchy();
                }
    
                //如果子元素是展开的,继续向下刷新
                if (tvi.GetChildrenByIndex(i).IsExpanding)
                {
                    RefreshTreeViewChild(tvi.GetChildrenByIndex(i));
                }
    
                int index = _treeViewItemsClone.IndexOf(tvi.GetChildrenByIndex(i).gameObject);
                if (index >= 0)
                {
                    _treeViewItemsClone[index] = null;
                }
            }
        }


    我这里将所有的元素复制了一份用于计算位置,主要就是为了防止在进行一轮刷新时某个元素被访问两次或以上,因为刷新的时候会遍历所有可见元素,如果第一次访问了元素A(元素A的位置被刷新),根据元素A的子元素列表访问到了元素B(元素B的位置被刷新),一直到达子元素的底部后,当不存在更深层次的子元素时,那么返回到元素A之后的元素继续访问,这时在所有元素列表中元素B可能在元素A之后,也就是说元素B已经通过父元素访问过了,不需要做再次访问,他的位置已经是最新的了,而之后根据列表索引很可能再次访问到元素B,如果是这样的话元素B的位置又要被刷新一次,甚至多次,性能影响不说,第二次计算的位置已经不是正确的位置了(总之也就是一个计算逻辑的问题,没看明白可以直接忽略)。

     

     

    四、菜单已经创建完毕并且经过了一轮刷新,此时它展示出来的就是这样一个所有子元素都展开的形状(我在demo中指定了数据源,关于数据源怎么设置在后面):

     

     

    我们要在每个元素都携带的脚本TreeViewItem中对自身的那个三角形的上下文按钮监听,当鼠标点击它时它的子元素就会被折叠或者展开:

     

    /// <summary>
        /// 点击上下文菜单按钮,元素的子元素改变显示状态
        /// </summary>
        void ContextButtonClick()
        {
            if (IsExpanding)
            {
                transform.FindChild("ContextButton").GetComponent<RectTransform>().localRotation = Quaternion.Euler(0, 0, 90);
                IsExpanding = false;
                ChangeChildren(this, false);
            }
            else
            {
                transform.FindChild("ContextButton").GetComponent<RectTransform>().localRotation = Quaternion.Euler(0, 0, 0);
                IsExpanding = true;
                ChangeChildren(this, true);
            }
    
            //刷新树形菜单
            Controler.RefreshTreeView();
        }
        /// <summary>
        /// 改变某一元素所有子元素的显示状态
        /// </summary>
        void ChangeChildren(TreeViewItem tvi, bool value)
        {
            for (int i = 0; i < tvi.GetChildrenNumber(); i++)
            {
                tvi.GetChildrenByIndex(i).gameObject.SetActive(value);
                ChangeChildren(tvi.GetChildrenByIndex(i), value);
            }
        }


    IsExpanding做为每个元素的字段用于设置或读取自身子元素的显示状态,这里根据改变的状态会递归循环此元素的所有子元素及孙元素,让他们可见或隐藏。

     

     

     

     

    五、对所有的子元素进行统一的事件分发,这里主要就有鼠标点击这一个事件:

     

    每个元素都会注册这个事件:(TreeViewItem.cs)

     

    void Awake()
        {
            //上下文按钮点击回调
            transform.FindChild("ContextButton").GetComponent<Button>().onClick.AddListener(ContextButtonClick);
            transform.FindChild("TreeViewButton").GetComponent<Button>().onClick.AddListener(delegate () {
                Controler.ClickItem(gameObject);
            });
        }

    树形菜单控制器统一分发:(TreeViewControl.cs)

     

     

    public delegate void ClickItemdelegate(GameObject item);
        public event ClickItemdelegate ClickItemEvent;
    
    /// <summary>
        /// 鼠标点击子元素事件
        /// </summary>
        public void ClickItem(GameObject item)
        {
            ClickItemEvent(item);
        }

     


    六、获取元素的复选框状态判断是否被勾选:

     

     

     

    根据元素名称进行筛选,获取此元素的选中状态,如果存在同名元素的话这个可能不好使:

     

    /// <summary>
        /// 返回指定名称的子元素是否被勾选
        /// </summary>
        public bool ItemIsCheck(string itemName)
        {
            for (int i = 0; i < _treeViewItems.Count; i++)
            {
                if (_treeViewItems[i].transform.FindChild("TreeViewText").GetComponent<Text>().text == itemName)
                {
                    return _treeViewItems[i].transform.FindChild("TreeViewToggle").GetComponent<Toggle>().isOn;
                }
            }
            return false;
        }


    返回树形菜单中所有被勾选的子元素名称集合:

     

     

    /// <summary>
        /// 返回树形菜单中被勾选的所有子元素名称
        /// </summary>
        public List<string> ItemsIsCheck()
        {
            List<string> items = new List<string>();
    
            for (int i = 0; i < _treeViewItems.Count; i++)
            {
                if (_treeViewItems[i].transform.FindChild("TreeViewToggle").GetComponent<Toggle>().isOn)
                {
                    items.Add(_treeViewItems[i].transform.FindChild("TreeViewText").GetComponent<Text>().text);
                }
            }
    
            return items;
        }

     

     


    七、接下来是我们的数据格式TreeViewData,树形菜单的数据源是由这个格式组成的集合:

     

     

    /// <summary>
        /// 当前树形菜单的数据源
        /// </summary>
        [HideInInspector]
        public List<TreeViewData> Data = null;


    每一个TreeViewData代表一个元素,Name为显示的文本内容,ParentID为它指向的父元素在整个数据集合中的索引,从0开始,-1代表不存在父元素的根元素,当然有时候数据源并不是这个样子的,可能是XML,可能是json,不过都可以通过解析数据源之后再变换成这种方式:

     

     

    /// <summary>
    /// 树形菜单数据
    /// </summary>
    public class TreeViewData
    {
        /// <summary>
        /// 数据内容
        /// </summary>
        public string Name;
        /// <summary>
        /// 数据所属的父ID
        /// </summary>
        public int ParentID;
    }

     

     

    八、属性面板的参数:

    Template:当前树形菜单的元素模板;

    TreeItems:当前树形菜单的元素根物体,自动指定的,这个别去动;

    VerticalItemSpace:相邻元素之间的纵向间距;

    HorizontalItemSpace:不同层级元素之间的横向间距;

    ItemWidth:元素的宽度,若自行修改过Template,这里的值需要自己去计算Template的大概宽度;

    ItemHeight:元素的高度,若自行修改过Template,这里的值需要自己去计算Template的大概高度;

     


    九、我已经将TreeView打包成了一个插件,在Unity中导入他,便可以直接使用TreeView:

     

    导入TreeView.unitypackage以后,先在场景中创建一个Canvas(画布),然后右键直接创建TreeView:

     

     

    之后在其他脚本中拿到这个TreeView,直接为他指定数据源(我这里是手动生成,篇幅有点长):

     

    //生成数据
            List<TreeViewData> datas = new List<TreeViewData>();
    
            TreeViewData data = new TreeViewData();
            data.Name = "第一章";
            data.ParentID = -1;
            datas.Add(data);
    
            data = new TreeViewData();
            data.Name = "1.第一节";
            data.ParentID = 0;
            datas.Add(data);
    
            data = new TreeViewData();
            data.Name = "1.第二节";
            data.ParentID = 0;
            datas.Add(data);
    
            data = new TreeViewData();
            data.Name = "1.1.第一课";
            data.ParentID = 1;
            datas.Add(data);
    
            data = new TreeViewData();
            data.Name = "1.2.第一课";
            data.ParentID = 2;
            datas.Add(data);
    
            data = new TreeViewData();
            data.Name = "1.1.第二课";
            data.ParentID = 1;
            datas.Add(data);
    
            data = new TreeViewData();
            data.Name = "1.1.1.第一篇";
            data.ParentID = 3;
            datas.Add(data);
    
            data = new TreeViewData();
            data.Name = "1.1.1.第二篇";
            data.ParentID = 3;
            datas.Add(data);
    
            data = new TreeViewData();
            data.Name = "1.1.1.2.第一段";
            data.ParentID = 7;
            datas.Add(data);
    
            data = new TreeViewData();
            data.Name = "1.1.1.2.第二段";
            data.ParentID = 7;
            datas.Add(data);
    
            data = new TreeViewData();
            data.Name = "1.1.1.2.1.第一题";
            data.ParentID = 8;
            datas.Add(data);
    
            //指定数据源
            TreeView.Data = datas;


    然后生成树形菜单,连带刷新一次:

     

     

    //重新生成树形菜单
            TreeView.GenerateTreeView();
            //刷新树形菜单
            TreeView.RefreshTreeView();


    然后注册子元素的鼠标点击事件(委托类型为返回值void,带一个Gameobject类型参数,参数item为被鼠标点中的那个元素的gameobject):

     

     

    //注册子元素的鼠标点击事件
            TreeView.ClickItemEvent += CallBack;
    
    void CallBack(GameObject item)
        {
            Debug.Log("点击了 " + item.transform.FindChild("TreeViewText").GetComponent<Text>().text);
        }


    以及要获取某一元素的勾选状态:

     

     

    bool isCheck = TreeView.ItemIsCheck("第一章");
                Debug.Log("当前树形菜单中的元素 第一章 " + (isCheck?"已被选中!":"未被选中!"));


    和获取所有被勾选的元素:

     

     

    List<string> items = TreeView.ItemsIsCheck();
                for (int i = 0; i < items.Count; i++)
                {
                    Debug.Log("当前树形菜单中被选中的元素有:" + items[i]);
                }

     

     


    效果图如下:

     

    源码链接:http://download.csdn.net/detail/qq992817263/9750031

     

     

     

    展开全文
  • Unity树形结构

    2016-07-28 18:48:47
    插件名称: Script Based Runtime Tree-View Control v1.1前面我有写过一篇关于unity树形结构插件的基本使用,可以动态的创建,并且为这个绑定方法这篇文章我们接着讨论,如何实现点击某个节点,其下所有的子孙...

    插件名称: Script Based Runtime Tree-View Control v1.1


    前面我有写过一篇关于unity树形结构插件的基本使用,可以动态的创建树,并且为这个树绑定方法


    这篇文章我们接着讨论,如何实现点击某个节点,其下所有的子孙节点全部勾选或全部不勾选


    我们通过CreateObject创建一个节点时,会返回一个FoldObject对象,通过这个对象的Obj就可以拿到场景面板中的该节点对象


    这里写图片描述


    这篇文章非常重要的要理解和运用好FoldObject对象的Obj属性,Obj是场景中对象,FoldObject是插件中的对象,此对象封装了Obj,注意我的用词是封装



    这里写图片描述


    这里写图片描述


    这里写图片描述


    最终截图:
    这里写图片描述


    FR:徐海涛(www.xuhaitao123.com)

    展开全文
  • unity3d TreeView Control

    2020-07-11 23:31:13
    unity3d中显示控件,代码可使用在Editor上,也可以使用在游戏场景中作为UI使用。
  • 之前在项目中多次用到目录,由于UGUI没有目录这样组件,需要我们拿基础的UI去拼凑,但是这样拼凑的目录一般需要制作为预制物,在我们想要迁移到别的工程时,总是因为打包且少资源而产生一些问题。而且很多新手...
  • Unity3D界面介绍及入门

    2014-05-25 11:48:37
    首先,你可以在unity3d官网(http://unity3d.com/)下载新版本的软件,本文中使用的是unity3d 4.0.标准版是不支持阴影的,只有专业版才支持,所以对于效果要求较高的读者,可以选择购买正版,不要使用盗版或者破解版,...
  • Unity3D知识体系

    2020-06-30 08:45:44
    Unity3D知识
  • 如果你接触过《设计模式》、软件架构的编程思想,就会知道优秀的设计准则:“组合优于继承的”。 这句话很简短,但开始学习OOP的时候,真切的是—-不太好理解(以我个人当初学习为例)。
  • 前言考虑到工业项目中可能会利用到类似日历的工具,就比如选取某个时间节点,所以我结合UGUI源码开发了日历工具和日期拾取器工具,简单易用,接口齐全,可中文显示,外观可自定义。只需要导入脚本,即可在Hierarchy...
  • 概要 撰写原因:当今市面上关于Unity的教程的...针对人群:有任意一门静态编程语言基础的(C||C++||Java||C#),对Unity引擎了解的(文主要讲解C#代码的编写,对于引擎里需要拖控件完成的工作不会有太多涉及) 编
  • 11 | 如何测试基于Unity3D引擎的游戏 由于游戏的界面是通过游戏引擎渲染出来的,游戏界面没有系统原生的控件信息,所以对于游戏,我们需要接入Poco-SDK才能获取到游戏界面中的控件信息。下面以Unity开发的手游为...
  • 工具栏:变换工具、gizmos切换、播放控件、层列表、布局列表 功能窗口 2、资源及资源类型:在project里面能够create的资源。project面板可以对资源进行组织管理,创建资源,搜索资源。 3、模型和角色动画: 角色动画...
  • Unity3D坦克大战

    2014-10-19 16:14:53
    因为接触Unity时间不是特别久,所以这里先帖出早期开发的C#游戏,然后再帖Unity游戏。 另外提醒,我的所有作品都是自己开发的,绝无抄袭(程序代码和编程思想绝没超抄过别人的),最多也就是高仿别人的游戏...
  • 1.以下哪一个选项不属于Unity引擎所支持的视频格式文件? 【D】 后缀名为mov的文件 后缀名为mpg的文件 后缀名为avi的文件 后缀名为swf的文件 2. HDR高动态光照渲染属于下列哪个选项的属性? 【D】 Lightmapping...
  • Unity3D 脚本参考

    2012-02-01 09:06:56
    Unity3D 脚本参考 核心提示:一、脚本概览这是一个关于Unity 内部脚本如何工作的简单概览。Unity 内 部的脚本,是通过附加自定义脚本对象到游戏物体组成的。在脚本对象内部不同志的函数被 特定的事件调用。最常用...
  • 一、前言 发现就喜欢研究这些插件,为什么...要不说Unity3D入门容易,提升难呢,因为提升全是靠苦功夫,去研究底层代码。算了,不絮叨了 二、参考文章 Unity3D 装备系统学习Inventory Pro 2.1.2 总结 Unity3D...
1 2 3 4 5 ... 20
收藏数 628
精华内容 251
热门标签