如果不太熟悉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指日可待了;