2017-05-14 20:14:32 jxw167 阅读数 2719

笔者介绍:姜雪伟,IT公司技术合伙人,IT高级讲师,CSDN社区专家,特邀编辑,畅销书作者,国家专利发明人;已出版书籍:《手把手教你架构3D游戏引擎》电子工业出版社和《Unity3D实战核心技术详解》电子工业出版社等。

CSDN视频网址:http://edu.csdn.net/lecturer/144

在利用Unity3D引擎开发程序时,UI资源的加载,卸载,隐藏以及UI渐变动画等功能是UI架构设计必须考虑的。

做每一款游戏都需要将这些功能编写一遍非常耗时,在此给读者介绍一种快速的实现方式,因为我们这个是通用的

模块,所以必须要使用模板实现,而且我们的逻辑脚本是不挂接到对象上的。接下来首先设计一个管理类Manager,

代码如下所示:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
/// <summary>
/// 抽象管理类
/// </summary>
/// <typeparam name="K"></typeparam>
/// <typeparam name="V"></typeparam>
public class Manager<T,K, V> : Singleton<T>
    where V : class ,IDisposable
    where T : Singleton<T>, new()
{
    protected Dictionary<K, V> mMap = new Dictionary<K, V>();
 
    /// <summary>
    /// 获取 对应实体
    /// </summary>
    /// <param name="key"></param>
    /// <returns></returns>
    public V Get(K key)
    {
        if (key == null) return null;
        return mMap.ContainsKey(key) ? mMap[key] : null;
    }

    /// <summary>
    /// 获取类型T的 Value
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="key"></param>
    /// <returns></returns>
    public U Get<U>(K key) where U : class,V 
    {
        V v = Get(key);
        return v as U;
    }

    /// <summary>
    /// 获取类型T的Value
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    public T Get<T>() where T : class,V 
    {
        foreach(V value in mMap.Values)
        {
            if(value.GetType().Equals(typeof(T)))
            {
                return value as T;
            }
        }
        return null;
    }
    /// <summary>
    /// 添加对应实体
    /// </summary>
    /// <param name="key"></param>
    /// <param name="value"></param>
    public bool Put(K key, V value)
    {
        if (mMap.ContainsKey(key))
        {
            if (value == mMap[key])
            {
                return false;
            }
            V v = mMap[key];
            mMap[key] = value;
            v.Dispose();
        }
        else
        {
            mMap.Add(key, value);
        }
        return true;
    }

    /// <summary>
    /// 删除
    /// </summary>
    /// <param name="key"></param>
    /// <returns></returns>
    public bool Remove(K key)
    {
        if (mMap.ContainsKey(key))
        {
            V v = mMap[key];
            mMap.Remove(key);
            v.Dispose();
        }
        return true;
    }


    public Dictionary<K,V>.ValueCollection Values
    {
        get { return mMap.Values; }
    }
    /// <summary>
    /// 清除所有管理的对象
    /// </summary>
    public void Clear()
    {
        foreach (V value in mMap.Values)
        {
            value.Dispose();
        }
        mMap.Clear();
    }
}

public class ManagerT<K, V> : Manager<ManagerT<K,V>, K, V>
    where V : class ,IDisposable
{

}


在这个类属于抽象类,它利用Dictionary实现了对象的管理操作,接下来需要实现UI的管理类了,先把代码给读者展示如下:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;

/// <summary>
/// UI 服务类
/// </summary>
public class UIService : Manager<UIService, string, UIService.UI>,IDisposable
{
    public void Dispose()
    {
        DestroyAll();
    }

    /// <summary>
    /// 创建UI
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="name"></param>
    /// <returns></returns>
    private T _CreateUI<T>(string name) where T : UI
    {
        T ui = Activator.CreateInstance(typeof(T), name) as T;
        return ui;
    }

    public class UIHolder : MonoBehaviour
    {
        public UI ui { get; set; }
    }
    public class UI : IDisposable
    {
        public UI(string name)
        {
                _Init(name);  
        }

        public enum UIStyle
        {
            Normal,//默认类型
            HideByTapScene,//点击空白处隐藏类型,和黑底不冲突
        }

        UIStyle mStyle = UIStyle.Normal;

        public UIStyle Style
        {
            get { return mStyle; }
            set { mStyle = value; }
        }

        internal GameObject mPrefab = null;
        protected UIPanel mPanel = null;
        #region 面板动画处理
        protected UITweener[] mTweens = null;
        protected UITweener   mMainTween = null;
        protected UITweener.ToggleStyle mMainToggleStyle = UITweener.ToggleStyle.normal;
        private void _TweensInit()
        {
            mTweens = mPrefab.GetComponentsInChildren<UITweener>();
            if (mTweens != null)
            {
                UITweener tween;
                for (int i = 0; i < mTweens.Length; ++i)
                {
                    tween = mTweens[i];
                    if (tween.toggleStyle == UITweener.ToggleStyle.OnShow)
                    {
                        mMainTween = tween;
                        mMainToggleStyle = UITweener.ToggleStyle.OnShow;
                    }
                    if (tween.toggleStyle == UITweener.ToggleStyle.OnShowAndHide)
                    {
                        mMainTween = tween;
                        mMainToggleStyle = UITweener.ToggleStyle.OnShowAndHide;
                        break;
                    }
                }
            }
        }

        private bool _HasTween()
        {
            return mMainTween != null && mMainTween.toggleStyle !=  UITweener.ToggleStyle.normal;
        }
        private void _TweenOnShow(EventDelegate.Callback call)
        {
            mMainTween.SetOnFinished(call);
            UITweener tween;
            for (int i = 0; i < mTweens.Length; ++i)
            {
                tween = mTweens[i];
                if(tween.toggleStyle != UITweener.ToggleStyle.normal)
                {
                    tween.ResetToStart(true);
                    tween.PlayForward();
                }
            }
        }

        private void _TweenOnHide(EventDelegate.Callback call)
        {
            if (mMainToggleStyle == UITweener.ToggleStyle.OnShow)
            {
                call();
                return;
            }
            mMainTween.SetOnFinished(call);
            UITweener tween;
            for (int i = 0; i < mTweens.Length; ++i)
            {
                tween = mTweens[i];
                if (tween.toggleStyle == UITweener.ToggleStyle.OnShowAndHide)
                {
                    tween.ResetToStart(!true);
                    tween.PlayReverse();
                }
            }
        }
        private void _Dummy()
        {

        }
        private void _Hide()
        {
            mPrefab.SetActive(false);
            mHiding = false;
        }
        #endregion

        internal void _Init(string name)
        {
            try
            {
                GameObject prefab = Resource.LoadUI(name);
                mPrefab = GameObject.Instantiate(prefab) as GameObject;
                UIHolder uiholder = UtilGameObject.GetOrAddComponent<UIHolder>(mPrefab);
                uiholder.ui = this;
                mPrefab.name = name;
                mPanel = mPrefab.GetComponent<UIPanel>(); //允许Panel为空
                _TweensInit();
            }
            catch (Exception e)
            {
                Looper.LogException(e);
            }
            UIService.Instance.InitUI(mPrefab);
            UIService.Instance._OnShowUI(this, true);
        }
        #region <默认属性>
 
        
        /// <summary>
        /// 深度信息
        /// </summary>
        public int depth
        {
            get
            {
                if (mPanel==null)
                {
                    return -1;
                }
                return mPanel.depth;
            }
            set
            {
                if (mPanel == null) return;
                mPanel.depth = value;
            }
        }
        /// <summary>
        /// 是否正在显示
        /// </summary>
        /// <returns></returns>
        public bool IsShowing()
        {
            if (mPrefab == null)
                return false;
            return mPrefab.activeSelf;
        }
        float mLastShowTime = Time.time;
        /// <summary>
        /// 最后一次显示的时间
        /// </summary>
        public float LastShowTime
        {
            get { return mLastShowTime; }
            set { mLastShowTime = value; }
        }
        #endregion

        /// <summary>
        /// 名字(和预制件名称一样)
        /// </summary>
        public  string Name
        {
            get { return mPrefab != null ? mPrefab.name : ""; }
        }
        /// <summary>
        /// 销毁对象
        /// </summary>
        public void Dispose()
        {
            UIService.Instance._OnHidUI(this);

            try
            {
                OnClose();
                if (mPrefab != null)
                {
                    GameObject.DestroyImmediate(mPrefab);
                    mPrefab = null;
                }

            }
            catch (Exception e)
            {
                Looper.LogException(e);
            }
            
        }

        /// <summary>
        /// 刷新界面
        /// 1 Grid 重排问题
        /// </summary>
        public void Refresh()
        {
           
                UIGrid[] grids = mPrefab.GetComponentsInChildren<UIGrid>();
                foreach (UIGrid grid in grids)
                {
                    if (grid != null && !grid.animateSmoothly)
                    {
                        grid.Reposition();
                    }
                }
           
        }


        public IEnumerator _Refresh()
        {
            {
                UIGrid[] grids = mPrefab.GetComponentsInChildren<UIGrid>();
                foreach (UIGrid grid in grids)
                {
                    if (grid != null && !grid.enabled)
                    {
                        grid.repositionNow = true;
                        grid.Reposition();
                    }
                }
            }

            yield return null;
        }


        //解决同一个UI动画隐藏还没结束,动画显示就开始了 状态不对的问题
        bool mHiding = false;
        /// <summary>
        /// 是否显示
        /// </summary>
        public void Show(bool v)
        {

            if (v)
            {
                if (mHiding)
                {
                    _Hide();
                }
                UIService.Instance._OnShowUI(this);
            }
            else
            {
                UIService.Instance._OnHidUI(this);
            }

            try
            {

                if (mPrefab != null)
                {
                    
                    if (_HasTween())
                    {
                        if (v)
                        {
                            mPrefab.SetActive(true);
                            _TweenOnShow(_Dummy);
                        }
                        else
                        {
                            mHiding = true;
                            _TweenOnHide(_Hide);
                        }
                    }
                    else
                    {
                        mPrefab.SetActive(v);
                    }
                    OnShow(v);
                    if (v)
                    {
                        LastShowTime = Time.time;
                        Refresh();
                        //();
                    }
                }
                
            }
            catch (Exception e)
            {
                Looper.LogException(e);
            }


        }


