[置顶] UGUI 技术点笔记 (干货走起)

如果不太熟悉UGUI的同学,请补充一下UGUI教程,这里就不一一说明了.

NGUI  与 UGUI 区分:

// -------------------------------------------------

打包图集: (为了优化图集,我们可以选择把带透明通道图片 和 不带透明通道的图片分开打图集,这样可以减少内存的占用量)

NGUI:在打包图集的时候图集的默认格式是RGBA32,也就是支持带透明通道的图片,这样一张1024的图集也就是4M内存。(然而着一切的一切在NGUI上都需要手动操作)

UGUI:SpritePacker则全自动完成。Sprite上的Packing Tag 同一标识的图片UGUI会把相同图片格式的图片打包成同一图集。

// -----------------------------------------------------

打包模式:

DefaultPackerPolicy:是默认的打包方式,也是矩形打包方式。他会把所有的小图按照矩形的方式来排列,如果宽高不一样的图片,它们会自动补起。(unity所推荐)

TightPackerPolicy:是紧密打包方式,也就是尽可能的把图片都打包在图集上,这种方式要比DefaultPackerPolicy打包的图片更多一些,也就是更省空间。

Packing Tag: [TIGHT]Atals // TightPackerPolicy

Packing Tag: [RECT]Atals   // DefaultPackerPolicy

// -----------------------------------------------------

UI和3D场景同时都需要响应触摸事件:

方案1:射线过滤方法;

方案2: UGUI 提供方法(缺点在android无效,unity bug 之后可能会解决)

if (Input.GetMouseButtonDown(0) )

{

Debug.Log(EventSystem.current.gameObject.name);

if (EventSystem.current.IsPointerOverGameObject())

Debug.Log("当前触摸在UI上");

else Debug.Log("当前没有触摸在UI上");

}

方案3: 修改测试通过: ( 解决方案2问题 )

#if !(UNITY_IPHONE || UNITY_ANDROID || UNITY_WP8 || UNITY_BLACKBERRY )
            if (Input.touchCount > 0 && Input.GetTouch (0).phase == TouchPhase.Began) {

                if (!EventSystem.current.IsPointerOverGameObject (Input.GetTouch (0).fingerId)) {
                    //Handle Touch
                    debugText = "Debug INFO: UI YES";
                    Debug.Log("UI YES");
                }
                else 
                {
                    debugText = "Debug INFO: UI NO";
                    Debug.Log("UI NO");
                }
            }

#else
            if (EventSystem.current.IsPointerOverGameObject())
            {
                debugText = "Debug INFO: UI YES";
                Debug.Log("UI NO");
            }
            else
            {
                debugText = "Debug INFO: UI NO";
                Debug.Log("UI YES");
            }
#endif

/ -----------------------------------------------------

NGUI与UGUI的动画部分:

NGUI:UITween;

UGUI:可以使用dotween或者LeanTween;

/ -----------------------------------------------------

自动布局:

NGUI: 缺失,需要自己实现;

UGUI: 官方支持,unity的LayoutGroup分为三种, Horizontal Layout Group(水平布局)Vertical Layout Group(垂直布局)Grid Layout Group (网格布局);

布局脚本: Layout Element (Script)脚本;

// -----------------------------------------------------

UGUI放大图片部分:

rectTransform.sizeDelta = new Vector2(Screen.width,Screen.height);

void Start()

{

int width = Screen.width;

int height = Screen.height;

int designWidth = 960;//开发时分辨率宽

int designHeight = 640;//开发时分辨率高

float s1 = (float)designWidth / (float)designHeight;

float s2 = (float)width / (float)height;

if(s1 < s2) {

designWidth = (int)Mathf.FloorToInt(designHeight * s2);

} else if(s1 > s2) {

designHeight = (int)Mathf.FloorToInt(designWidth / s2);

}

float contentScale = (float)designWidth/(float)width;

RectTransform rectTransform = this.transform as RectTransform;

if(rectTransform != null){

rectTransform.sizeDelta = new Vector2(designWidth,designHeight);

}

}

// -----------------------------------------------------

获取UI在Canvas下的2D坐标:

3d坐标: transform.postion

2d坐标: rectTransform.anchoredPosition

public Canvas canvas;

 

void Start(){

Vector2 pos;

if(RectTransformUtility.ScreenPointToLocalPointInRectangle(canvas.transform as RectTransform, transform.position, canvas.camera, out pos)){

Debug.Log(pos);

}

 

}

代码就是用UI元素的世界坐标和canvas的RectTrasform再加上UI摄像机,换算出元素在Canvas的2D坐标。

最后在想需要赋值的UI 用 rectTransform.anchoredPosition = pos 就可以了

// -----------------------------------------------------

两张图片局部遮挡的事件相应问题:

(如果一个按钮有一半的区域被Image挡住,那么被挡住的按钮区域的点击事件就会被拦截掉。解决这个问题有两个方法。)

加個UGUI內建的CanvasGroup組件, 把Interactable和Blocks Raycasts選項取消。(不会增加多余dc)

// -----------------------------------------------------

Sprite Packer压缩规则 图集分配错误:(u3d bug)

.bug: 一张1024的rgba32图片被莫名其妙分切成2张图;

图集打包部分分类:大致3类

1.带透明通道

2.不带透明通道

3.手动设置的格式

// -----------------------------------------------------

UGUI 字体组件加阴影特效:

.解决方案在Text组件下增加component中的UI/EFFECTS/Shadow (Script);

// -----------------------------------------------------

UGUI 字体组件加富文本:

<color=#00ffffff> // 颜色

