unity 2D游戏开发教程(三):共通Loading画面

1.共通Loading画面

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace MoreMountains.Tools
{
    /// <summary>
    /// 一个简单的组件,可以确保(如果在游戏中安装所有音频监听器)
    ///你永远不会再看到“场景中有两个音频听众”的警告。
    /// </summary>
    [RequireComponent(typeof(AudioListener))]
    public class MMAudioListener : MonoBehaviour
    {
        protected AudioListener _audioListener;
        protected AudioListener[] _otherListeners;

        /// <summary>
        /// 启用时,如果发现其他侦听器,则禁用它们
        /// </summary>
        protected virtual void OnEnable()
        {
            _audioListener = this.gameObject.GetComponent<AudioListener>();
            _otherListeners = FindObjectsOfType(typeof(AudioListener)) as AudioListener[];
            foreach (AudioListener audioListener in _otherListeners)
            {
                if ((audioListener != null) && (audioListener != _audioListener))
                {
                    audioListener.enabled = false;
                }
            }
        }


    }

}

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

namespace MoreMountains.Tools
{
    /// <summary>
    /// 使用加载屏幕而不是仅使用默认的API加载场景的类
    ///该类以前称为LoadingSceneManager,现在已重命名为MMSceneLoadingManager以保持一致性
    /// </summary>
    public class MMSceneLoadingManager : MonoBehaviour
    {
        public enum LoadingStatus
        {
            LoadStarted, BeforeEntryFade, EntryFade, AfterEntryFade, UnloadOriginScene, LoadDestinationScene,
            LoadProgressComplete, InterpolatedLoadProgressComplete, BeforeExitFade, ExitFade, DestinationSceneActivation, UnloadSceneLoader, LoadTransitionComplete
        }

        public struct LoadingSceneEvent
        {
            public LoadingStatus Status;
            public string SceneName;
            public LoadingSceneEvent(string sceneName, LoadingStatus status)
            {
                Debug.Log("MMSceneLoadingManager-----LoadingSceneEvent");
                Status = status;
                SceneName = sceneName;
            }
            static LoadingSceneEvent e;
            public static void Trigger(string sceneName, LoadingStatus status)
            {
                e.Status = status;
                e.SceneName = sceneName;
                MMEventManager.TriggerEvent(e);
            }
        }

        [Header("绑定")]
        /// 加载实际目标场景时要加载的场景名称(通常是加载屏幕)
        public static string LoadingScreenSceneName = "LoadingScreen";

        [Header("游戏对象")]
        /// 要在其中显示加载消息的文本对象
		public Text LoadingText;
        /// 包含进度条的画布组
        public CanvasGroup LoadingProgressBar;
        /// 包含动画的画布组
        public CanvasGroup LoadingAnimation;
        /// 包含加载完成时要播放的动画的画布组
        public CanvasGroup LoadingCompleteAnimation;

        [Header("时间")]
        /// 初始淡入淡出的持续时间(秒)
        public float StartFadeDuration = 0.2f;
        /// 进度条的速度
        public float ProgressBarSpeed = 2f;
        /// 负载完全淡出的持续时间(秒)
        public float ExitFadeDuration = 0.2f;
        /// 完成后离开场景前的延迟(秒)
        public float LoadCompleteDelay = 0.5f;

        protected AsyncOperation _asyncOperation;
        protected static string _sceneToLoad = "";
        protected float _fadeDuration = 0.5f;
        protected float _fillTarget = 0f;
        protected string _loadingTextValue;
        protected Image _progressBarImage;

        protected static MMTweenType _tween;


