2019-10-13 18:38:21 qq_36704494 阅读数 70
  • Unity3D的UI系统(UGUI)初级入门

    本课程主要介绍Unity3d的UI系统(UGUI),先对UGUI做一个总体概述,之后对每个UI控件逐一进行详细讲述,内容包括控件的作用、设置方法、使用场景及属性细节,帮助大家熟练使用UGUI设计游戏的交互界面。

    985 人正在学习 去看看 伍晓波

基于UGUI的Unity画线工具

最近项目里需要做一个画线的小游戏,LineRenderer不是很好用,自己撸了一个小工具,效果如下
画线例子

下面上代码

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using FMCShape;

    public class MyLineDrawer : Image
    {
        public List<Vector2> pointer = new List<Vector2>();
        public float radio = 30;
        private int headPointCount = 7;//头部顶点数量
        private Vector2 offset;
        protected override void Awake()
        {
            base.Awake();
            offset = new Vector2(Screen.width * 0.5f, Screen.height * 0.5f);
        }
        protected override void OnPopulateMesh(VertexHelper toFill)
        {
            toFill.Clear();
            if (pointer.Count >= 2)
            {
                for (int i = 1; i < pointer.Count; i++)
                {
                    Draw(toFill, pointer[i - 1], pointer[i]);
                }
            }
        }
        public void AddPointer(Vector2 pointer)
        {
            this.pointer.Add(pointer);
            ReDraw();
        }
        public void ReDraw()
        {
            SetVerticesDirty();
        }
        void Draw(VertexHelper vh, Vector2 start, Vector2 end)
        {
            Vector2 to = end - start;
            Vector2 nor_to = to.normalized * radio + start;
            Vector2 up = MathHepler.RotateVector2(90, nor_to, start);
            Vector2 down = MathHepler.RotateVector2(-90, nor_to, start);
            Vector2 up_end = up + to;
            Vector2 down_end = down + to;
            //添加直线
            AddQuad(vh, up, down, up_end, down_end);
            List<Vector2> tempPointer = ListPool<Vector2>.Get();
            //添加左边头部
            float angel = 180 / (headPointCount + 1);
            tempPointer.Add(down);
            for (float i = -angel; i > -180; i -= angel)
            {
                tempPointer.Add(MathHepler.RotateVector2(i, down, start));
            }
            tempPointer.Add(up);

            for (int i = 1; i < tempPointer.Count; i++)
            {
                AddVert(vh, tempPointer[i - 1], tempPointer[i], start);
            }
            //添加右边头部
            tempPointer.Clear();
            tempPointer.Add(up_end);
            for (float i = -angel; i > -180; i -= angel)
            {
                tempPointer.Add(MathHepler.RotateVector2(i, up_end, end));
            }
            tempPointer.Add(down_end);
            for (int i = 1; i < tempPointer.Count; i++)
            {
                AddVert(vh, tempPointer[i - 1], tempPointer[i], end);
            }
            ListPool<Vector2>.Release(tempPointer);
        }

        void AddVert(VertexHelper vh, Vector2 pos1, Vector2 pos2, Vector2 pos3)
        {
            AddVert(vh, CreateEmptyVertex(pos1), CreateEmptyVertex(pos2), CreateEmptyVertex(pos3));
        }
        void AddVert(VertexHelper vh, UIVertex v1, UIVertex v2, UIVertex v3)
        {
            int index = vh.currentVertCount;
            vh.AddVert(v1);
            vh.AddVert(v2);
            vh.AddVert(v3);
            vh.AddTriangle(index, index + 1, index + 2);
        }
        void AddQuad(VertexHelper vh, Vector2 pos1, Vector2 pos2, Vector2 pos3, Vector2 pos4)
        {
            AddQuad(vh, CreateEmptyVertex(pos1), CreateEmptyVertex(pos2), CreateEmptyVertex(pos3), CreateEmptyVertex(pos4));
        }
        void AddQuad(VertexHelper vh, UIVertex v1, UIVertex v2, UIVertex v3, UIVertex v4)
        {
            int index = vh.currentVertCount;
            vh.AddVert(v1);
            vh.AddVert(v2);
            vh.AddVert(v3);
            vh.AddVert(v4);
            vh.AddTriangle(index, index + 1, index + 2);
            vh.AddTriangle(index + 2, index + 3, index + 1);
        }
        UIVertex CreateEmptyVertex(Vector2 pos)
        {
            UIVertex v = new UIVertex();
            v.position = pos;
           //需要修改颜色,在这里改就可以了
            v.color = color;
            v.uv0 = Vector2.zero;
            return v;
        }
}