        /// <summary>
        /// 跟随场景中物体
        /// </summary>
        /// <param name="target"></param>
        public void ApplyHub(Transform target)
        {
            NGUIExt guiExt = PluginManager.Instance.Get<NGUIExt>();
            if (guiExt != null)
            {
                guiExt.ApplyHud(mPrefab, target);
            }
        }

        public virtual void OnCreate() { }
        public virtual void OnShow(bool v) { }
        public virtual void OnClose() { }

        /// <summary>
        /// 点击事件
        /// </summary>
        /// <param name="obj">被点击的控件</param>
        public virtual void OnClick(GameObject obj) { }

        /// <summary>
        /// 双击事件
        /// </summary>
        /// <param name="obj">被双击的控件</param>
        public virtual void OnDoubleClick(GameObject obj) { }
        /// <summary>
        /// 按住事件
        /// </summary>
        /// <param name="obj">被Pressed的控件</param>
        /// <param name="pressed"></param>
        public virtual void OnPress(GameObject obj, bool isPressed) { }

        /// <summary>
        /// 拖动事件
        /// </summary>
        /// <param name="obj">拖动的控件</param>
        /// <param name="delta"></param>
        public virtual void OnDrag(GameObject obj, Vector2 delta) { }

        /// <summary>
        /// 拖放事件
        /// </summary>
        /// <param name="obj">拖放的当前控件</param>
        /// <param name="objSelected">一直被拖住的控件</param>
        public virtual void OnDrap(GameObject obj, GameObject objSelected) { }

        /// <summary>
        /// 显示Tooltip事件
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="isShow">显示或隐藏Tooltip</param>
        public virtual void OnTooltip(GameObject obj, bool isShow) { }

        /// <summary>
        /// 被选中事件
        /// </summary>
        /// <param name="obj">被选中的控件</param>
        /// <param name="isSelected">选中或取消被选中</param>
        public virtual void OnSelect(GameObject obj, bool isSelected) { }

        /// <summary>
        /// 光标划过事件
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="isHover">光标进入或光标离开</param>
        public virtual void OnHover(GameObject obj, bool isHover) { }

        /// <summary>
        /// 根据类型获取对应名称控件;
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="name"></param>
        /// <returns></returns>
        protected T GetChild<T>(string name,GameObject obj = null, int index = 0) where T : MonoBehaviour
        {
            if(obj == null)
            {
                obj = mPrefab;
            }

            Transform child = obj.transform.Find(name);
            if (child == null)
            {
                T[] childs = obj.GetComponentsInChildren<T>();
                foreach (T t in childs)
                {
                    if (t.gameObject.name == name)
                    {
                        return t;
                    }
                }
            }
            else
            {
                if (child.childCount == 0)
                {
                    return child.GetComponent<T>();
                }

                {
                    int count = 0;
                    T[] comps = child.GetComponents<T>();
                    foreach (T t in comps)
                    {

                        if (t.gameObject.name == name && count == index)
                        {
                            return t;
                        }
                        count++;
                    }
                }
                {
                    int count = 0;
                    T[] childs = child.GetComponentsInChildren<T>();
                    foreach (T t in childs)
                    {

                        if (t.gameObject.name == name && count == index)
                        {
                            return t;
                        }
                        count++;
                    }
                }

            }

            Debug.LogError(obj.name + " hasn't Components :" + typeof(T).Name + " in children named:" + name);
            return null;
        }

        protected GameObject FindChild(string name)
        {
            var child = mPrefab.transform.FindChild(name);
            return child.gameObject;
        }

        protected T FindChild<T>(string name) where T : Component
        {
            var child = mPrefab.transform.FindChild(name);
            T cmp = child.GetComponent<T>();
        
            return cmp;
        }

        /// <summary>
        /// 获取对应名称子控件;
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        protected GameObject GetChild(string name, GameObject obj = null)
        {
            if(obj == null)
            {
                obj = mPrefab;
            }
            Transform child = obj.transform.Find(name);
            if (child == null)
            {
                Debug.LogError(obj.name + "is not find child of:" + name);
                return null;
            }
            return child.gameObject;
        }
        /// <summary>
        /// 用指定的对象替换子对象
        /// </summary>
        /// <param name="name">子对象名字</param>
        /// <param name="obj">指定的对象</param>
        /// <returns></returns>
        protected bool ReplaceChild(string name, GameObject obj)
        {
            GameObject orginal = GetChild(name);

            if (orginal == null) {
				GameObject.DestroyImmediate (obj);
				return false;
			}
            obj.transform.parent = orginal.transform.parent;
            obj.transform.localPosition = Vector3.zero;
            obj.transform.localRotation = Quaternion.identity;
            obj.transform.localScale = Vector3.one;
			obj.name = orginal.name;

			orginal.transform.parent = null;
			GameObject.DestroyImmediate (orginal);

            return true;
        }

        /// <summary>
        /// 用指定的对象替换子对象
        /// </summary>
        /// <param name="orginal">原件</param>
        /// <param name="obj">指定的对象</param>
        /// <returns></returns>
        protected bool ReplaceChild(GameObject orginal, GameObject obj)
        {
            if (orginal == null) {
				GameObject.DestroyImmediate (obj);
				return false;
			}
            obj.transform.parent = orginal.transform.parent;
            obj.transform.localPosition = Vector3.zero;
            obj.transform.localRotation = Quaternion.identity;
            obj.transform.localScale = Vector3.one;
			obj.name = orginal.name;

			orginal.transform.parent = null;
			GameObject.DestroyImmediate (orginal);
            return true;
        }

    }


    NGUIExt mPlugin;
    GameObject mBG;
    UIPanel mBGPanel;
    int mBGCount = 0;

    private void _OnShowUI(UI t,bool init = false)
    {
        if (t.IsShowing())
        {
            if(!init)
                return;
        }
        if (t.IsShowBlackBG())
        {
            mBGCount++;
            if (mBGCount > 0 && mBG.activeSelf == false)
            {
                mBG.SetActive(true);
            }
            if (mBG.activeSelf)
            {
                mBGPanel.depth = t.depth-1;
            }
        }

    }
    private void _OnHidUI(UI t)
    {
        if (!t.IsShowing()) return;

        if (t.IsShowing() && t.IsShowBlackBG())
        {
            mBGCount--;
            if(mBGCount <= 0)
            {
                mBGCount = 0;
                if (mBG.activeSelf == true)
                {
                    mBG.SetActive(false);
                }
            }


            if (mBG.activeSelf)
            {
                UI ui = _GetLastShowUI(true, t);
                if (ui != null) mBGPanel.depth = ui.depth-1;
            }
        }

    }

    public bool IsFingerHoverGUI()
    {
        if(mPlugin == null)
        {
            return false;
        }
        return mPlugin.IsFingerHoverGUI;
    }

    public bool IsFingerHoverGUI3D()
    {
        if (mPlugin == null)
        {
            return false;
        }
        return mPlugin.IsFingerHoverGUI3D();
    }

    public bool IsFingerHoverGUIWithout3D()
    {
        if (mPlugin == null)
        {
            return false;
        }
        return mPlugin.IsFingerHoverGUIWithout3D();
    }

    public bool IsPrefab(GameObject ui_prefab)
    {
        return mPlugin.IsPrefab(ui_prefab);
    }
    
    /// <summary>
    /// 初始化 继承与 Singleton 对象构建的时候被调用
    /// </summary>
    protected override void OnCreate()
    {
        
        mPlugin = PluginManager.Instance.Get<NGUIExt>();
        if (mPlugin != null)
        {
            mPlugin.SetEventHandler(this._HandlerUIEvent);
        }
        GameObject prefab = Resource.LoadUICommon("black_background");
        Looper.Assert(prefab != null , "默认黑底 black_background Prefab不存在 !!");
        if(prefab != null)
        {
            mBG = mPlugin.AddChild(prefab);
            mBGPanel = mBG.GetComponent<UIPanel>();
            mBG.transform.localScale = new Vector3(1, 1, 1);
            mBG.transform.localPosition = new Vector3(mBG.transform.localPosition.x, mBG.transform.localPosition.y, Mathf.Clamp(mBG.transform.localPosition.z, -2f, 2f));
            if(mBG != null)
            {
                UISprite sprite = mBG.GetComponent<UISprite>();
                BoxCollider collider = mBG.GetComponent<BoxCollider>();
                if(sprite!= null)
                {
                    Vector2 size = mPlugin.GetSize();
                    sprite.SetDimensions((int)size.x, (int)size.y);
                    collider.size = new Vector3(size.x, size.y, 0);
                }
            }
            
            mBG.SetActive(false);
        }
        //EasyTouch.On_SimpleTap += On_SimpleTap;
        
    }

    public void InitUI(GameObject ui)
    {
        try
        {
            LayerUtils.SetLayer(ui.transform, (int)LayerUtils.ELayerIndex.ui);
            ui.transform.parent = mPlugin.GetRoot().transform;
            
            switch(ui.name)
            {
                default:
                    ui.transform.localScale = new Vector3(1, 1, 1);
                    ui.transform.localPosition = Vector3.zero;
                    break;
            }
        }
        catch (Exception e)
        {
            Looper.LogException(e);
        }
      
    }
    /// <summary>
    /// 创建UI
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="name"></param>
    /// <returns></returns>
    public T CreateUI<T>(string name) where T: UI
    {
        UI  t = this.Get(name) as T;
        if(t == null)
        {
            t = _CreateUI<T>(name) as UI;
           try
           {
               t.OnCreate();
           }
           catch (Exception e)
           {
               Looper.LogException(e);
           }
           
           Put(name, t);
        }
        return t as T;
    }
    List<UI> mUIScene = new List<UI>();
    /// <summary>
    /// 创建一个不加入管理队列的UI,主要用于世界地图上关卡界面的创建。
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="name"></param>
    /// <returns></returns>
    public T CreateUIWithoutManager<T>(string name) where T : UI
    {
        T ui = _CreateUI<T>(name);
        try
        {
            ui.OnCreate();
        }
        catch (Exception e)
        {
            Looper.LogException(e);
        }
        mUIScene.Add(ui);
        return ui;
    }
	