        /// <summary>
        /// 调用此静态方法从任何地方加载场景
        /// </summary>
        /// <param name="sceneToLoad">Level name.</param>
        public static void LoadScene(string sceneToLoad)
        {
            _sceneToLoad = sceneToLoad;
            /*
             Q:在切场景时,为什么调整Application.backgroundLoadingPriority为High
               可以减少加载耗时呢?
             A: Application.backgroundLoadingPriority这个API会限制主线程的集成的时间,
                默认设置是ThreadPriority.BelowNormal,也就是每一帧执行主线程集成的操作耗时不能超过4毫秒,
                这将会导致每一帧剩余的时间用于等待或者渲染,而这些等待和渲染的时间都是无意义的耗时(场景加载没有太多渲染)。
                如果把这个设置改为ThreadPriority.High,那么每一帧执行主线程集成的操作耗时可以增加到50毫秒,
                大大减少了所需要的帧数。
             */
            Application.backgroundLoadingPriority = ThreadPriority.High;

            if (LoadingScreenSceneName != null)
            {
                LoadingSceneEvent.Trigger(sceneToLoad, LoadingStatus.LoadStarted);
                SceneManager.LoadScene(LoadingScreenSceneName);
            }
        }

        /// <summary>
        /// 调用此静态方法从任何地方加载场景
        /// </summary>
        /// <param name="sceneToLoad">Level name.</param>
        public static void LoadScene(string sceneToLoad, string loadingSceneName)
        {
            _sceneToLoad = sceneToLoad;
            Application.backgroundLoadingPriority = ThreadPriority.High;
            LoadingSceneEvent.Trigger(sceneToLoad, LoadingStatus.LoadStarted);
            SceneManager.LoadScene(loadingSceneName);
        }



        /// <summary>
		/// On Start(), 我们开始异步加载新级别
		/// </summary>
		protected virtual void Start()
        {
            _tween = new MMTweenType(MMTween.MMTweenCurve.EaseOutCubic);
            _progressBarImage = LoadingProgressBar.GetComponent<Image>();
            _loadingTextValue = LoadingText.text;
            if (!string.IsNullOrEmpty(_sceneToLoad))
            {
                StartCoroutine(LoadAsynchronously());
            }
        }

        /// <summary>
		/// 每一帧,我们都会根据加载进度顺利填充条形图
		/// </summary>
		protected virtual void Update()
        {
            Time.timeScale = 1f;
            //根据指定的速度从“from”移动到“to”并返回相应的值
            //不用这个方法就会看到进度条,一段一段的跳,这个方法的画让进度条很顺滑的进行变化
            _progressBarImage.fillAmount = MMMaths.Approach(_progressBarImage.fillAmount, _fillTarget, Time.deltaTime * ProgressBarSpeed);
        }

        /// <summary>
		/// 加载场景以异步加载
		/// </summary>
		protected virtual IEnumerator LoadAsynchronously()
        {
            // 我们设置了各种视觉元素
            LoadingSetup();
            // 我们从黑暗中消失
            MMFadeOutEvent.Trigger(StartFadeDuration, _tween);
            yield return new WaitForSeconds(StartFadeDuration);
            //在后台加载一个场景。在此期间,会加载该场景中引用的纹理、音频和 3D 模型等资源。
            // 我们开始加载场景
            _asyncOperation = SceneManager.LoadSceneAsync(_sceneToLoad, LoadSceneMode.Single);
            //设置后,就算加载完成了也不自动跳转过去
            _asyncOperation.allowSceneActivation = false;
            // 加载场景时,我们将其进度分配给一个目标,用于平滑填充进度条
            while (_asyncOperation.progress < 0.9f)
            {
                //使用_asyncOperation加载,最大加载到0.9就会暂停
                _fillTarget = _asyncOperation.progress;
                //表示暂缓一帧,有写代码可以看到yield return 10,表示的是延缓10帧再处理,这个是个误区,后面的数字没有作用的
                yield return null;
            }
            // 当负载接近末尾(它永远不会到达)时,我们将其设置为100%
            _fillTarget = 1f;
            // 我们等待酒吧在视觉上被填满,然后继续
            while (_progressBarImage.fillAmount != _fillTarget)
            {
                //表示暂缓一帧
                yield return null;
            }
            // 现在加载完成,我们用完整的动画替换条形图
            LoadingComplete();
            yield return new WaitForSeconds(LoadCompleteDelay);

            // 我们逐渐变黑
            MMFadeInEvent.Trigger(ExitFadeDuration, _tween);
            yield return new WaitForSeconds(ExitFadeDuration);

            // 我们切换到新场景
            _asyncOperation.allowSceneActivation = true;
            LoadingSceneEvent.Trigger(_sceneToLoad, LoadingStatus.LoadTransitionComplete);
        }

