美文网首页Unity3d
Unity基础(15)-Application与SceneMan

Unity基础(15)-Application与SceneMan

作者: 元宇宙协会 | 来源:发表于2018-07-06 09:56 被阅读111次

    Application类与SceneManager类

    • 在较早Unity版本之前,Application类负责:应用程序运行时数据,获取并加载场景(异步,同步),随着移动端兴起,后期版本中只负责获取跟应用程序运行时数据,而场景相关的被SceneManager替代。这也是与其他移动平台结合的改变。


      移动端
    静态属性
    • Application静态属性:
      dataPath属性 : 数据文件路径
      public static string dataPath{ get; }
      Application.dataPath 返回程序的数据文件所在文件夹的路径(只读).返回路径为相对路径,不同游戏平台的数据文件保存路径不同,Editor中就是项目的Assets文件夹的路径,通过这个路径可以访问项目中任何文件夹中的资源,但是在移动端它是完全没用。
      Application.persistentDataPath 此属性返回一个持久化数据存储目录的路径,可以在此路径下存储一些持久化的数据文件。这个路径可读、可写,但是只能在程序运行时才能读写操作,不能提前将数据放入这个路径。在IOS上是应用程序的沙盒,可以被iCloud自动备份,可以通过同步推送一类的助手直接取出文件;在Android上的位置是根据Project Setting里设置的Write Access路径,可以设置是程序沙盒还是sdcard,注意:如果在Android设置保存在沙盒中,那么就必须root以后才能用电脑取出文件,因此建议写入sdcard里。一般情况下,建议将获得的文件保存在这个路径下,例如可以从StreamingAsset中读取的二进制文件或者从AssetBundle读取的文件写入PersistentDatapath。
      Application.streamingAassetsPath 此属性用于返回流数据的缓存目录,返回路径为相对路径,适合设置一些外部数据文件的路径.在PC/MAC中可实现对文件的“增删改查”等操作,但在移动端是一个只读路径。
      Application.temporaryCachePath 此属性返回一个临时数据的缓存目录,跟Application.persistentDataPath类似,但是在IOS上不能被自动备份
      以上各路径中的资源加载方式都可以用WWW类加载,但要注意各个平台路径需要加的访问名称,例如Android平台的路径前要加"jar:file://",其他平台使用"file://"。以下是各路径在各平台中的具体位置信息:
    • Android平台
    Application.dataPath :  /data/app/xxx.xxx.xxx.apk
    Application.streamingAssetsPath :  jar:file:///data/app/xxx.xxx.xxx.apk/!/assets
    Application.persistentDataPath :  /data/data/xxx.xxx.xxx/files
    Application.temporaryCachePath :  /data/data/xxx.xxx.xxx/cache
    
    • IOS平台
    Application.dataPath :                    Application/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/xxx.app/Data
    Application.streamingAssetsPath : Application/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/xxx.app/Data/Raw
    Application.persistentDataPath :    Application/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/Documents
    Application.temporaryCachePath : Application/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/Library/Caches
    
    • Windows Web Player
    Application.dataPath :  file:///D:/MyGame/WebPlayer (即导包后保存的文件夹,html文件所在文件夹)
    Application.streamingAssetsPath : 
    Application.persistentDataPath : 
    Application.temporaryCachePath : 
    
    #if UNITY_EDITOR
    string filepath = Application.dataPath +"/StreamingAssets"+"/version.txt";
    #elif UNITY_IPHONE
     string filepath = Application.dataPath +"/Raw"+"/my.xml";
    #elif UNITY_ANDROID
     string filepath = "jar:file://" + Application.dataPath + "!/assets/"+"/version.txt";
    #endif
    

    StreamingAssets在各个平台上的文本支持读取方式
    string path = System.IO.Path.Combine(Application.streamingAssetsPath,"version.txt");

    ## Editor:
    1::System.IO.File.ReadAllText (path);
    2:path = "file://"+path;或者 path = "file:/"+path;或者 path = "file:\\"+path或者 path = "file:\\\\"+path;在win7上都可以 在mac上path = "file:/"+path不可以外,别的都可以 
    然后WWW www = new WWW (path);
    
    ## Android:
    1:WWW www = new WWW (path);
    
    ##  iphone:
    1:System.IO.File.ReadAllText (path);
    2:path = "file://"+path;System.IO.File.ReadAllText (path); 
    
    还有一点就是在读取streamingAssets目录下的文本文件时android平台必须要用www来读取哦,因为android平台是被压缩在apk中,
    所以不能直接用CSharp去读,ios可以直接用System.IO.File.ReadAllText(filePath)
    
    
    • loadedLevel属性 :
      SceneManager.GetActiveScene().buildIndex返回当前场景的索引值
      SceneManager.GetActiveScene().name返回当前场景的名字
      SceneManager.sceneCountInBuildSettings游戏中可被加载的场景数量
      Application.platform 当前游戏的运行平台,返回值为枚举类型
      Application.isPlaying 当前游戏是否正在运行
      Application.isEditor 游戏是否处于Unity编辑模式

    • Application类静态方法:
      旧方法Application.CaptureScreenshot方法 : 截屏

    目前改为了:ScreenCapture.CaptureScreenshot
    public static void CaptureScreenshot(string filename);
    参数filename 截屏文件名称 superSize放大系数,默认为0,即不放大
    public static void CaptureScreenshot(string filename, int superSize);
    此方法截取当前游戏画面并保存为PNG格式,文件默认保存在根目录下,若有重名文件则替换.

     public void CameraGame()
     {
             Debug.Log(Application.dataPath);
             string fileName = Application.dataPath +"/Images/" + Time.time+ ".png";
             ScreenCapture.CaptureScreenshot(fileName);
     }
    
      public void CameraGame()
      {
             Debug.Log(Application.dataPath);
            StartCoroutine(GetScreenCamera());
      }
    
     IEnumerator GetScreenCamera()
     {
            yield return new WaitForEndOfFrame();
            Texture2D t = new Texture2D(100, 100, TextureFormat.RGB24, false);
            t.ReadPixels(new Rect(0, 0, 100, 100), 0, 0);
            // 保存图片
            t.Apply();
            byte[] imgB = t.EncodeToPNG();
            System.IO.File.WriteAllBytes(Application.dataPath + "/Images/" + Time.time + ".png", imgB);
      }
    
    • RegisterLogCallback方法 :注册委托
      方法1:Application.RegisterLogCallback
      static function RegisterLogCallback (handler : Application.LogCallback) : void
      在一个日志信息上注册一个委托来被调用,这个函数和RegisterLogCallback唯

    方法2:Application.RegisterLogCallbackThreaded
    static function RegisterLogCallbackThreaded (handler : Application.LogCallback) : void
    在一个日志信息上注册一个委托来被调用,这个函数和RegisterLogCallback唯一不同的是,这个函数将从不同的线程被调用,注意:你只有你知道你在做什么时才能使用这个函数,否则使用Application.RegisterLogCallback。

    两个方法在使用的时候,都需要传递一个委托
    public delegate void LogCallback (string condition, string stackTrace, LogType type);
    第一个参数为日志描述信息,第二个参数为日志产生的栈数据,第三个参数为日志的类型

    using UnityEngine;
    using System.Collections;
    using UnityEngine.UI;
    
    public class LogMessage : MonoBehaviour {
        string  message="";
        public Text text;
        void Start () {
            //在一个日志信息上注册一个委托来被调用
            Application.logMessageReceivedThreaded +=MyLogCallback;
        }
    
        void Update () {
            text.text = message;
        }
    
        /// <summary>
        /// log callback check
        /// </summary>
        /// <param name="condition">日志描述信息log内容.</param>
        /// <param name="stackTrace">log产生的栈数据追踪</param>
        /// <param name="type">log的类型.</param>
        void  MyLogCallback (string condition, string stackTrace, LogType type){
            switch(type){
            case LogType.Assert:
                message += "      receive an assert log"+",condition="+condition+",stackTrace="+stackTrace;
                break;
            case LogType.Error:
                message += "      receive an Error log"+",condition="+condition+",stackTrace="+stackTrace;
                break;
            case LogType.Exception:
                message += "      receive an Exception log"+",condition="+condition+",stackTrace="+stackTrace;
                break;
            case LogType.Log:
                message += "      receive an Log log"+",condition="+condition+",stackTrace="+stackTrace;
                break;
            case LogType.Warning:
                message += "      receive an Warning log"+",condition="+condition+",stackTrace="+stackTrace;
                break;
            }
        }
    
        void OnGUI(){
            if(GUI.Button(new Rect(10,20,200,40),"assert")){
                Debug.LogAssertion ("assertion");
            }else if(GUI.Button(new Rect(10,80,200,40),"error")){
                Debug.LogError ("error");
            }else if(GUI.Button(new Rect(10,140,200,40),"exception")){
                Debug.LogException (new System.NullReferenceException());
            }else if(GUI.Button(new Rect(10,200,200,40),"log")){
                Debug.Log ("log");
            }else if(GUI.Button(new Rect(10,260,200,40),"warning")){
                Debug.LogWarning ("waring");
            }
        }
    }
    

    Application相关事件函数

    OnApplicationPause(bool pause) 如果应用程序暂停,则为True,否则为False
    OnApplicationFocus(bool focus) 如果应用程序失去焦点
    OnApplicationQuit() 程序退出事件

    `强制暂停时`,先 `OnApplicationPause`,后 `OnApplicationFocus`;
    `重新“启动”手机时`,先`OnApplicationFocus`,后 `OnApplicationPause`;
    `启用键盘按Home`不会调用OnApplicationFocus,而是调用OnApplicationPause;
    `安卓上启用手机键盘`,会调用OnApplicationFocus](false)事件。
      private void OnApplicationPause(bool pause)
        {
            Debug.Log("停止程序" + pause);
        }
        private void OnApplicationFocus(bool focus)
        {
            Debug.Log("程序失去焦点" + focus);
        }
    
    
      // 当前应用双击Home,然后Kill(IOS 有回调,android 没回调)
      private void OnApplicationQuit()
        {
            QuitGame();
        }
        public void QuitGame()
        {
            Debug.Log("Quit");
            // 在编辑器或者web播放器中退出被忽略
            // Application.Quit();
    #if UNITY_EDITOR
            UnityEditor.EditorApplication.isPlaying = false;
    #elif UNITY_IPHONE
            Application.Quit();
    #elif UNITY_ANDROID
           Application.Quit();
    #else
            Application.Quit();
    #endif
        }
    

    SceneManager

    通常游戏的主场景包含的资源较多,这会导致加载场景的时间较长。
    为了避免这个问题,可以首先加载Loading场景,然后再通过Loading场景来加载主场景。
    因为Loading场景包含的资源较少,所以加载速度快。
    在加载主场景的时候一般会在Loading界面中显示一个进度条来告知玩家当前加载的进度。
    在Unity中可以通过调用SceneManager.LoadSceneAsync(旧版本:Application.LoadLevelAsync)函数来异步加载游戏场景,
    通过查询AsyncOperation.progress的值来得到场景加载的进度。
    通过Unity提供的Coroutine机制,我们可以方便的在每一帧结束后调用SetLoadingPercentage函数来更新界面中显示的进度条的数值。
    SceneManager.LoadSceneAsync()
    此方法用于按照关卡名字在后台异步加载关卡到当前场景中,此方法只是将新关卡加载到当前场景,当前场景的原有内容不会被销毁.
    AsynvOperation colve = public static AsynvOperation LoadLevelAdditiveAsync(int index);
    colve.isDone 是否加载完成
    colve.progress 加载进度

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.UI;
    using UnityEngine.SceneManagement;
    using System;
    
    public class Loading : MonoBehaviour {
    
        public Slider loadingSlider;
        public Text loadingText;
        public AsyncOperation op;
        public float targetValue;
    
        void Start () {
            loadingSlider.value = 0.0f;
            // 判断当前场景的名字是Loading
            if (SceneManager.GetActiveScene().name == "Loading")
            {
                // 加载下一个场景
                StartCoroutine(AsyncLoading());
            }
        }
    
        private IEnumerator AsyncLoading()
        {
            op =  SceneManager.LoadSceneAsync(3);
            // 阻止当加载完成自动切换
            op.allowSceneActivation = false;
            // 
            yield return op;
        }
    
        void Update () {
            Debug.Log(op.progress);
            targetValue = op.progress;
            if (op.progress >= 0.9f)
            {
                    //operation.progress的值最大为0.9
                    targetValue = 1.0f;
            }
            if (targetValue != loadingSlider.value)
            {
                //插值运算
                loadingSlider.value = Mathf.Lerp(loadingSlider.value, targetValue, Time.deltaTime * 1);
                if (Mathf.Abs(loadingSlider.value - targetValue) < 0.01f)
                {
                    loadingSlider.value = targetValue;
                }
            }
            loadingText.text = ((int)(loadingSlider.value * 100)).ToString() + "%";
            if ((int)(loadingSlider.value * 100) == 100)
            {
                //允许异步加载完毕后自动切换场景
                op.allowSceneActivation = true;
            }
        }
    }
    

    第二种方式:进度条加载

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.SceneManagement;
    using UnityEngine.UI;
    
    public class LoadScene : MonoBehaviour {
        public Slider sl;
        public Text t;
        void Start () {
            sl.value = 0;
            StartCoroutine(LoadingScene());
        }
    
        private IEnumerator LoadingScene(int scene)
        {
            AsyncOperation op = SceneManager.LoadSceneAsync(3);
            while (!op.isDone)
            {
                t.text = op.progress * 100 + "%";
               sl.value = op.progress * 100 ;
                yield return new WaitForEndOfFrame();        
            }
        }
    
        private IEnumerator LoadingScene()
        {
            int displayProgress = 0;
            int toProgress = 0;
            AsyncOperation op = SceneManager.LoadSceneAsync(3);
            op.allowSceneActivation = false;
            while (op.progress < 0.9f)
            {
                toProgress = (int)op.progress * 100;
                while (displayProgress < toProgress)
                {
                    ++displayProgress;
                    t.text = displayProgress + "%";
                    sl.value = displayProgress * 0.01f;
                    yield return new WaitForEndOfFrame();
                }
            }
            toProgress = 100;
            while (displayProgress < toProgress)
            {
               ++displayProgress;
               t.text = displayProgress  + "%";
               sl.value = displayProgress * 0.01f;
               yield return new WaitForEndOfFrame();
            }
           op.allowSceneActivation = true;
        }
    

    相关文章

      网友评论

        本文标题:Unity基础(15)-Application与SceneMan

        本文链接:https://www.haomeiwen.com/subject/foujuftx.html