    /// <summary>
    /// 销毁不加入队列的UI
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="ui"></param>
    public void CloseUIWithoutManager<T>(T ui) where T : UI
    {
        try
        {
            ui.OnClose();
            ui.Dispose();
        }
        catch (Exception e)
        {
            Looper.LogException(e);
        }
        mUIScene.Remove(ui);
    }
    /// <summary>
    /// 显示UI
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="name"></param>
    public T ShowUI<T>(string name) where T : UI
    {
        T t = CreateUI<T>(name);
        if(t != null)
        {
            t.Show(true);
        }
        return t;
    }
    /// <summary>
    /// 显示UI
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="name"></param>
    public T HideUI<T>(string name) where T : UI
    {
        T t = Get<T>(name);
        if (t != null)
        {
            t.Show(!true);

        }
        return t;
    }

    Stack<UI> mStack = new Stack<UI>();

    /// <summary>
    /// 清除栈
    /// </summary>
    public void StackClean()
    {
        mStack.Clear();
    }
    /// <summary>
    /// UI隐藏压栈
    /// </summary>
    /// <param name="t"></param>
    /// <returns></returns>
    public UI Push(UI t)
    {
        if (t != null)
        {
            t.Show(false);
            mStack.Push(t);
        }
        return t;
    }
    /// <summary>
    /// UI隐藏压栈
    /// </summary>
    /// <param name="t"></param>
    /// <returns></returns>
    public T Push<T>(string name) where T: UI
    {
        T t = Get<T>(name);
        if (t != null)
        {
            t.Show(false);
            mStack.Push(t);
        }
        return t;
    }
    /// <summary>
    /// UI显示出栈
    /// </summary>
    /// <param name="t"></param>
    /// <returns></returns>
    public UI Pop()
    {
        UI t = mStack.Pop();
        if (t != null)
        {
            t.Show(true);
        }
        return t;
    }


    /// <summary>
    /// 销毁UI
    /// </summary>
    /// <param name="name"></param>
    public void Distroy(string name)
    {
        UI ui = Get(name);
        if(ui != null)
        {
            ui.Dispose();
            Remove(name);
        }
    }

    public void Distroy<T>(string name) where T : UI
    {
        UI ui = Get<T>(name);
        if (ui != null)
        {
            ui.Dispose();
            Remove(name);
        }
    }
    public void DestroyAll(bool includeScene= false)
    {
        StackClean();
        Clear();
        if(includeScene)
        {
            foreach (UI ui in mUIScene)
            {
                ui.Dispose();
            }
            mUIScene.Clear();
        }

    }
    /// <summary>
    /// 隐藏其他UI
    /// </summary>
    /// <param name="name"></param>
    public void HideOtherUI(string name)
    {
        foreach (UI ui in Values)
        {
            if (ui.Name.Equals(name))
                continue;
            ui.Show(false);
        }
    }

    UI _GetLastShowUI(bool showBG = false,UI except=null)
    {
        UI lastShowUI = null;
        float lastShowTime = 0;
        foreach (UI ui in Values)
        {
            if (ui == except) continue;
            if (ui.IsShowing() && ui.LastShowTime > lastShowTime)
            {
                if (showBG)
                {
                    if (ui.IsShowBlackBG())
                    {
                        lastShowUI = ui;
                        lastShowTime = ui.LastShowTime;
                    }
                }else
                {
                    lastShowUI = ui;
                    lastShowTime = ui.LastShowTime;
                }
            }
        }
        return lastShowUI;
    }

    /// <summary>
    /// 隐藏最新显示的UI
    /// </summary>
    public void HideLastShow()
    {
        UI lastShowUI = _GetLastShowUI();
        if (lastShowUI != null)
        {
            lastShowUI.Show(false);
        }
    }
    /// <summary>
    /// 隐藏所有UI
    /// </summary>
    public void HideAllUI()
    {
        foreach(UI ui in Values)
        {
            if(ui != null)ui.Show(false);
        }
    }
    /// <summary>
    /// 获取UI跟面板
    /// </summary>
    /// <param name="obj"></param>
    /// <returns></returns>
     GameObject _GetRootPanelExt(GameObject obj)
    {
        Transform parent = obj.transform.parent;
        UIHolder uiHolder = null;// = root.GetComponent<UIService.UIHolder>();

        while (parent != null)
        {
            if (parent.gameObject.GetComponent<UICamera>() != null)
                break;

            UIHolder tempPanel = parent.GetComponent<UIHolder>();
            if (tempPanel != null)
            {
                uiHolder = tempPanel;
            }
            parent = parent.parent;
        }
        if (uiHolder == null)
        {
            return null;
        }
        return uiHolder.gameObject;
    }
    /// <summary>
    /// NGUI事件处理器
    /// </summary>
    /// <param name="eventNane">事件名称</param>
    /// <param name="sender">发送事件的控件</param>
    /// <param name="arg">事件参数</param>
    private void _HandlerUIEvent(string eventName, GameObject sender, object arg)
    {
        try
        {
            if(sender == mBG)
            {
                //MainLooper.LogError("mBG, eventName:" + eventName + "!!");
                if (eventName.Equals("OnClick"))
                {
                   
                }
                return;
            }
            GameObject root = _GetRootPanelExt(sender);//mPlugin.GetRootPanel(sender);
            if (root == null) return;
            UI ui = Get(root.name);
            if(ui == null)
            {
                UIHolder uiHolder = root.GetComponent<UIHolder>();
                if( uiHolder!= null) ui = uiHolder.ui;
            }
            if (ui == null)
            {
                Debug.LogWarning("UI:" + root.name + " not match prefab's name " + sender.name);
                return;
            }

            if (eventName.Equals("OnClick"))
            {
                ui.OnClick(sender);
            }
            else if (eventName.Equals("OnPress"))
            {
                ui.OnPress(sender, (bool)arg);
            }
            else if (eventName.Equals("OnDrag"))
            {
                ui.OnDrag(sender, (Vector2)arg);
            }
            else if (eventName.Equals("OnDrop"))
            {
                ui.OnDrap(sender, (GameObject)arg);
            }
            else if (eventName.Equals("OnSelect"))
            {
                ui.OnSelect(sender, (bool)arg);
            }
            else if (eventName.Equals("OnHover"))
            {
                ui.OnHover(sender, (bool)arg);
            }
            else if (eventName.Equals("OnTooltip"))
            {
                ui.OnTooltip(sender, (bool)arg);
            }
            else if (eventName.Equals("OnDoubleClick"))
            {
                ui.OnDoubleClick(sender);
            }
        }
        catch(Exception e)
        {
            Looper.LogException(e);
        }

    }
}

该类实现了UI的创建,也就是我们说的实例化操作,以及UI的显示,隐藏,动画等效果。在代码的最后使用了点击的回调函数避免

将脚本挂接到对象上。以上类的实现基本上把UI的大部分功能都实现出来了,可以直接拿过来使用。


2019-09-22 14:05:19 fengliaoai 阅读数 12138

每周更新unity3d视频教程,从入门到就业,官方unity3d培训,上千门实时更新课程,供学员在线观看学习,unity3d游戏开发,可以让学员随时随地学习!
免费网上学习unity3d自学教程,国内名师机构专业授课,O基础快速学习,1小时快速入门,7天unity3d自学教程学习,能力快速提升,优质作品随手呈现!

unity3d菜鸟自学教程介绍

unity3d难学吗?

unity3d自学教程目录

unity3d视频教程百度网盘下载

unity3d难学吗?
学习unity3d特效,多来学习路线网看教程,一线游戏特效老师,游戏特效就业安排!学习unity3d特效入门+进阶+精通选择专业才能学得专业!

unity3d自学教程目录
课程介绍:
Unity3d史诗 MMO ARPG 课程《泰斗破坏神》,精心设计将包含200+课时,由视频课时+直播课时+测试课时混合组成。最重头unity3d ARGP课程,完整的 ARPG 网络游戏开发教学。包含多人合作,在线多人游戏开发,角色创建系统,作战系统,RPG系统,技能系统,任务系统,商店系统。

课程大纲:

单机版功能实现

项目概要
登录系统
角色创建、选择、自定义系统
场景加载与游戏存储记录
角色控制
聊天通讯
游戏AI
战斗系统
游戏角色与玩家信息系统
商店系统
道具系统
装备系统
装备与道具掉落
仓库与背包系统
副本系统
任务系统
地图与寻路系统

网络版功能实现

服务端搭建
登录系统
角色选择
游戏场景
聊天功能
角色具体信息
商店系统
道具系统
装备系统
仓库和背包
副本系统
任务系统

unity3d视频教程百度网盘下载
http://www.xuexiluxian.net/unity3d-cainiao-zixue.html

2017-07-16 20:10:17 dark00800 阅读数 16305

Unity3d不久之前正式发布了Unity3d 2017.1, 这个版本的发布也宣告了Unity3d正式告别了5.x时代,并且开始已年份直接命名,开启了新的纪元。那么Unity3d 2017相较上一版本到底有哪些改进呢?

这介绍这些改进之前先放出下载地址:Unity 2017.1
有趣的是通过Unity产品蓝图我们可以发现Unity 2017.2 beta已经提供下载测试并且Unity 2017.3也已经在制作中了。
这里写图片描述
Unity 2017.2 beta下载地址:Unity 2017.2 beta

以下关于Unity2017.1的介绍内容来自Unity官方中文社区,原帖地址:[官方] Unity 2017.1正式版发布