        /// <summary>
        /// 设置所有视觉元素,从一开始就从黑色渐变
        /// </summary>
        protected virtual void LoadingSetup()
        {
            LoadingCompleteAnimation.alpha = 0;
            _progressBarImage.fillAmount = 0f;
            LoadingText.text = _loadingTextValue;

        }

        /// <summary>
        /// 当实际加载完成时触发,用完整的动画替换进度条
        /// </summary>
        protected virtual void LoadingComplete()
        {
            LoadingSceneEvent.Trigger(_sceneToLoad, LoadingStatus.InterpolatedLoadProgressComplete);
            LoadingCompleteAnimation.gameObject.SetActive(true);
            StartCoroutine(MMFade.FadeCanvasGroup(LoadingProgressBar, 0.1f, 0f));
            StartCoroutine(MMFade.FadeCanvasGroup(LoadingAnimation, 0.1f, 0f));
            StartCoroutine(MMFade.FadeCanvasGroup(LoadingCompleteAnimation, 0.1f, 1f));
        }

    }

}

MMFade

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


namespace MoreMountains.Tools
{
    /// <summary>
    /// Fade helpers
    /// </summary>
    public static class MMFade
    {
        /// <summary>
		/// Fades the specified image to the target opacity and duration.
		/// </summary>
		/// <param name="target">Target.</param>
		/// <param name="opacity">Opacity.</param>
		/// <param name="duration">Duration.</param>
		public static IEnumerator FadeImage(Image target, float duration, Color color)
        {
            if (target == null)
                yield break;

            float alpha = target.color.a;
            for (float t = 0.0f; t < 1.0f; t += Time.deltaTime / duration)
            {
                if (target == null)
                    yield break;
                Color newColor = new Color(color.r, color.g, color.b, Mathf.SmoothStep(alpha, color.a, t));
                target.color = newColor;
                yield return null;
            }
            target.color = color;
        }

        /// <summary>
		/// Fades the specified image to the target opacity and duration.
		/// </summary>
		/// <param name="target">Target.</param>
		/// <param name="opacity">Opacity.</param>
		/// <param name="duration">Duration.</param>
		public static IEnumerator FadeText(Text target, float duration, Color color)
        {
            if (target == null)
                yield break;

            float alpha = target.color.a;
            for (float t = 0.0f; t < 1.0f; t += Time.deltaTime / duration)
            {
                if (target == null)
                    yield break;
                Color newColor = new Color(color.r, color.g, color.b, Mathf.SmoothStep(alpha, color.a, t));
                target.color = newColor;
                yield return null;
            }
            if (target != null)
            {
                target.color = color;
            }
        }

        /// <summary>
        /// Fades the specified image to the target opacity and duration.
        /// </summary>
        /// <param name="target">Target.</param>
        /// <param name="opacity">Opacity.</param>
        /// <param name="duration">Duration.</param>
        public static IEnumerator FadeSprite(SpriteRenderer target, float duration, Color color)
        {
            if (target == null)
                yield break;

            float alpha = target.material.color.a;

            float t = 0f;
            while (t < 1.0f)
            {
                if (target == null)
                    yield break;

                Color newColor = new Color(color.r, color.g, color.b, Mathf.SmoothStep(alpha, color.a, t));
                target.material.color = newColor;

                t += Time.deltaTime / duration;

                yield return null;
            }
            Color finalColor = new Color(color.r, color.g, color.b, Mathf.SmoothStep(alpha, color.a, t));
            if (target != null)
            {
                target.material.color = finalColor;
            }

        }