<size=50>largely</size> //字体

 <i>usually</i> // 斜体

 <b>not</b> //粗体

sample:<size=30>Some<color=yellow>RICH</color> text</size>

// -----------------------------------------------------

UGUI 设置半透明遮罩与3d模型显示在ui前方做法:

游戏中设置3个相机分别是
.mainCamera: 主透视相机                      遮罩: 取消ui与要显示的层                                                     depth:-1;

.ForwardUICamera: 跟随视相机透视        遮罩: 只渲染要显示在最前方的层(ForwardUICamera)         depth:10

.UICamera: 跟随UGUI正交相机                遮罩: 只渲染UI层                                                                 depth:0


游戏中层级

普通游戏层:

.Default:0

.TransparentFx:1

.Ignore Raycast:2

....:3

.Water:4

.UI:5

....:6

....:7

LayerGround:8

LayerFloor:9

LayerMapObject:10

最前方层:

.定义一个显示比ui高的层:FORWORD_UI :20;



逻辑处理

当需要显示在base前方的模型或者特效方法:

.激活ForwardUICamera;

.调整现实对象的layer进入ForwardUICamera渲染区域;

.使用后,设置原先的游戏对象还原到之前的layer层级;

// -----------------------------------------------------

UGUI 事件处理:

public class HLEventTriggerListener : EventTrigger{
    public delegate void VoidDelegate (GameObject sender);
    public VoidDelegate onClick;
    public VoidDelegate onDown;
    public VoidDelegate onEnter;
    public VoidDelegate onExit;
    public VoidDelegate onUp;
    public VoidDelegate onSelect;
    public VoidDelegate onUpdateSelect;
    
    static public HLEventTriggerListener AddEeventListener (GameObject sender)
    {
        HLEventTriggerListener listener = sender.GetComponent<HLEventTriggerListener>();
        if (listener == null)
            listener = sender.AddComponent<HLEventTriggerListener>();
        return listener;
    }


    public override void OnPointerClick(PointerEventData eventData)
    {
        if(onClick != null)
            onClick(gameObject);
    }


    public override void OnPointerDown (PointerEventData eventData){
        if(onDown != null)
            onDown(gameObject);
    }


    public override void OnPointerEnter (PointerEventData eventData){
        if(onEnter != null)
            onEnter(gameObject);
    }
    public override void OnPointerExit (PointerEventData eventData){
        if(onExit != null)
            onExit(gameObject);
    }


    public override void OnPointerUp (PointerEventData eventData){
        if(onUp != null)
            onUp(gameObject);
    }


    public override void OnSelect (BaseEventData eventData){
        if(onSelect != null)
            onSelect(gameObject);
    }


    public override void OnUpdateSelected (BaseEventData eventData){
        if(onUpdateSelect != null)
            onUpdateSelect(gameObject);
    }
}


Sample:

void Start()

{

HLEventTriggerListener.AddEeventListener(this.gameObject).onClick = OnButtonClick;
public void OnButtonClick(GameObject sender)
{
Debug.Log(sender.name);
}

}

// -----------------------------------------------------

UGUI 自适应问题:(这里我使用的方案与NGUI的双相机类同)






设置一下参数即可;

// -----------------------------------------------------

使用SpritePack方法与代码调用:

.Resources下不可以打包SpritePack 包,放到其他目录下即可;

.选项卡Edit->ProjectSetting->Editor-> Sprite Packer (Mode:Always Enabled)

.将临时的图片sprite打包成perfab放到Resources下使用这里制作了一个小工具:

  [MenuItem ("Assets/AtlasMaker")]
   public static  void MakeAtlas()
    {
        string spriteDir = Application.dataPath +"/Resources/UI/sprite2d";//"/BaseRes/UI/menu_action";//创建一个接受perfab的路径
        
        if(!Directory.Exists(spriteDir)){
            Directory.CreateDirectory(spriteDir);
        }
        
        DirectoryInfo rootDirInfo = new DirectoryInfo (Application.dataPath +"/BaseRes/UI");// 使用道的临时图片路径
        Debug.Log(Application.dataPath);
        foreach (DirectoryInfo dirInfo in rootDirInfo.GetDirectories()) {
            foreach (FileInfo pngFile in dirInfo.GetFiles("*.png",SearchOption.AllDirectories)) {
                Debug.Log(pngFile.FullName);
                string allPath = pngFile.FullName;
                string assetPath = allPath.Substring(allPath.IndexOf("Assets"));
                Sprite sprite = AssetDatabase.LoadAssetAtPath<Sprite>(assetPath);
                GameObject go = new GameObject(sprite.name);
                go.AddComponent<SpriteRenderer>().sprite = sprite;
                allPath = spriteDir+"/"+sprite.name+".prefab";
                string prefabPath = allPath.Substring(allPath.IndexOf("Assets"));
                PrefabUtility.CreatePrefab(prefabPath,go);
                GameObject.DestroyImmediate(go);
            }
        }   
    }

运行后

使用之前的图片资源

调用脚本代码来创建Sprite:

测试getSprite("UI/sprite2d/Icon_Five");

///

public Sprite getSprite(string spritePrefabPath)
        {
            return Resources.Load<GameObject>(spritePrefabPath).GetComponent<SpriteRenderer>().sprite;
        }

// -----------------------------------------------------

设置ugui的层级问题,来修改渲染先后顺序:

GetSiblingIndex();// 同级计算

SetSiblingIndex(); //同级设置;

// -----------------------------------------------------





随后继续补充,ugui征服ngui指日可待了;






你可能感兴趣的:([置顶] UGUI 技术点笔记 (干货走起))