Unity 2017.1中包含大量新功能与改进。主要内容如下:

  • 艺术家和设计师们:全新的叙事和游戏视频创作工具
    Unity 2017.1为艺术家和设计师们提供了全新的工具,使用Timeline,Cinemachine和Post-processing工具,可以创造令人惊叹的影视内容,合成精美相机镜头,描绘更好的视觉故事。
    Timeline是一款强大的可视化新工具,可用于创建影视内容,例如过场动画、预告片、游戏试玩视频等等。
    Cinemachine是一个高级相机系统,您可以像电影导演一样,在Unity中合成镜头,无需编写任何代码,引领您进入程序化摄影时代。
    Post-processing可以很方便地为场景应用各种逼真滤镜,使用电影工业级技术、控件和颜色空间格式来创造高质量视觉效果,让画面更生动、更逼真,助您描绘更好的视觉故事。
  • 效率:协作、实时操作分析、工具
    我们发布了Unity Teams,它由一系列简化创作者协作流程的功能和解决方案组成,包含Collaborate多人协作(现已发布)和Cloud Build云构建。
    实时操作分析系统引入了新的、更简单的方法,帮助您理解用户,并在不需要重新部署的情况下,对游戏做出动态的反应和调整。
    最重要的是,Unity 2017.1对编辑器进行了大量更新,包括对FBX导入、动画工作流程、2D功能、Asset Bundle工作流和Visual Studio集成的改进。
  • 图形与平台:全面改进
    Unity 2017.1对粒子系统和Progressive Lightmapper进行了大量改进,提供了更多选择来实现您的艺术愿景并控制性能。不同平台可采用不同的渲染品质,例如iOS平台上的Deferred Rendering,和PC上的NVIDIA VRWorks。
    这些都只是Unity 2017.1的亮点概念,下面将介绍完整丰富的细节内容!

Unity 2017.1新看点

艺术家叙事工具: Timeline和Cinemachine介绍

设计师、艺术家或动画师们可以使用新的集成叙事工具,自己制作影视内容和游戏视频,而不用依赖程序员。这意味着开发效率更高,而节约沟通与排队成本。

Timeline是一款强大的可视化新工具,可用于创建影视内容(例如短片Adam)。通过编排游戏对象、动画、声音和场景,来创建过场动画、游戏视频等等。有了Timeline,您可以专注于叙事和电影艺术创作,而非编码。

Timeline基于轨道的序列工具,使用“拖放”操作来编排动画、声音、事件、视频等元素,以更快地创建漂亮的过场动画和程序化内容。Timeline有许多功能,例如动画、音频、自动关键帧,以及可以锁定或静音特定轨道的多轨道界面。Timeline可通过Playable API进行扩展,支持创建自定义轨道,来驱动游戏中的任意系统。您可以制作一个Timeline剪辑来表示几乎所有内容——并且可以重复播放、缩放和混合这些剪辑,所有这些都可在Timeline中实现。
这里写图片描述

Cinemachine 是多年游戏和电影摄像机的构建经验凝聚而成的结晶。现在,它将业界领先的摄像操作置于所有人手中,引领了程序化摄影的时代。

这是一套智能摄像机,可以动态的根据场景组成和交互,在最佳时间拍摄最佳镜头。使您摆脱无尽的手工动画、摄像机编程以及修订的过程。

Cinemachine可以在Asset Store资源商店中下载,现在就添加到您的项目中。

从第一人称射击游戏到第三人称动作冒险,您可以用Cinemachine彻底改变游戏内摄像机。很容易地:

  • 像电影导演那样,使用高级摄像机工具及真实的摄像机设置,来控制视频序列。
  • 合成镜头,把重点放在艺术方向上,而非实现细节。给Cinemachine智能摄像机一个简单的指示,比如跟随人物的头部,如果动画发生变化,镜头会自动更新并继续正常工作。
    这里写图片描述

    在Unity 2017.1中,我们为Cinemachine增加了很多新功能,比如:

  • 多个目标对象:以多个对象为目标,并设置它们的权重。它基于任意数量的对象创建一个逻辑组,根据其成员的位置来定位自己。在跟踪一组对象时,可以将其用作LookAt和Follow方法的目标。对2D场景也非常适用。
  • 动态取景多个对象:该功能将基于对象的位置自动取景一组目标。如果对象散开,Cinemachine将根据您创建的一套规则调整FOV或推拉(或两者同时进行)
  • 全新开放API:轻松定制Cinemachine配置,获得项目需要的摄像机行为。
  • 推拉轨道:创造出像电影一样的推拉镜头,让摄像机在游戏世界里平滑移动。适合于电影序列,或当您希望摄像机沿着一组轨道跟踪拍摄对象时。
  • 安全镜头:安全镜头会根据镜头优先级与质量,动态选择最佳的摄像机。有东西进了取景框,破坏了镜头?没问题,Cinemachine会切换到下一个最佳摄像机。尤其适用于回放或任何一个可变场景的电影序列。

Timeline和Cinemachine结合使用,您可以将叙事带入更高的层次。使用后处理栈来进一步创建特效,烘托场景氛围和戏剧效果。
这里写图片描述

改进Post-processing栈(测试)

Post-processing将全屏滤镜和特效应用于摄像机的图像缓冲区,然后再将其显示在屏幕上。您可以使用图像后处理特效来模拟物理摄像机和电影效果。

最新版的Post-processing栈测试版可以在此下载。最终版预计将于今年夏季发布。(注意:上一个稳定版本可以在Asset Store资源商店中下载)

改进后的后处理栈将一组完整的图像效果整合到单个后期处理流程中,并带有一系列高质量的摄像机效果:

  • Screen-space anti-aliasing
  • Auto Exposure
  • Motion Blur
  • Bokeh Depth of Field
  • Bloom
  • Color Grading
  • Chromatic Aberration
  • Film Grain
  • Vignette

您可以将多个特效组合到单个Pass中,使用基于Asset的预设配置系统管理特效也非常轻松。

颜色分级效果是一种支持Academy Color Encoding System (ACES)的全HDR颜色管线,低端平台可以使用LDR管线。该栈有两个屏幕空间的光照特效,即环境光遮蔽和屏幕空间反射。

这个新版本还提供了一个基于体积的混合特性,您可以在场景中定义区域(任何类型的网格),并在玩家进入区域时设置特定的氛围/外观。Unity会自动在体积之间进行混合,以实现流畅的外观转换。
这里写图片描述

Unity Collaborate多人协作已正式发布!现为Unity Teams一员

Unity Collaborate多人协作已结束测试,与Cloud Build云构建一起成为Unity Teams的一部分,仅用一个解决方案一套功能,即可帮助您更快速地进行团队协作。Unity Teams将可免费使用至2017年10月。

点击了解有关Unity Teams的更多内容。

对于Collaborate多人协作,我们在Unity 2017.1中发布的首个发布版本优先处理了Beta用户提供的反馈。除了性能改进、稳定性和Bug修复之外,我们还增加了一组新功能:选择性推送、更佳的Asset浏览器集成和一个新的“In Progress”功能,用以标志团队成员在某个场景或预制件上有未发布的本地更改。
这里写图片描述