        public static IEnumerator FadeCanvasGroup(CanvasGroup target, float duration, float targetAlpha, bool unscaled = true)
        {
            if (target == null)
                yield break;

            float currentAlpha = target.alpha;
            float t = 0f;
            while (t < 1.0f)
            {
                if (target == null)
                    yield break;

                //SmoothStep(float from, float to, float t)
                //根据t(0---1),来获取from 到 to 之间的插值
                //currentAlpha=50  targetAlpha=0 t=0.5 ->newAlpha = 25
                //currentAlpha=50  targetAlpha=0 t=0.9 -> newAlpha = 5
                float newAlpha = Mathf.SmoothStep(currentAlpha, targetAlpha, t);
                target.alpha = newAlpha;
                //Time.deltaTime 如果1秒是60FPS 的时候 deltaTime=0.02s
                //也就是说1帧经过的时间
                if (unscaled)
                {
                    //Time.frameCount = 500  Time.frameCount = 501   每一帧进过的事件DeltaTime
                    //DeltaTime  /  duration  其实就是算现在的  DeltaTime是duration这个期间里面的 1分之几。
                    //假设unscaledDeltaTime是1秒 而duration是5秒  1 / 5 = 0.2 ,t就等于 0 + 0.2 = 0.2
                    //第一帧t是0.2 ,第二帧0.4,第三帧0.6 *** 估计过5帧后,while发现0<0.1f不满足就执行跳出while了
                    //也就等于实现了duration 5秒后,fade结束
                    t += Time.unscaledDeltaTime / duration;
                }
                else
                {
                    t += Time.deltaTime / duration;
                }
                yield return null;
            }
            target.alpha = targetAlpha;
        }


    }

}

2.StartScene开始画面

3.Editor自定义标签

using MoreMountains.Tools;
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;

public class MMInformationTest : MonoBehaviour
{
    [Header("Sprite Swap")]
    [MMInformation("如果你想要一个不同的图片和不同的颜色,你可以在这里定义用于禁用和按下状态", MMInformationAttribute.InformationType.Info, false)]
    public Sprite DisabledSprite;
    public Sprite PresseddSprite;


    [Header("Test")]
    [MMInformation("这个区域是用来测试的", MMInformationAttribute.InformationType.Info, false)]
    public int testCount;
    public float floattest;

    private void Awake()
    {

        Debug.Log("MMTouchButton----Awake");

        ///EditorPrefs.SetBool("MMShowHelpInInspectors1", true);
        //EditorPrefs.SetInt("MMShowHelpInInspectors1", 1);
        //
    }
}

using System.Collections;
using UnityEngine;

#if UNITY_EDITOR
using UnityEditor;
#endif


namespace MoreMountains.Tools
{
    public class MMInformationAttribute : PropertyAttribute
    {
        public enum InformationType { Error, Info, None, Warning }


#if UNITY_EDITOR
        public string Message;
        public MessageType Type;
        public bool MessageAfterProperty;


        public MMInformationAttribute(string message, InformationType type, bool messageAfterProperty)
        {
            this.Message = message;
            if (type == InformationType.Error) { this.Type = UnityEditor.MessageType.Error; }
            if (type == InformationType.Info) { this.Type = UnityEditor.MessageType.Info; }
            if (type == InformationType.Warning) { this.Type = UnityEditor.MessageType.Warning; }
            if (type == InformationType.None) { this.Type = UnityEditor.MessageType.None; }
            this.MessageAfterProperty = messageAfterProperty;
        }
#else
        public MMInformationAttribute(string message, InformationType type, bool messageAfterProperty)
		{

		}
#endif
    }
}
   

对编辑器属性操作,需要继承PropertyDrawer类

#if UNITY_EDITOR
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;

namespace MoreMountains.Tools
{

    //对编辑器属性操作,需要继承PropertyDrawer类
    [CustomPropertyDrawer(typeof(MMInformationAttribute))]
    public class MMInformationDrawer : PropertyDrawer
    {

        // 确定帮助框后的空间、文本框前的空间和帮助框图标的宽度
        const int spaceBeforeTheTextBox = 5;
        const int spaceAfterTheTextBox = 10;
        const int iconWidth = 55;

