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);
}
}
}