以下是我们为Collaborate多人协作添加的一些新功能:

  • In Progress标志
    为场景和预制件添加了In Progress标志,以指示团队中其他人已对某个场景或预制件做出了一些未发布的本地更改。这个特性有助于协作者协调对场景和预制件的更改。
    这里写图片描述
    这里写图片描述

  • 右键单击选择发布
    我们添加了右键单击操作,现在您可以在项目浏览器中直接发布、恢复、查看差异,解决文件冲突。这是一个主要的用户痛点源头,我们希望使Collaborate的行为与其他项目浏览器的行为更加一致。请注意,这种UX允许您选择性地发布已更改的Asset。之前的版本中,您必须发布所有更改。
    这里写图片描述

  • 浏览体验更佳
    在项目浏览器的“收藏”中添加了新的过滤器,包括“所有修改”、“所有被排除”和“所有冲突”,这样用户就可以看到他们所有修改过的文件、所有正在修改的文件、带有冲突的文件和忽略的文件。特别要留意的是“All in Progress(一切都在进行中)”,这让您可以实时看到Collaborate团队中的其他人正在处理哪些Asset(稍后将详细介绍)。
    这里写图片描述

  • 实时操作分析
    Unity 2017.1可以通过数据驱动的实时操作,随时获得丰富的分析数据。深入了解您的用户与您作品的互动情况,并实时做出相应的调整,迎合他们的习惯,无需重新部署新版本。在Unity 2017中,您可以更好地为用户提供更佳的游戏体验。
    通过Standard Events (目前是Beta版)可以进行更高效的洞察,它提供了一组精心设计的预定义事件,可揭示与您游戏相关的重要信息。使用新的Analytics Event Tracker,无需代码即可实现这些功能。
    这里写图片描述
    使用Remote Settings特性,可以即时更改游戏,无需重新部署,该特性已添加到Unity Analytics分析服务中。
    这里写图片描述

  • 2D改进
    在Unity 5.6中,我们为2D游戏开发者对工具和工作流程进行了重大改进。Unity 2017.1中引入了2D Sprite Atlas,这是一种新的Asset,将取代Sprite Packer。随着它的出现,新改进的工作流程可以在运行时更好地控制精灵的打包和使用。图集是Unity中2D工作流程的重要组成部分,而精灵图集不仅提供了更简单的图集创建和管理方式,还有相应的脚本API,可获得更多的控制和用途。
    这里写图片描述
    Sprite Masks用于在世界空间中隐藏或显示精灵或精灵组的一部分。精灵遮罩仅对拥有Sprite Renderer组件或粒子系统的对象生效。
    这里写图片描述
    在Unity 2017.1中,我们还为精灵编辑器添加了精灵物理形状。可以为精灵设置自定义的默认形状,以使用PolygonCollider2D生成碰撞器形状。

  • 动画改进
    我们对Animation窗口进行了全面修改,改进了关键帧的工作流程,使动画制作更方便和熟练,并支持与Animator状态机进行交互。Performance Recording是一个实验性功能。
    新的关键帧工作流程支持明确指定何时将哪帧变为关键帧,并在重新评估/预览动画时,将所有未修改且未关键帧化的属性值都丢弃。我们已经改变了在Animation窗口中编辑剪辑的默认行为(新的默认预览模式)、视觉反馈和全局关键帧操作热键。这些变化的目的是在Animation窗口之外为关键帧操作提供一个流畅的工作流程,同时预览动画剪辑无需处于自动关键帧或录制模式下。
    现在在编辑器中可以对状态机行为进行调试。
    我们还引入了GameObjectRecorder,这是一个新的实验性编辑器特性,它允许您记录GameObject和它子对象上的任何属性。这样就可以轻松地创建动画,将被记录的所有内容保存到一个动画剪辑中。欢迎访问论坛进行反馈。
    这里写图片描述

  • Playables已正式发布
    Playables API通过使用树状结构的PlayableGraph组织和评估数据来源,提供一种创建工具、特效或其他游戏机制的方法。PlayableGraph允许您混合和修改多个数据源,合成为单一输出后播放。
    Playables API支持动画、音频和脚本。Playables API还提供了通过脚本来与动画系统和音频系统进行交互的能力。
    Playable API是一个通用API,它最终将用于视频和其他系统。查看文档了解更多细节。

  • Ambisonic音频
    在Unity 2017.1中,我们增加了对环绕立体声音频剪辑的支持,这是全方位环绕音频技术,它(除了水平面外)还覆盖了听众上方和下方的声源。
    Ambisonics以多声道格式储存。它不是将每个通道都映射到一个特定的扬声器,而是以一种更通用的方式来表示声场。然后,根据聆听者的方向(即XR中用户的头部旋转),旋转声场。声场也可以被解码成一种与扬声器设置相匹配的格式。Ambisonics通常与360度视频结合使用,也可以用作音频天空盒,表现遥远的环境声音。
    我们还添加了Ambisonic解码器插件,而且现在也可以使用正开发中的API,在新的叙事工具Timeline中使用音频剪辑了。

  • 编辑器改进
    我们在UnityEditor.IMGUI.Controls中添加了一个新的ArcHandle类,它可以在场景视图中交互式地编辑弧线。还加入了名为SearchField的新IMGUI控件,它带有普通和工具栏用户界面风格,但也可以自行定制。
    这里写图片描述
    现在还支持使用JetBrains Rider作为外部脚本编辑器。
    其他改进还包括对所有播放器循环阶段添加分析器标签,改进Package Export加载状态,以及记录已连接玩家的日志信息,这些都将出现在编辑器控制台中,使调试更加轻松。

  • 改进了对Visual Studio的支持,包括Mac OS
    Unity安装程序现在可以选择在Windows上安装Visual Studio Community 2017(而非Visual Studio Community 2015)。安装速度显著提高也更轻量。
    Mac用户也别难过,现在可以使用Visual Studio了!微软发布了Mac版的Visual Studio和Tools for Unity。Visual Studio for Mac还提供了许多很酷的功能:一键调试,Unity消息的IntelliSense(完整Unity特定库代码),着色器代码高亮显示等等(点此查看详情)。

  • 场景与Asset Bundle改进
    我们对游戏中的场景和Asset Bundle进行了一些改进。更改底层架构使场景和Asset Bundle加载速度更快,从而使玩家体验更加流畅。我们还创建了一个工具,Asset Bundle浏览器——以帮助创建和优化Asset Bundle。

  • Asset Bundle浏览器
    Asset Bundle浏览器的Beta版与Unity 2017.1一同发布。该工具允许您在Unity项目中查看和编辑Asset Bundle的配置。它的目的是替换当前选择Asset的工作流,并在检视窗口中手动设置Asset Bundle的工作流程。现在您可以集中查看所有的Asset Bundle配置。通过使用上下文菜单和拖放功能,配置、修改和分析相关资源包。
    该工具将标记可能值得关注的警告,并提示将中断资源包创建的错误。从上层查看包集合,您可以更有效地组织Asset Bundle。在更低层查看单个Asset Bundle,您可以看到由于显式包含或依赖项的关系,哪些内容将会放入包中。
    更多细节请查阅文档
    这里写图片描述
    Asset Bundle浏览器可以从Asset Store资源商店下载。

  • 脚本运行时升级(实验性):畅享 C# 6和.NET 4.6
    在Unity 2017.1中,我们引入了实验性版本的脚本运行时内核,该内核已升级到Mono/.NET 4.6运行时。它包含了许多修复、性能改进,可以使用C# 6。我们相信它会提高游戏的整体性能。
    可以在Player Settings中启用.NET 4.6:
    这里写图片描述
    注意,更改该设置会在重启编辑器后生效,因为它会影响编辑器和播放器。对应的脚本API是PlayerSettings.scriptingRuntimeVersion属性。
    IL2CPP完全支持新的.NET 4.6 API,因此您仍可使用C#编写脚本,同时享有原生C++的性能优势。如果您发现任何问题,请访问论坛进行反馈。

  • 模型导入器改进
    从像Maya这样流行的数字内容创作(DCC)工具导入Asset的过程是首批重要的改进对象,这使得DCC工作流程变得更加轻松。最终提高了艺术家和设计师的生产力,减少了程序员的麻烦。
    现在Unity导入从Maya导出的FBX文件已支持Segment Scale Compensation,而且FBX SDK已升级至2016.1.2。
    在导入FBX文件时,我们还添加了计算加权法线的选项,如按面积、角度或二者皆有,以及硬边缘的固定法线生成。现在,可以从FBX文件中导入灯光和摄像机,Unity会自动在需要时为对象添加和配置摄像机和/或灯光组件。
    Unity现在可以使用“Import Visibility”属性从FBX文件中读取可见性属性。值和动画曲线将启用或禁用MeshRenderer组件:
    这里写图片描述

  • Progressive Lightmapper改进
    Unity 2017.1增加了Progressive Lightmapper中对烘焙LOD的支持。在烘焙LOD时,Enlighten和Progressive Lightmapper之间的主要区别在于,使用Progressive Lightmapper不必在LOD周围放置光照探针来获得反射光。在完全烘焙分辨率下,间接光照将为LOD提供更优质的烘焙光照贴图,您也可以避免为它们设置光照探针的繁琐过程。(Unity 5.6中也有此功能。)
    我们还在Progressive Lightmapper中增加了对双面材质的支持,通过添加新的材质设置,使光线与背面接触。启用后,在进行全局光照计算时几何体的两面都被包括在内。当从其他对象观察时,背面不会被认定为无效。背面渲染既不受该设置的控制,也不会在光照贴图中显示。背面使用与正面相同的自发光和漫反射设置反射光线。(该功能也可在Unity 5.6中使用)
    这里写图片描述

  • 实时阴影改进
    我们优化了在稳定模式下,级联定向光源阴影投射器的选择。这意味着生成阴影贴图时会产生更少的Draw Call。这增益是与场景和配置相关的。例如,在四个级联光的情况下,可以看到Draw Call数量显著下降。根据太阳/摄像机的方向,场景中可以减少50%的阴影投射器。下面是维京村庄的一个例子:
    下面的场景在Unity 5.6中有5718个阴影投射器。
    这里写图片描述
    在Unity 2017.1中,相同的场景,只有4807个阴影投射器。
    这里写图片描述
    Unity 2017.1还实现了实时阴影的Percentage Closer Filtering (PCF)。每个像素的深度值都是从当前像素周围的阴影贴图中取样,并所有的采样值进行比较。这使得光和影之间的线条更加平滑。您可以在下图中看到对比:
    这里写图片描述
    除了实时阴影改进,Shadowmask和Distance Shadowmask光照模式现在已成为Quality Setting中的参数,可以在运行时进行修改而无需任何成本。例如,可以在室内使用Shadowmask (实现柔和的阴影),并在相同关卡中的户外场景切换至distance Shadowmask。它也可以作为一个质量设置项。
    我们还添加了Custom Render纹理作为渲染纹理的扩展,可以很方便地用着色器来更新纹理。这有助于实现各种复杂的模拟,比如焦散光、雨滴涟漪模拟,墙面液体喷溅等等。它还提供了一个脚本和着色器框架,以便进行更复杂的配置,比如局部或多阶段更新,不同的更新频率等等。
    这里写图片描述
    有了新添加的LineUtility类和LineRenderer.Simplify函数,现在可以优化线条,用LineUtility创建由简单形状组成的简化版本。
    使用Metal/OpenGL ES3实现iOS上的Deferred Rendering
    我们为A8芯片和以后的iOS设备启用了一个使用Metal和OpenGL ES 3.0的延迟渲染路径。当使用延迟着色时,能够影响GameObject的灯光数量是没有限制的。所有的灯光都是按像素计算的,这意味着它们都能与法线贴图进行正确的交互等等。此外,所有的灯光都可以有剪影和阴影。

  • 粒子系统改进
    我们引入了精灵集成,粒子碰撞力(可以推动碰撞器),大量形状方面的改进,包括一个新的形状类型,噪音模块增加了新选项,以及其他一些较小的特性和增强。因为增加了新的控制和约束,例如速度与对齐,使得在2D中使用粒子更加轻松。可以使用粒子来获得比以往更多的特效和动画效果,包括光线的线条和尾迹。
    通过Texture Sheet Animation模块,我们在粒子系统中增加了对精灵使用的支持。这使粒子系统能更好地进行了图集处理和批处理,同时也在粒子系统中增加了大量与精灵相关的特性,例如不同大小的动画帧,以及每帧的轴心点。
    这里写图片描述
    这里写图片描述
    噪音模块提供了新的选项,可以更好地将噪音应用于粒子效果中。这个功能在Unity 5.5中第一次实现,噪音是被应用到粒子的位置属性。在2017.1中,我们可以将噪音应用到更多的地方:
    -位置
    -旋转
    -大小
    -使用Custom Vertex Streams的着色器(非常适合制作UV失真效果!)
    这里写图片描述
    在粒子系统形状模块的碰撞模式中,我们引入了一个新的甜甜圈粒子发射形状和编辑模式。模块内的Transform可以为粒子发射的形状应用自定义位置、旋转和缩放。
    其他的改进还包括将粒子与速度方向对齐的能力,以及允许在局部空间系统使用Emit over Distance。边缘粒子发射现在更加灵活,可以选择用来产生粒子的边缘厚度。
    粒子现在也可以使用碰撞模块对碰撞器进行施力。
    这里写图片描述

  • Windows Store现在改名为Universal Windows Platform
    Unity现在支持Windows商店的Universal Windows Platform(UWP)应用模式,支持为Xbox One、Windows 10、Windows Phone 10和HoloLens进行构建。
    请注意,对Windows混合现实PC设备的支持将在今年晚些时候发布。
    这里写图片描述
    我们增加了对UWP的多显示支持,现在Unity播放器二进制文件已做数字签名,增加了额外的一层安全性,可以防止对Unity运行时二进制文件进行篡改。
    最后,我们取消了对Windows 8.1和Windows Phone 8.1应用的支持,Unity 5.6是最后一个支持这两个平台的版本。

  • 索尼PS4的视频播放器
    我们在Unity 5.6中引入了一个全新的视频播放器,在Unity 2017.1中正式加入了对索尼PS4的支持,从而完成了对跨平台的支持。PS4的视频播放器使用索尼的AvPlayer库来加速h.264流的解码。解码h.264流(PS4的推荐格式)时,CPU开销非常低。可以同时对最多8个并发h.264流进行解码。它还支持对webm容器中的VP8格式流进行软件解码(更高的CPU开销)。最后,它支持多种视频渲染模式(直接渲染到摄像机的近/远平面,作为材质覆盖,或渲染纹理),音频流可以直接输出或发送到音频源进行混合。

  • 底层原生插件渲染扩展
    我们已经扩展了底层渲染插件API,并提供了一些很酷的新特性:
    -现在可以将用户数据发送到回调函数。
    -我们已经扩展了插件将接收回调的可能事件列表。
    -我们在着色器编译器进程中添加了钩子,可以在发送到编译器之前对着色器打补丁。支持创建自定义关键字所控制的自定义变体。
    -要想了解这些扩展的威力,请查看NVIDIA的VRWorks包,它是实现这一切的基石。

  • VR: NVIDIA VRWorks
    现在,在Unity 2017.1中,NVIDIA VRWorks通过以下特性,为虚拟现实提供了一种全新高度的视觉保真度、性能和响应能力:
    -Multi-Res Shading是一种用于VR的创新性渲染技术,它可以使图像的每一部分都能渲染在一个与镜头矫正图像像素密度相匹配的分辨率上。
    -Lens Matched Shading使用NVIDIA基于Pascal的GPU的新Simultaneous Multi-Projection架构,为像素着色提供潜在的性能改进。
    -Single Pass Stereo使用NVIDIA基于Pascal的GPU的新Simultaneous Multi-Projection架构,仅对几何体进行一次绘制,即可在双眼视图同时投射相同几何体。
    -VR SLI为虚拟现实应用程序提供更高的性能,其中两个GPU可以被指派给特定眼睛,极大地加速立体渲染。
    这里写图片描述
    为了更好地利用这些改进,应该在PC上使用GeForce 9系列或更高的GPU来进行回放。可以访问Asset Store资源商店下载NVIDIA VRWorks for Unity

  • 发布说明
    与往常一样,请查阅发布说明,以了解新特性、改进和修复的完整列表。