        MMInformationAttribute informationAttribute { get { return ((MMInformationAttribute)attribute); } }


#if UNITY_EDITOR
        /// <summary>
        /// OnGUI, 按指定顺序显示属性和文本框
        /// </summary>
        /// <param name="rect">Rect.</param>
        /// <param name="prop">Property.</param>
        /// <param name="label">Label.</param>
        public override void OnGUI(Rect rect, SerializedProperty prop, GUIContent label)
        {
            if (HelpEnabled())
            {
                EditorStyles.helpBox.richText = true;
                if (!informationAttribute.MessageAfterProperty)
                {
                    // we position the message before the property
                    rect.height = DetermineTextboxHeight(informationAttribute.Message);
                    EditorGUI.HelpBox(rect, informationAttribute.Message, informationAttribute.Type);
                    rect.y += rect.height + spaceBeforeTheTextBox;
                    EditorGUI.PropertyField(rect, prop, label, true);
                }
                else
                {
                    // we position the property first, then the message
                    rect.height = GetPropertyHeight(prop, label);
                    EditorGUI.PropertyField(rect, prop, label, true);

                    rect.height = DetermineTextboxHeight(informationAttribute.Message);
                    // we add the complete property height (property + helpbox, as overridden in this very script), and substract both to get just the property
                    rect.y += GetPropertyHeight(prop, label) - DetermineTextboxHeight(informationAttribute.Message) - spaceAfterTheTextBox;
                    EditorGUI.HelpBox(rect, informationAttribute.Message, informationAttribute.Type);
                }
                    
            }
            else
            {
                EditorGUI.PropertyField(rect, prop, label, true);
            }
               
        }

#endif

        /// <summary>
        /// 返回整个块的完整高度(属性+帮助文本)
        /// </summary>
        /// <returns>The block height.</returns>
        /// <param name="property">Property.</param>
        /// <param name="label">Label.</param>
        public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
        {
            if (HelpEnabled())
            {
                return EditorGUI.GetPropertyHeight(property) + DetermineTextboxHeight(informationAttribute.Message) + spaceAfterTheTextBox + spaceBeforeTheTextBox;
            }
            else
            {
                return EditorGUI.GetPropertyHeight(property);
            }
        }

        /// <summary>
        /// 检查编辑器首选项,查看是否启用了帮助
        /// </summary>
        /// <returns><c>true</c>, if enabled was helped, <c>false</c> otherwise.</returns>
        protected virtual bool HelpEnabled()
        {
            bool helpEnabled = false;
            if (EditorPrefs.HasKey("MMShowHelpInInspectors"))
            {
                if (EditorPrefs.GetBool("MMShowHelpInInspectors"))
                {
                    helpEnabled = true;
                }
            }
            return helpEnabled;
        }

        /// <summary>
        /// 确定文本框的高度
        /// </summary>
        /// <returns>The textbox height.</returns>
        /// <param name="message">Message.</param>
        protected virtual float DetermineTextboxHeight(string message)
        {
            GUIStyle style = new GUIStyle(EditorStyles.helpBox);
            style.richText = true;
            float newHeight = style.CalcHeight(new GUIContent(message), EditorGUIUtility.currentViewWidth - iconWidth);
            return newHeight;
        }
    }
}

#endif

4.UI组件按钮

4.1 MMTouchButton

将此组件添加到GUI图像中,使其充当按钮。
    ///捆绑被按下,不断按下,并从检查员那里释放动作
    ///操作鼠标和多点触控

5.保存机制

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

namespace MoreMountains.Tools
{
    /// <summary>
    /// 用于存储数据以测试MMSaveLoadManager类的测试对象
    /// </summary>
    [System.Serializable]
    public class MMSaveLoadTestObject
    {
        public string SavedText;
    }

    /// <summary>
    /// MMSaveLoadTestScene中用于测试MMSaveLoadManager类的简单类
    /// </summary>
    public class MMSaveLoadTester : MonoBehaviour
    {
        [Header("绑定")]
        /// 要保存的文本
        public InputField TargetInputField;

        [Header("保存设置")]
        /// 所选的保存方法(json、加密json、二进制、加密二进制)
        public MMSaveLoadManagerMethods SaveLoadMethod = MMSaveLoadManagerMethods.Binary;
        /// 要保存的文件的名称
        public string FileName = "TestObject";
        /// 目标文件夹的名称
        public string FolderName = "MMTest/";
        /// 要使用的扩展
        public string SaveFileExtension = ".testObject";
        /// 用于加密文件的密钥(如果需要)
        public string EncryptionKey = "ThisIsTheKey";