使用时当做一个image就可以,代码如下

    public MyLineDrawer line;
    private void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            line.AddPointer(Input.mousePosition-new Vector3(540,960));
        }
    }
2015-06-03 16:04:28 xhyzdai 阅读数 13910
  • Unity3D的UI系统(UGUI)初级入门

    本课程主要介绍Unity3d的UI系统(UGUI),先对UGUI做一个总体概述,之后对每个UI控件逐一进行详细讲述,内容包括控件的作用、设置方法、使用场景及属性细节,帮助大家熟练使用UGUI设计游戏的交互界面。

    985 人正在学习 去看看 伍晓波

刚开始学Unity3D,最近在看UI这一块,使用Unity编辑器进行事件绑定,总感觉怪怪的,不如使用代码进行监听来得直观。

首先是资源层次结构


然后在Panel上挂Test脚本,脚本里使用委托进行事件监听

using UnityEngine;
using UnityEngine.UI;

public class Test : MonoBehaviour
{
    private GameObject buttonObj;
    private GameObject toggleObj;
    private GameObject toggleGroupObj;
    private Button button;
    private Toggle toggle;
    private ToggleGroup toggleGroup;

    void Awake()
    {
        buttonObj = gameObject.transform.FindChild("Button").gameObject;
        toggleObj = gameObject.transform.FindChild("Toggle").gameObject;
        toggleGroupObj = gameObject.transform.FindChild("ToggleGroup").gameObject;
        button = buttonObj.GetComponent<Button>();
        toggle = toggleObj.GetComponent<Toggle>();
        toggleGroup = toggleGroupObj.GetComponent<ToggleGroup>();
    }

    void Start()
    {
        //lambda表达式转换为委托类型
        toggle.onValueChanged.AddListener((bool value) => OnToggleClick(toggle, value));

        //匿名委托调用
        button.onClick.AddListener(delegate()
        {
            Debug.Log("toggle is " + (toggle.isOn ? "On" : "Off"));
        });
    }

    public void OnToggleClick(Toggle toggle, bool value)
    {
        Debug.Log("toggle change " + (value ? "On" : "Off"));
    }
}





2017-04-03 16:52:19 xxxhhhyxy 阅读数 874
  • Unity3D的UI系统(UGUI)初级入门

    本课程主要介绍Unity3d的UI系统(UGUI),先对UGUI做一个总体概述,之后对每个UI控件逐一进行详细讲述,内容包括控件的作用、设置方法、使用场景及属性细节,帮助大家熟练使用UGUI设计游戏的交互界面。

    985 人正在学习 去看看 伍晓波

这一节将主要讲述所有UGUI物体的排布属性RectTransform,熟练运用这个组件,能够让你的UGUI Demo永远排布美观。

5. Rect Transform

对于任意创建好的UGUI物体,它的位姿属性全由RectTransform决定,这和一般的GameObject物体由Transform决定有所区别,本节以Image为例:


每次创建UGUI控件,画布上都还有四片三角形组成的图案,其实那是4个Anchor(锚点),每个三角形都可单独拖动,默认会出现在该UGUI物体的父物体的正中央。

①  Anchor Presets-这是左图被红框圈起的部分,只有点开来才能看明全貌。通过它可以直接强行定位Anchor的排布。


A) 将4片Anchor分为左右两组,则横向上可以将之都分布在极左、正中、极右,或者左右各安置一组;将锚点分为上下两组,则纵向上可以将之都分布在最上、正中、最下,或者上下边各一组。——这里的极左、极右等等指的都是父物体的边界。

4*4=16,所以锚点有16种极端排布的样式,正如上图所示。