以上内容来源Unity官方中文社区,原帖地址:http://forum.china.unity3d.com/thread-25171-1-1.html
本文仅做转载和整理。

by:蒋志杰

2014-10-25 15:58:32 qinyuanpei 阅读数 5271

       

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

喜欢我的博客请记住我的名字:秦元培,我的博客地址是blog.csdn.net/qinyuanpei

转载请注明出处,本文作者:秦元培, 本文出处:http://blog.csdn.net/qinyuanpei/article/details/40452019

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

         大家好,我是秦元培,欢迎大家关注我的博客,我的博客地址是blog.csdn.net/qinyuanpei。在Unity4.3版本以后,Unity3D推出了基于Box2D的2D组件,使得Unity3D成为一个可以支持2D游戏开发的游戏引擎。在Unity3D推出这一功能之前,大家对使用Unity3D开发2D游戏已经进行了大量的研究。所以,Unity3D推出2D组件从本质上来讲并不算是一个巨大的突破,因为二维与三维的区别就在于三维比二维多了一个Z轴,如果我们将Z轴固定,那么这就是一个二维的世界。在此之前,我们普遍采用的是正交投影法,即让摄像机垂直于XY平面进行投影,这样可以利用3D引擎实现2D游戏的效果。既然现在Unity可以支持原生2D游戏开发,为什么我们不来尝试一下呢?博主之前就打算抽时间研究下Unity3D的Native2D的特性,不过因为种种原因一直没有时间来研究,那么现在正好利用这个周末来研究下吧!


       一、精灵(Sprite)与精灵图集

    虽然我们将Unity3D的2D特性成为Native2D,不过事实上Natvite只是相对于第三方插件而言的,从本质上Unity3D的2D仍然是属于3D的范畴。精灵(Sprite)是我们走进Native2D的第一个组件,所以的2D特性都是以这个组件作为基础。学习过2D游戏开发的朋友应该知道精灵其实就是我们在2D世界里一张贴图。好了,下面我们创建一个新的项目来演示如何使用Sprite组件吧!第一个让我们激动人心的特性是我们可以在创建项目的时候就决定一个项目是3D游戏还是2D游戏,如图,这里我们直接选择2D,因为我们今天要探索的是Unity3D的Native2D特性


进入Unity后我们将注意到Unity的工具栏上会出现一个2D/3D的选项按钮且在当前场景中2D按钮被激活,这意味着这是一个2D项目,通过切换该按钮我们可以发现,Unity3D的Native2D就是将Unity3D的Z轴固定以后的效果,所以从本质上来讲Unity3D的Native2D还是3D引擎在2D效果下的一种实现。


博主从爱给网上找了点素材,做了下面的这样一个场景:


我们注意到Sprite组件中有一个最重要的SpriteRenderer组件,该组件负责的是对Sprite的渲染,我们可以通过指定Sprite这个属性来指定的渲染的资源。我们选择其中的一个图片资源,可以看到其属性窗口:


其中TextureType用来指明贴图的类型,这里我们选择Sprite类型,因为只有这种类型的贴图才能提供给Sprite组件来使用。SpriteMod用来指定精灵是一张单个的图还是一系列图集,我们注意到这张图片是一个帧动画序列,所以我们应该选择Multiple类型。接下来,我们单击SpriteEditor按钮打开精灵编辑器,目的是将这些精灵图集分割成单个的图片。如果大家阅读过博主刚开始学习Unity3D时写过的文章,一定记得博主曾经用PhotoShop将一张帧动画序列图用切图的方式分割出来,再通过绘制贴图的方式来实现帧动画吧。这样是不是很麻烦啊?没关系,Unity3D的Nativie2D提供的精灵编辑器可以帮你快速地完成这一工作。我们打开精灵编辑器:


大家可以看到这里博主将这张图片分割成了16个图片。这里有一个技巧是可以通过Trim按钮获得大小一致的图块,因为精灵编辑器可以帮助你判断图形的边界。这样做的好处是Unity可以帮你生成16张个帧动画序列,从而你可以任意地调用某一帧动画,然而资源管理器中并不会生成相应的文件,这样可以节省项目资源的大小。如图:


好了,接下来,我们来编写脚本来展示如何使用这组精灵动画:

using UnityEngine;
using System.Collections;

public class SpriteScript : MonoBehaviour {

	//向上的精灵集合
	public Sprite[] UpSprites;
    //向下的精灵集合
	public Sprite[] DownSprites;
	//向左的精灵集合
	public Sprite[] LeftSprites;
	//向右的精灵集合
	public Sprite[] RightSprites;

	//上一次使用的精灵集合
	private Sprite[] lastSprites;
	//当前使用的精灵集合
	private Sprite[] currentSprites;

	//当前帧序列索引
	private int index=0;
	//每秒帧数
	private float fps=10;
	//当前经历时间
	private float currentTime=0;

	//角色当前状态
	private PlayerState state;

	//精灵渲染器
	private SpriteRenderer renderer=null;

	void Start () 
	{
		//初始化角色状态
		state=PlayerState.Idle;
		//初始化角色精灵集合
		currentSprites=UpSprites;
		lastSprites=currentSprites;
		//获取精灵渲染器
		renderer=GetComponent<SpriteRenderer>();
	}
	

	void FixedUpdate () 
	{
		if(Input.GetAxis("Horizontal")==1){
			state=PlayerState.Walk;
			SetSprites(RightSprites);
			MoveTo(new Vector2(Time.deltaTime * 2.5F,0));
		}else if(Input.GetAxis("Horizontal")==-1){
			state=PlayerState.Walk;
			SetSprites(LeftSprites);
			MoveTo(new Vector2(-Time.deltaTime * 2.5F,0));
		}else if(Input.GetAxis("Vertical")==1){
			state=PlayerState.Walk;
			SetSprites(UpSprites);
			MoveTo(new Vector2(0,Time.deltaTime * 2.5F));
		}else if(Input.GetAxis("Vertical")==-1){
			state=PlayerState.Walk;
			SetSprites(DownSprites);
			MoveTo(new Vector2(0,-Time.deltaTime * 2.5F));
		}else if(!Input.anyKey){
			state=PlayerState.Idle;
		}
		DrawSprites(currentSprites);
	}

	//角色移动
	private void MoveTo(Vector2 offest)
	{
	   //根据偏移量计算角色位置
	   float x=transform.position.x + offest.x;
	   float y=transform.position.y + offest.y;
	   //使用2D刚体组件来移动精灵
	   this.rigidbody2D.MovePosition(new Vector2(x,y));
	}

	//设置当前精灵集合
	private void SetSprites(Sprite[] sprites)
	{
		currentSprites=sprites;
	    //如果当前精灵集合和上一次使用的精灵集合不等则表明要切换精灵集合
		if(currentSprites!=lastSprites)
		{
		   lastSprites=currentSprites;
		   index=0;
		}
	}

    //绘制当前精灵集合
	private void DrawSprites(Sprite[] sprites)
	{
	  //如果角色处于站立状态则显示第一帧
	  if(state==PlayerState.Idle){
		 renderer.sprite=sprites[0];
	  }else{
		 currentTime+=Time.deltaTime;
		 //如果当前时间大于帧动画渲染时间则需要渲染新的帧动画
		 if(currentTime>1/fps){
			//使索引增加并将当前时间清零以便于重新计数
		    index+=1;
			currentTime=0;
			//使索引连续画面循环
			if(index>=sprites.Length){
			   index=0;
			}
		 }
	  }
	  //渲染
	  renderer.sprite=sprites[index];
	}
	