        /// Test button
        [MMInspectorButton("Save")]
        public bool TestSaveButton;
        /// Test button
        [MMInspectorButton("Load")]
        public bool TestLoadButton;
        /// Test button
        [MMInspectorButton("Reset")]
        public bool TestResetButton;

        protected IMMSaveLoadManagerMethod _saveLoadManagerMethod;

        /// <summary>
        ///将TestObject的内容保存到文件中
        /// </summary>
        public virtual void Save()
        {
            InitializeSaveLoadMethod();
            MMSaveLoadTestObject testObject = new MMSaveLoadTestObject();
            testObject.SavedText = TargetInputField.text;
            MMSaveLoadManager.Save(testObject, FileName + SaveFileExtension, FolderName);

        }

        /// <summary>
        /// 加载保存的数据
        /// </summary>
        public virtual void Load()
        {
            InitializeSaveLoadMethod();
            MMSaveLoadTestObject testObject = (MMSaveLoadTestObject)MMSaveLoadManager.Load(typeof(MMSaveLoadTestObject), FileName + SaveFileExtension, FolderName);
            TargetInputField.text = testObject.SavedText;
        }

        /// <summary>
        /// 通过删除整个文件夹重置所有保存
        /// </summary>
        protected virtual void Reset()
        {
            MMSaveLoadManager.DeleteSaveFolder(FolderName);
        }

        /// <summary>
        /// 创建新的MMSaveLoadManagerMethod并将其传递给MMSaveLoadManager
        /// </summary>
        protected virtual void InitializeSaveLoadMethod()
        {
            switch(SaveLoadMethod)
            {
                case MMSaveLoadManagerMethods.Binary:
                    _saveLoadManagerMethod = new MMSaveLoadManagerMethodBinary();
                    break;
                case MMSaveLoadManagerMethods.BinaryEncrypted:
                    _saveLoadManagerMethod = new MMSaveLoadManagerMethodBinaryEncrypted();
                    (_saveLoadManagerMethod as MMSaveLoadManagerEncrypter).Key = EncryptionKey;
                    break;
                case MMSaveLoadManagerMethods.Json:
                    _saveLoadManagerMethod = new MMSaveLoadManagerMethodJson();
                    break;
                case MMSaveLoadManagerMethods.JsonEncrypted:
                    _saveLoadManagerMethod = new MMSaveLoadManagerMethodJsonEncrypted();
                    (_saveLoadManagerMethod as MMSaveLoadManagerEncrypter).Key = EncryptionKey;
                    break;
            }
            MMSaveLoadManager.saveLoadMethod = _saveLoadManagerMethod;
        }

    }

}

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
using System;
#if UNITY_EDITOR
using UnityEditor;
#endif

namespace MoreMountains.Tools
{
    /// <summary>
    /// 允许在特定文件夹和文件中保存和加载对象。
    /// 
    ///如何使用(至少):
    /// 
    ///保存:MMSaveLoadManager。保存(测试对象、文件名+保存文件扩展名、文件夹名);
    /// 
    ///加载:测试对象=(YourObjectClass)MMSaveLoadManager。加载(类型(YourObjectClass)、文件名+保存文件扩展名、文件夹名);
    /// 
    ///删除保存:MMSaveLoadManager。删除保存(文件名+保存文件扩展名,文件夹名);
    /// 
    ///删除保存文件夹:MMSaveLoadManager。删除保存文件夹(FolderName);
    /// 
    ///您还可以指定系统应使用的IMMSaveLoadManagerMethod。默认情况下,它是二进制的,但您也可以选择二进制加密、json或json加密
    ///您将在MMSaveLoadTester类中找到如何设置这些的示例
    /// 
    /// </summary>
    public static class MMSaveLoadManager
    {
        //轻松更改saveMethod
        //保存和加载文件时使用的方法(当然两次都必须相同)
        //public static IMMSaveLoadManagerMethod saveLoadMethod = new MMSaveLoadManagerMethodBinary();
        public static IMMSaveLoadManagerMethod saveLoadMethod = new MMSaveLoadManagerMethodJson();