B)选中不同排布时,黄色框内的东西会不一样:

    当选中左上方的9中排布方式时,4片Anchor是聚拢在一起的,此时可以调整Image中心相对于Anchor的坐标(PosX,PosY,PosZ)和其尺寸(Width,Height)。

    当选中最右一列的排布方式时,4片Anchor将会左右分离,因此Anchor不再具有确切的X坐标,Image的宽度将由其左右边界到两边Anchor的横向距离(Left,Right)决定。

    当选中最下一行的排布方式时,4片Anchor将会上下分离,因此Anchor不再具有确切的Y坐标,Image的高度由其上下边界到两端Anchor的纵向距离(Top,Bottom)决定。

  

② Anchors-这是当前UGUI物体的Anchor所框选的区域,相对于父物体边界的比例值。

下图中的Min X=0,Y=0;Max X=0,Y=1是对应上方右边图片的值。代表Anchor分为上下两组,形成一条和父物体左边界重合的竖线。


倘若要制作一个纵向手机APP的Title,可以尝试将

Min X=0,Y=0.9;Max X=1,Y=1,然后由于四片Anchor完全分开,所以可以将Image的Transform值手动地设置为(Left,Right,Top,Bottom)=(0,0,0,0)。结果将如下图所示:


③  Pivot-中心点,代表的是该UGUI物体的中心位于何处,当四片Anchor聚合在父物体正中央时,在Game视窗中的Image,其高度宽度都是250。

左边图是Pivot X=Y=0.5的情况;右边是Pivot X=0.5,Y=1的情况,Pos Y已经被莫名其妙改成了125,也就是高度的一半。

Pivot默认在UGUI空间的正中央,Y=1会强制将中心点上移至顶端,所以出现了这类情况。

    

④  Rotation和Scale,与常规的GameObject并无出入,这里讲一下在UGUI中的使用要点:

     Rotation:当我们改变Z值,那么Image将会绕着Pivot中心点、平行于电脑屏幕进行旋转度,可是如果我们如③所示,改变了Pivot的位置……那么旋转中心也会相应改变。

     Scale:是这里建议大家不要乱动Scale,因为UGUI物体的尺寸完全可以由Width、Height之类的东西来改变。Scale和Width、Height是完全独立的两套体系,改动Scale将会使UGUI物体在程序内部和显示上出现矛盾。例如将Scale的X设为2,肉眼可见图片宽度成为原先的2倍,但是上方的Width却没有改变,这对于日后UGUI物体的位置改写是很不利的。


代码演示:

using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class teachRect : MonoBehaviour {
    public Image m_img;
    float timeCounter = 0;
	// Use this for initialization
	void Start () {
	
	}
	
	// Update is called once per frame
	void Update () {
        if (timeCounter <= 3)
        {
            m_img.transform.Rotate(0, 0,120 * Time.deltaTime);
            timeCounter += Time.deltaTime;
        }
        else
        {
            timeCounter = 0;
            m_img.rectTransform.pivot = new Vector2(0, 0);
        }
    }
}

演示如下

可以发现旋转中心确实变了,但是为什么图片的位置也变了呢?

因为我只用代码改变了旋转中心,而UGUI在系统运行时Rect Transform似乎只会因为代码而改变。所以Image的Pos X,Pos Y,Pos Z依然是原先的值(0,0,0),也就是说程序运行的所有时间内,Anchor和Pivot一直是重合的,对于图片来说是Pivot挪到了左下角,但是对于Pivot来说,是图片网右上方挪动,而并没有影响Pivot自己。

而在停止运行的编辑界面下,改动Pivot,Position的值会如③所述、根据Pivot和(width,heigth)而自适应改变的哦。

运行前   

运行3秒后:

编辑模式下:

2017-12-21 18:36:42 hanxiaoyuan32 阅读数 822
  • Unity3D的UI系统(UGUI)初级入门

    本课程主要介绍Unity3d的UI系统(UGUI),先对UGUI做一个总体概述,之后对每个UI控件逐一进行详细讲述,内容包括控件的作用、设置方法、使用场景及属性细节,帮助大家熟练使用UGUI设计游戏的交互界面。

    985 人正在学习 去看看 伍晓波

Unity3D UGUI

User Interface 用户界面