	#region 角色状态枚举定义#
	enum PlayerState
	{
		Walk,
		Idle
	}
	#endregion
}
那么,我们来看看实际的运行效果吧:



这是一个控制人物沿着上、下、左、右四个方向进行移动的动画效果,我们很容易就实现了。不过,我们代码似乎写了不少啊,那么有没有一种更好的方法呢?在Unity3D没有推出2D组件的时候,我们可以以贴图的形式来绘制一个Sprite,对于这种帧动画序列图片,我们可以通过offset来决定贴图上要显示的位置。不过这种方法似乎只对普通的贴图管用,对于Sprite无能为力。博主个人还是喜欢使用这种方式,毕竟有了精灵编辑器后,切图就是一件很简单的事情了。下面,我们再来给出一个通用的脚本,该脚本可以实现任何连续帧动画的循环播放,适合在游戏中表现相对玩家来说静止的效果,比如在游戏中飘扬的旗子、飞来飞去的小鸟等等:

using UnityEngine;
using System.Collections;

public class FightScript: MonoBehaviour {

	//序列帧动画集合
	public Sprite[] Animations;
	//当前帧序列索引
	private int index=0;
	//每秒帧数
	public float fps=10;
	//当前经历时间
	private float currentTime=0;
	//精灵渲染器
	private SpriteRenderer renderer;

	void Start()
	{
		//获取精灵渲染器
		renderer=GetComponent<SpriteRenderer>();
	}

	void FixedUpdate () 
	{
		DrawSprite();
	}

	//提供一个外部接口以便于随时改变动画
	public void SetAnimations(Sprite[] sprites,int index)
	{
		this.Animations=sprites;
		this.index=index;
	}

	//根据精灵集合播放动画
	void DrawSprite()
	{
		currentTime+=Time.deltaTime;
		//如果当前时间大于帧动画渲染时间则需要渲染新的帧动画
		if(currentTime>1/fps){
			//使索引增加并将当前时间清零以便于重新计数
			index+=1;
			currentTime=0;
			//使索引连续画面循环
			if(index>=Animations.Length){
				index=0;
			}
		}
	   //渲染
	   renderer.sprite=Animations[index];
	}
}
这个脚本的特点是只要指定了一系列帧动画序列,就可以让动画从某一帧开始循环播放动画。下面,我们添加两个带有攻击效果的Sprite:

怎么样?效果还不错吧,哈哈。好了,下面我们来说说精灵图集吧!大家可以注意到随着项目的持续推进,项目中使用的图片资源会越来越多,如果不注意控制的话,整个游戏的体积会越来越大。为了解决这个问题,Unity提供了精灵图集的打包制作功能Sprite Packer。所谓精灵图集呢,其实就是把分散的图片资源集中到一张图片啊,这样可以减少图片资源的容量。这其实有点类似于NGUI里面的图集啦,博主前段时间还解包了《仙剑奇侠传四》的部分资源,对于游戏中的图片资源它同样是采用这种方式进行处理的。好了,下面我们就来看看如何在Unity3D中实现精灵打包吧!首先需要在Unity中启用Sprite Packer功能:

接下来通过Window->Sprite Packer打开Sprite Packer窗口后,然后到项目资源中选择要打包的图片资源,并将其Packing Tag设为同一个名称如enemys,这样它们将会被打包在同一张图片上。

接下来我们点击Pack,就会发现这些图片被合成在一张图片上,如果我们修改任何一张图片的Packing Tag,则这张图片会从当前图集中消失。

好了,第一部分内容到此结束,大家稍作休整,我们开始本文的第二部分:2D物理世界一样美好


     二、2D物理与Box2D

     提及2D游戏引擎就不能不说Box2D。Box2D是一个用于模拟2D刚体物体的C++引擎,通常作为物理引擎被用到2D游戏引擎中,因此在很多游戏引擎中都能找到它的身影,而Unity3D的Native2D就是使用了Box2D这个引擎。关于这个引擎的细节大家可以自己去了解,总之如果游戏世界缺少了碰撞,那么游戏世界未免太无趣了吧!人生就像愤怒的小鸟,当你失败的时候总有猪在笑。该面对的我们还是要去面对,就算在现实中碰壁被撞得头破血流,可是这样的人生总是值得我们去追逐的,因为寒冷寂寞的生,终究是比不上轰轰烈烈的死。好了,闲话少叙,我们下面来一起学习下Unity3D中2D物理吧。在Unity3D中,所有与2D物理相关的组件都被放到Physics  2d这个父菜单中,因此我们可以在这里找到相关的2D物理组件。Unity中提供的2D物理组件主要有三类:刚体、碰撞体、关节。目前我们只需要关注刚体和碰撞体就可以了。估计2D物理这块很多朋友会觉得无所谓吧,大不了自己写呗。博主之前和一个朋友交流,他做的一款打击感不错ARPG手游从头到尾从来没有用过碰撞,所有的逻辑几乎都是自己写的,因为2D物理实在是简单啊,只要通过计算距离就可以了。可是作为一名有节操的程序员,在深刻理解了不重复制造轮子这一内涵后,还会执着地自己写碰撞检测吗?所以我们这里就直接使用Unity提供的2D组件了。我们首先给主角添加一个刚体Rigidbody 2D组件,并勾选Fixed Anglg这是因为我们在碰撞的过程中并不需要角度的变化。同样,我们不需要重力,所以需要将Gravity Angle设为0.如图:


接下来我们分别给场景里的主角、两个战斗角色和一个NPC添加Box Collider 2D碰撞器,并编写以下脚本来分别测试碰撞器和触发器,这里需要把握一个细节,就是如果需要物体碰撞后有力的效果,则需要给该物体增加一个刚体组件,因为力的作用是相互的。下面给出脚本:

using UnityEngine;
using System.Collections;

public class CollisionCheck : MonoBehaviour {

	void OnCollisionEnter2D(Collision2D Coll2D)
	{
		if(Coll2D.gameObject.tag=="Fight Player")
		{
			Debug.Log("请离我远一点,我正在练习绝世武功!");
		}
	}

	void OnTriggerEnter2D(Collider2D Coll2D)
	{
		if(Coll2D.gameObject.tag=="NPC Player")
		{
			Debug.Log(" 尽管我是一名NPC,但是我的戏份还是要有的!");
		}
	}
}
2D物理世界里的碰撞检测和3D物理世界里的碰撞检测基本一致,大家可以参考官方最新的API文档,因为国内翻译的API文档基本上都没有这一部分。好了,我们来看看运行效果吧!


       好啦,今天的内容就是这样了,希望大家喜欢啊,为什么每次写完博客都这么累啊?难道是因为要查阅大量的资料吗?有不懂的地方大家可以给我留言,我尽量给大家解决,还是希望大家能关注和支持博主的博客,这样博主才有勇气一直写下去。好了,就这样啦!


每日箴言:生命中所有的挫折与伤痛,所有的经历,都是为了造就你锻炼你。不要总说岁月残忍,它其实温柔了你。




-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

喜欢我的博客请记住我的名字:秦元培,我的博客地址是blog.csdn.net/qinyuanpei

转载请注明出处,本文作者:秦元培, 本文出处:http://blog.csdn.net/qinyuanpei/article/details/40452019

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------


2014-10-16 16:25:49 jiguangcanhen 阅读数 5464
         这两天刚刚接触Unity3d,之前一直是做android开发,对于Unity3d的开发有专门的人才,我主要涉及在Unity3d与android的交互,经过两天是实验终于完成了下面的效果:
本来想写几篇博客,来详细说明下Unity3d导出android Project然后再进行二次开发的过程,后来发现几篇博客,过程和我的类似,对于重复的过程我就不写了,大家参考他的博客就可以了。而且,包括了Unity3d调用android脚本,这一块我暂时还没有涉及。
在此,道一声博主辛苦,对于上面的三篇博客大家看完之后,肯定已经可以从Unity3d导出android project,然后再倒入Eclipse了。我们可以看到MainActivity不是继承自NativeActivity就是集成自UnityPlayerActivity(或者UnityPlayerNativeActivity),这样就会给新手一个错觉,就是要展示Unity3d的视图,就必须要集成自这几个接口,那么这个想法,是错误的,具体大家可以参考一下这个博客:
这个帖子中,就是使用继承自Activity的类来展示的U3d的视图。
这样的话,之前可能存在的一个问题,如果只能继承自那几个类,那么supportV4包中的Fragment岂不是不能用了,我们都知道,android.app.Fragment只支持2.3以上的版本,而V4中可以支持到1.6,所以一般来说都推荐大家使用V4包中的Fragment。
好了,说完这个问题,我们就看上面那个效果,如果在android原生应用的话,这个是很常见也很简单的应用,我们可以不停的切换中间的Fragment。
那么换成Fragment来展示U3d,并且相互切换的话,应该怎么样书写代码呢?大家看看下面两个代码块。
/**
 * 主界面
 * @author gavin
 *
 */
public class MainActivity extends FragmentActivity implements OnClickListener {

	private Button btn1;
	private Button btn2;
	private FragmentManager fm;
	View playerView;
	private Fragment currentFragment;
	private U3dFragment u3dFragment = new U3dFragment();
	private MenuOneFragment menuOneFragment = new MenuOneFragment();
	private MenuTwoFragment menuTwoFragment = new MenuTwoFragment();
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.onCreate(savedInstanceState);
		Constants.mUnityPlayer = new UnityPlayer(this);
		int glesMode = Constants.mUnityPlayer.getSettings().getInt("gles_mode", 1);
		boolean trueColor8888 = false;
		Constants.mUnityPlayer.init(glesMode, trueColor8888);
		
		fm = getSupportFragmentManager();
		