        /// 系统将用于保存文件的默认顶级文件夹
        private const string _baseFolderName = "/MMData/";
        /// 保存文件夹的名称(如果未提供)
		private const string _defaultFolderName = "MMSaveLoadManager";

        /// <summary>
		/// 根据文件夹名称确定加载和保存文件时使用的保存路径。
		/// </summary>
		/// <returns>The save path.</returns>
		/// <param name="folderName">Folder name.</param>
		static string DetermineSavePath(string folderName = _defaultFolderName)
        {
            string savePath;
            // 根据我们使用的设备,我们组装路径
            if (Application.platform == RuntimePlatform.IPhonePlayer)
            {
                savePath = Application.persistentDataPath + _baseFolderName;
            }
            else
            {
                savePath = Application.persistentDataPath + _baseFolderName;
            }
            #if UNITY_EDITOR
                savePath = Application.dataPath + _baseFolderName;
            #endif
            savePath = savePath + folderName + "/";
            return savePath;
        }

        /// <summary>
		/// 确定要保存的文件的名称
		/// </summary>
		/// <returns>The save file name.</returns>
		/// <param name="fileName">File name.</param>
		static string DetermineSaveFileName(string fileName)
        {
            return fileName;
        }


        /// <summary>
        /// 将指定的saveObject、fileName和foldername保存到磁盘上的文件中。
        /// </summary>
        /// <param name="saveObject">Save object.</param>
        /// <param name="fileName">File name.</param>
        /// <param name="foldername">Foldername.</param>
        public static void Save(object saveObject, string fileName, string foldername = _defaultFolderName)
        {
            string savePath = DetermineSavePath(foldername);
            string saveFileName = DetermineSaveFileName(fileName);
            // if the directory doesn't already exist, we create it
            if (!Directory.Exists(savePath))
            {
                Directory.CreateDirectory(savePath);
            }
            // we serialize and write our object into a file on disk
            FileStream saveFile = File.Create(savePath + saveFileName);
            saveLoadMethod.Save(saveObject, saveFile);
            saveFile.Close();
        }

        /// <summary>
        /// 根据文件名将指定文件加载到指定文件夹中
        /// </summary>
        /// <param name="fileName">File name.</param>
        /// <param name="foldername">Foldername.</param>
        public static object Load(System.Type objectType, string fileName, string foldername = _defaultFolderName)
        {
            string savePath = DetermineSavePath(foldername);
            string saveFileName = savePath + DetermineSaveFileName(fileName);
            object returnObject;
            // 如果MMSaves目录或保存文件不存在,则无需加载任何内容,我们什么都不做并退出
            if (!Directory.Exists(savePath) || !File.Exists(saveFileName))
            {
                return null;
            }
            FileStream saveFile = File.Open(saveFileName, FileMode.Open, FileAccess.Read, FileShare.Read);
            returnObject = saveLoadMethod.Load(objectType, saveFile);
            saveFile.Close();
            return returnObject;
        }

        /// <summary>
        /// 从磁盘中删除保存
        /// </summary>
        /// <param name="fileName">File name.</param>
        /// <param name="folderName">Folder name.</param>
        public static void DeleteSave(string fileName, string folderName = _defaultFolderName)
        {
            string savePath = DetermineSavePath(folderName);
            string saveFileName = DetermineSaveFileName(fileName);
            if (File.Exists(savePath + saveFileName))
            {
                File.Delete(savePath + saveFileName);
            }
        }

        internal static void DeleteSaveFolder(string folderName)
        {
            string savePath = DetermineSavePath(folderName);
            if (Directory.Exists(savePath))
            {
                DeleteDirectory(savePath);
            }

        }

        private static void DeleteDirectory(string target_dir)
        {
            string[] files = Directory.GetFiles(target_dir);
            string[] dirs = Directory.GetDirectories(target_dir);
            foreach (string file in files)
            {
                File.SetAttributes(file, FileAttributes.Normal);
                File.Delete(file);
            }
            foreach (string dir in dirs)
            {
                DeleteDirectory(dir);
            }
            Directory.Delete(target_dir, false);
        }
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值