GUI:优点使用简单,有专一性。缺点:代码繁琐,屏幕自适应差。

常用来当调试工具,还有editor编辑器的开发

UGUI:亲儿子,优点:使用灵活。层级清晰。屏幕自适应。缺点:宽度,高度自适应只有一种。Canvas不容易理解,RectTransform不直观。

NGUI:第三方插件,优点:使用方便(大多功能已集成),自带ITween插件。缺点:层级深度调整困难,不打包图集2d图片无法使用。

UGUINGUI目前使用较多,但新项目大多使用UGUINGUI在老项目中使用。

UGUI属性:

共有属性

UGUI的渲染顺序是通过排列顺序决定的,谁在hierarchy后面,谁就在屏幕的前面

代码实现:

Pivot UI的轴心点 ,决定位置和旋转的中心点,0,0 UI控件的左下角,右上角为1,1。该值为比例。

unity左上角pivot改成center后,UI就不显示pivot,而只显示比例中心,此时UI会按照比例中心旋转,用代码来旋转是旋转的pivot,而不是比例中心。)

没有transform,而是其子类RectTransform

获取RectTransform的方式,可以通过getComponent获取,或者transform as RectTransform强制转换获得。

Width,height UI的宽和高,数值不能为负数

Posx posy 值是以锚点为中心的自身坐标系,如果锚点被拆分开后,posxy会被lefttop,right,bottom替代,四个值都是到拆分锚点组合的图形的四边的距离,0000会占满锚点组合的图形。此时坐标原点是锚点组成的图形的中心点。

子物体的锚点最大范围就是父物体的大小

Anchors锚点:min,max都为00在左下角,1,1,在左上角,min是锚点左下角的锚点,max是右上角的锚点

Ui控件的transform.positiom就是世界坐标的点, localposition的原点也不是锚点,而是父物体的中心点。

Ui控件的transform.positiomlocalposition都是transform组件

获取锚点的中心点使用RectTransform对象.anchoredPosition

anchoredPosition是物体到锚点四条边的距离

Canvas

画布负责管理当前属于canvas的所有UI控件,UI只有在canvas下才能可见。

Canvas就是游戏屏幕大小,不能单独调整。

画布可以有多个。

如果canvas选成camera模式(让摄像机渲染ui),camera正交投影高度为图片screen.height/2/piexperunit(100)

UI Scaler mode :

Const 自由比例下不会改变ui元素的大小。

Canvas的缩放系数:缩放系数是在原有基础上的像素大小缩放的,小数是扩大,正数才是缩小的,内部进行的缩放方式是除法的操作。但此时无论缩放,ui控件的大小widthheight属性始终是真实宽高,不受缩放影响。

所以,任何对UI控件大小的处理,一定要乘以缩放系数。

Scale with screen size:

根据屏幕的一边(高度,或者宽度,不能同时)做自适应缩放元素ui,一般以高度自适应,宽度自己写适应

设定缩放的分辨率比例。手机常用比例:960*640

 

Canvas的渲染方式:

1、 camera方式:

判断出界:

鼠标拖动:此时世界坐标系和canvas的坐标原点重合,所以ui的世界坐标就是在屏幕上的位置,所以只要将鼠标位置转化成世界坐标给uitransform.position就可以实现拖动。

2、 overlay方式:

判断出界:transform.x<-(rec.rect.width/2+screen.width/2);

鼠标拖动:此时世界坐标和屏幕坐标的原点重合,世界坐标和屏幕坐标是一样的,所以只要将鼠标的屏幕坐标直接给transform.position即可实现鼠标拖动。

3、 真实的鼠标拖动:

上述办法只能一旦拖动,图片的中心就会变成鼠标位置,为了实现真实的拖动,其实只要计算出拖动位置和中心点的距离,然后实时判断该距离的增量,让中心点也就是transform.position加上增量既可以实现。

代码仅适用于overlay的方式,camera方式需要先将鼠标点击和实时位置转成世界坐标

public class tuodong : MonoBehaviour,IDragHandler,IPointerDownHandler {

    public Image img;

    Vector2 dian;

    Vector2 dian1;

    Vector3 v3;

 