		setContentView(R.layout.activity_main);
		initView();
		currentFragment = u3dFragment;
		changeFragment(currentFragment);
		
	}
	
	/**
	 * 初始化控件
	 */
	private void initView(){
		btn1 = (Button) findViewById(R.id.btn1);
		btn2 = (Button) findViewById(R.id.btn2);
		btn1.setOnClickListener(this);
		btn2.setOnClickListener(this);
	}
	
	@Override
	public void onClick(View v) {
		// TODO Auto-generated method stub
		switch(v.getId()){
			case R.id.btn1:
				Toast.makeText(MainActivity.this, "btn1", Toast.LENGTH_SHORT).show();
				if(currentFragment instanceof U3dFragment || currentFragment instanceof MenuTwoFragment){
					currentFragment = menuOneFragment;
					changeFragment(currentFragment);
				}else{
					currentFragment = u3dFragment;
					changeFragment(currentFragment);
				}
				break;
			case R.id.btn2:
				Toast.makeText(MainActivity.this, "btn2", Toast.LENGTH_SHORT).show();
				if(currentFragment instanceof U3dFragment || currentFragment instanceof MenuOneFragment){
					currentFragment = menuTwoFragment;
					changeFragment(currentFragment);
				}else{
					currentFragment = u3dFragment;
					changeFragment(currentFragment);
				}
				break;
		}
	}
	
	/**
	 * 方法用来改变界面
	 */
	private void changeFragment(Fragment fragment){
		FragmentTransaction ft = fm.beginTransaction();
		ft.replace(R.id.content, fragment);
		ft.commit();
	}
	
	protected void onDestroy ()
	{
		Constants.mUnityPlayer.quit();
		super.onDestroy();
	}

	// onPause()/onResume() must be sent to UnityPlayer to enable pause and resource recreation on resume.
	protected void onPause()
	{
		super.onPause();
		Constants.mUnityPlayer.pause();
	}
	protected void onResume()
	{
		super.onResume();
		Constants.mUnityPlayer.resume();
	}
	public void onConfigurationChanged(Configuration newConfig)
	{
		super.onConfigurationChanged(newConfig);
		Constants.mUnityPlayer.configurationChanged(newConfig);
	}
	public void onWindowFocusChanged(boolean hasFocus)
	{
		super.onWindowFocusChanged(hasFocus);
		Constants.mUnityPlayer.windowFocusChanged(hasFocus);
	}
	public boolean dispatchKeyEvent(KeyEvent event)
	{
		if (event.getAction() == KeyEvent.ACTION_MULTIPLE)
			return Constants.mUnityPlayer.onKeyMultiple(event.getKeyCode(), event.getRepeatCount(), event);
		return super.dispatchKeyEvent(event);
	}

}
上面是Activity的写法。
/**
 * 展示u3d的界面
 * @author gavin
 *
 */
public class U3dFragment extends Fragment {

	private Activity context;
	View playerView;
	@Override
	public void onAttach(Activity activity) {
		// TODO Auto-generated method stub
		super.onAttach(activity);
		context = activity;
	}

	@Override
	public void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.onCreate(savedInstanceState);
	}

	@Override
	public View onCreateView(LayoutInflater inflater,
			@Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		playerView = Constants.mUnityPlayer.getView();
		LayoutParams lp = new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);
		playerView.setLayoutParams(lp);
		if(playerView.getParent() != null){
			((ViewGroup)playerView.getParent()).removeAllViews();
		}
		return playerView;
	}

	@Override
	public void onDestroy() {
		// TODO Auto-generated method stub
//		Constants.mUnityPlayer.quit();
		super.onDestroy();
	}

	@Override
	public void onPause() {
		// TODO Auto-generated method stub
		super.onPause();
		Constants.mUnityPlayer.pause();
	}

	@Override
	public void onResume() {
		// TODO Auto-generated method stub
		super.onResume();
		Constants.mUnityPlayer.resume();
	}
	
}
上面是展示U3d视图的Fragment的写法。
要注意的有以下几点:
1.UnityPlayer这个对象被定义为了静态变量,在MainActivity中进行初始化,在Fragment中进行使用,用来获取Unity3d的view。
2.在U3dFragment中没有在onDestroy中,调用quit()方法。
3.在U3dFragment中的onCreateView()方法中,进行了下面的处理。
((ViewGroup)playerView.getParent()).removeAllViews();

对于上面三个问题,如果不处理会相应的引发下面三个问题。
1.展示U3d视图的Fragment无法显示Unity3d的动画效果。
2.切换页面的时候会报下面的错误:
10-16 13:26:44.927: D/dalvikvm(8170): Unregistering JNI method Lcom/unity3d/player/UnityPlayer;.nativeVideoFrameCallback:VILII
10-16 13:26:44.927: D/dalvikvm(8170): Unregistering JNI method Lcom/unity3d/player/UnityPlayer;.nativeSoftInputClosed:V
10-16 13:26:44.927: D/dalvikvm(8170): Unregistering JNI method Lcom/unity3d/player/UnityPlayer;.nativeSetTouchDeltaY:VF
10-16 13:26:44.927: D/dalvikvm(8170): Unregistering JNI method Lcom/unity3d/player/UnityPlayer;.nativeSetInputString:VL
10-16 13:26:44.927: D/dalvikvm(8170): Unregistering JNI method Lcom/unity3d/player/UnityPlayer;.nativeSetInputCanceled:VZ
10-16 13:26:44.927: D/dalvikvm(8170): Unregistering JNI method Lcom/unity3d/player/UnityPlayer;.nativeSetExtras:VL
10-16 13:26:44.927: D/dalvikvm(8170): Unregistering JNI method Lcom/unity3d/player/UnityPlayer;.nativeSetDefaultDisplay:VI
10-16 13:26:44.927: D/dalvikvm(8170): Unregistering JNI method Lcom/unity3d/player/UnityPlayer;.nativeResume:V
10-16 13:26:44.927: D/dalvikvm(8170): Unregistering JNI method Lcom/unity3d/player/UnityPlayer;.nativeResize:VIIII
10-16 13:26:44.927: D/dalvikvm(8170): Unregistering JNI method Lcom/unity3d/player/UnityPlayer;.nativeRequestedAA:I
10-16 13:26:44.927: D/dalvikvm(8170): Unregistering JNI method Lcom/unity3d/player/UnityPlayer;.nativeRequested32bitDisplayBuffer:Z
10-16 13:26:44.927: D/dalvikvm(8170): Unregistering JNI method Lcom/unity3d/player/UnityPlayer;.nativeRender:Z
10-16 13:26:44.927: D/dalvikvm(8170): Unregistering JNI method Lcom/unity3d/player/UnityPlayer;.nativeRecreateGfxState:VL
10-16 13:26:44.927: D/dalvikvm(8170): Unregistering JNI method Lcom/unity3d/player/UnityPlayer;.nativePause:Z
10-16 13:26:44.927: D/dalvikvm(8170): Unregistering JNI method Lcom/unity3d/player/UnityPlayer;.nativeKeysPressed:VL
10-16 13:26:44.927: D/dalvikvm(8170): Unregistering JNI method Lcom/unity3d/player/UnityPlayer;.nativeInjectEvent:ZL
10-16 13:26:44.927: D/dalvikvm(8170): Unregistering JNI method Lcom/unity3d/player/UnityPlayer;.nativeInitWWW:VL
10-16 13:26:44.927: D/dalvikvm(8170): Unregistering JNI method Lcom/unity3d/player/UnityPlayer;.nativeFocusChanged:VZ
10-16 13:26:44.927: D/dalvikvm(8170): Unregistering JNI method Lcom/unity3d/player/UnityPlayer;.nativeFile:VL
10-16 13:26:44.927: D/dalvikvm(8170): Unregistering JNI method Lcom/unity3d/player/UnityPlayer;.nativeDone:V
10-16 13:26:44.927: D/dalvikvm(8170): Unregistering JNI method Lcom/unity3d/player/UnityPlayer;.nativeActivityIndicatorStyle:I
10-16 13:26:44.927: D/dalvikvm(8170): Unregistering JNI method Lcom/unity3d/player/UnityPlayer;.initJni:VL
10-16 13:26:44.927: D/dalvikvm(8170): Unregistering JNI method Lcom/unity3d/player/UnityPlayer;.UnitySendMessage:VLLL
10-16 13:26:44.927: D/dalvikvm(8170): Unregistering JNI method Lcom/unity3d/player/UnityPlayer;.nativeSetLocationStatus:VI
10-16 13:26:44.927: D/dalvikvm(8170): Unregistering JNI method Lcom/unity3d/player/UnityPlayer;.nativeSetLocation:VFFFFDF
10-16 13:26:44.927: D/dalvikvm(8170): Unregistering JNI method Lcom/unity3d/player/UnityPlayer;.nativeForwardEventsToDalvik:VZ
10-16 13:26:44.927: D/dalvikvm(8170): Unregistering JNI method Lcom/unity3d/player/UnityPlayer;.nativeDeviceOrientation:VI
10-16 13:26:44.927: D/dalvikvm(8170): Unregistering JNI method Lorg/fmod/FMODAudioDevice;.fmodUnblockStreaming:I
10-16 13:26:44.927: D/dalvikvm(8170): Unregistering JNI method Lorg/fmod/FMODAudioDevice;.fmodProcess:IL
10-16 13:26:44.927: D/dalvikvm(8170): Unregistering JNI method Lorg/fmod/FMODAudioDevice;.fmodInitJni:I
10-16 13:26:44.927: D/dalvikvm(8170): Unregistering JNI method Lorg/fmod/FMODAudioDevice;.fmodGetInfo:II
10-16 13:26:44.927: D/dalvikvm(8170): Unregistering JNI method Lorg/fmod/FMODAudioDevice;.fmodBlockStreaming:I
10-16 13:26:44.927: D/dalvikvm(8170): Unregistering JNI method Lorg/fmod/FMODAudioDevice;.fmodProcessMicData:ILI
10-16 13:26:44.927: D/dalvikvm(8170): Unregistering JNI method Lcom/unity3d/player/ReflectionHelper;.nativeProxyInvoke:LILL
10-16 13:26:44.927: D/dalvikvm(8170): Unregistering JNI method Lcom/unity3d/player/ReflectionHelper;.nativeProxyFinalize:VI
3.会报下面的错误:
Caused by: java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.

现在来说,功能是实现了,但是还有很多可以改进和不明白的地方,大家可以一起讨论一下。


unity3d环境搭建

阅读数 88

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