    public void OnDrag(PointerEventData eventData) {

        dian1 = eventData.position;

 

Vector3 vv = new Vector3(dian1.x -transform.position.x- v3.x, dian1.y - transform.position.y- v3.y, transform.position.z);算出固定距离发生的增量

         transform.position += vv;

    }

 

    public void OnPointerDown(PointerEventData eventData) {

        dian = eventData.position;

v3 = new Vector3(dian.x - transform.position.x, dian.y - transform.position.y, transform.position.z);//先用点击位置判断一下点击位置和位置的距离。

 

}

 

其实鼠标拖动有一个对应的apiRectTransformUtility(rect的工具).ScreenPointToWorldPointInRectangle(移动元素的rectransform(其实这里要的是一个矩形框,uirect都是矩形框),鼠标位置,eventdata下的pressEventCamera,out 返回v3worldpos);该类可以将屏幕坐标转化成世界坐标并且实时和矩形框内做对比。

api返回bool,如果当前鼠标位置在移动的元素以内,就返回true,否则为false,常用来判断有没有点击到对应的UI元素。

而且该api可以适应任何摄像机渲染方式,和ui的位置方式,真实拖动时只要计算差量就行了,上述代码内容完全没用。

 

RectTransformUtility(rect的工具).ScreenPointToLocalPointInRectangle(父物体的rectransform(其实这里要的是一个矩形框,uirect都是矩形框),鼠标位置,eventdata下的pressEventCamera,out 返回v2localpos); api把当前坐标转换为父物体的相对坐标位置。相对位置是以父物体(center模式下)矩形的中心为参考,而非轴心点,和archer和轴心点没有关系。

public void OnDrag(PointerEventData eventData) {

        if (RectTransformUtility.ScreenPointToWorldPointInRectangle(rec, Input.mousePosition, eventData.enterEventCamera, out worldpos)) {

            transform.position = worldpos - offset;

        }

}

 

    public void OnPointerDown(PointerEventData eventData) {

        if (RectTransformUtility.ScreenPointToWorldPointInRectangle(rec, Input.mousePosition, eventData.enterEventCamera, out worldpos)) {

            offset = worldpos - transform.position;

        }

    }

Canvas Group

Alpha设置透明度,子物体也会生效

Interactable

Blocks RayCasta阻挡射线

Image

Color:需要叠加到img的颜色

Material:添加材质

Raycast Target:不勾选,UI不能和用户交互(拖拽点击功能都没有了)并且还有穿透的效果(不接受射线检测)该射线不是常规射线,是ui的射线。

Image type:图片模式

Simple正常图片模式

filled是填充

Fill amount 填充方式,0-1,0的时候就没有了。不同的填充方式可以模拟进度条

Sliced.切片模式,设置拉伸区域(在图片sprite edit中修改设置四条切绿色线,以前用过),可用于按钮的中间拉伸而四边不拉伸

Tiled:平铺,图片拉伸尺寸超过原图时,采用重复平铺的模式。

button

interactable : 按钮是否可用,勾上会变灰

Fade Duration :颜色过度时间

Navigation : 按钮导航,可以由键盘控制按钮

Animation动画按钮:

通过动画片段来实现,点击可实现自动

Btn.onClick.Addlistener(方法名);

Toggle

Ison: 打开关闭的选项,对应Graphic开关与否,组合下只有一个toggle能是ison

Toggle Transition:过渡效果,Fade淡出效果,none没有效果

Graphic : 勾选的标志,默认是对勾图形

Grouptoggle组,制作单选的效果,将多个放在一个组中。组合下只有一个toggle能是ison

 

Dropdown

下拉菜单

Label 默认显示的选项内容

Scroll rect:滚动条

事件有一个int 参数,参数是选项的索引

对象.OnValueChanged(函数名);

函数名(int a

通过索引取选项内容:对象.options[int参数];取到的是一个对象,对象内包含一个图片,一个内容,获取内容应该用对象.options[int参数].text

Slider

监听事件:

对象.OnValueChanged(函数名);

函数名(float a

注意,函数参数必须要,不写会报错

当作进度条时,Fill拿出来,不需要手柄,可以将两边的留空给覆盖到

Scrollbar

Handle 滑块,此滑块必须要,和slider不一样

Size 滑块的大小

Numbrer of step:滑块从0-1滑动的步数。一般和value配合使用

UImask

Mask

遮罩组件。

在父物体身上添加img组件和遮罩组件,子物体的图形会按照父物体的图形形状遮罩显示,img必须是带透明通道的图片

Rect mask 2d

以中心点为基准点遮罩,并且是方形的。

Scroll Rect组件

事件接口

引用命名空间,using untiyEngine.EventSystems;

IBeginDragHandler,开始拖动,鼠标不松手,即是不拖动了,事件也不会判断结束

Public void OnBeginDrag(Point);

IEndDragHandler,结束拖动

拖动

IdragHandler,拖动中

自动排版

Layout下的组件

HorizontalLayoutGroup:自动横向布局

Padding:四边的距离,left,right,top,bottom

Spacing:每个元素之间的间隔

Child Alignment  对齐方式

Control child size:勾选这个,配合Layout Element起作用

Child Force Expland : 是否有间隔。

 

Layout Element :配合LayoutGroup使用,勾选lgnore image不自动调整该元素。

 

元素过多时的动态扩容:Content size fitter,动态扩容时必须将内容面板的轴心点放在上面。

 

 

背包界面

Ui设置:

1、 背包系统需要layoutgroup组件,为了避免物体的UI也被自动布局,所以应该将物体ui上加上layout element组件,使该组件不自动布局。

2、 拖动物体ui时,物体ui应该显示在所有物体之上,由于ugui的渲染机制,只有将物体放在同级最下面才能显示在所有上面,所以实现IbenginDrag接口,每次拖动开始时,将物体ui的父类设置为格子的父类(原物体ui在每个格子内,是格子的子类),并且通过transform. SetAslastSiblingIndex()设置为最后一个。

3、 EventdatapointEnter可以获取物体ui移动到了哪个格子。

4、 物体UI身上加上Canvas Group 拖动物体UI时,勾选掉Blocks RayCasta,就会阻挡射线点击到物品UI(否则pointEnter就会是物体ui自己),但松开拖动物体时,再将Blocks RayCasta勾回来,就可以再点击拖动了。

背包系统

思路:先写Model数据

背包物品的基类:ItemBase{idnameCountdescriptionprice}

基类按照物品的分类有多个子类:

EquipmentItemBase装备类:

枚举.类型:{人物属性:攻击力,防御,敏捷等,人物状态:红,蓝}

Asitem: ItemBase 消耗品类

使用数组存储所有背包数据。

背包管理类:bagManager

使用数组存储的背包数据

交换两个格子的物品

删除物品

查找物品

添加物品

 

ItemUI:背包物品  

数量,图,继承itembase,写入

GridUI 背包格子

IndexitemUI(当前格子的物品)

 

BagWindow 背包窗口,管理整个背包的显示层

Grids 存所有格子

Additem

Removeitem

Fxchangeitem

Useitem

Moveto

 

 

 

 

 

 

 

2017-10-25 09:58:42 nicepainkiller 阅读数 1040
  • Unity3D的UI系统(UGUI)初级入门

    本课程主要介绍Unity3d的UI系统(UGUI),先对UGUI做一个总体概述,之后对每个UI控件逐一进行详细讲述,内容包括控件的作用、设置方法、使用场景及属性细节,帮助大家熟练使用UGUI设计游戏的交互界面。

    985 人正在学习 去看看 伍晓波

其中stateText 为Text 当然也可以是 Image 等等UGUI的 组件

onTextClick 为方法的回调



            EventTrigger trigger        = stateText.gameObject.GetComponentEx<EventTrigger>();
            trigger.triggers            = new System.Collections.Generic.List<EventTrigger.Entry>();

            EventTrigger.Entry entry    = new EventTrigger.Entry();
            entry.eventID               = EventTriggerType.PointerClick;
            entry.callback              = new EventTrigger.TriggerEvent();

            entry.callback.AddListener(OnTextClick);
            trigger.triggers.Add(entry);


unity3d 动态创建ugui

阅读数 3117

没有更多推荐了,返回首页