Unity项目较大刷新及编译卡顿解决方法
开发中当Unity项目比较大的时候,每次Unity窗口获取焦点时刷新需要3-5秒,非常麻烦!常见有几种方法来缓解这个问题:
- 关闭unity自动刷新Edit->Preferences->General->Auto Refresh,改为自己手动Ctrl+R刷新;
缺点:每次都需要手动刷新比较麻烦
- 修改unity的ScriptChangesWhilePlaying选项Editor->Preferences->General->Script Changes While Playing
Recompile And Continue Playing 编译并继续播放
Recompile After Finished Playing 停止播放后再编译
Stop Playing And Recompile 停止播放进行编译
- 开发工具在Editor模式自动检查资源变更自动刷新,代码如下:
第一步:检查开发过程中需要及时刷新的资源,如:Scripts目录,prefab目录
第二步:获取最后改动时间是否与上一次检查的时间一致,不一致则启动刷新
第三步:将时间写入文件缓存,方便下一次对比
第四步:在窗口获取焦点以及Playing启动时启动检测
#if UNITY_EDITOR
using UnityEditor;
using UnityEngine;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Security.Cryptography;
[InitializeOnLoad]
public class EditorNotification : AssetPostprocessor
{
private static bool isFocused;
private static bool isPlaymode;
static EditorNotification()
{
EditorApplication.update -= Update;
EditorApplication.update += Update;
EditorApplication.playmodeStateChanged -= PlaymodeStateChanged;
EditorApplication.playmodeStateChanged += PlaymodeStateChanged;
}
private static void Update()
{
if (isFocused == UnityEditorInternal.InternalEditorUtility.isApplicationActive)
{
return;
}
isFocused = UnityEditorInternal.InternalEditorUtility.isApplicationActive;
OnEditorFocus(isFocused);
}
private static void PlaymodeStateChanged()
{
if(EditorApplication.isPlayingOrWillChangePlaymode && !isPlaymode)
{
//Debug.LogError(EditorApplication.isPlaying.ToString() + " - " + EditorApplication.isPlayingOrWillChangePlaymode.ToString());
isPlaymode = true;
Refresh();
}
else if(!EditorApplication.isPlayingOrWillChangePlaymode && !EditorApplication.isPlaying)
{
isPlaymode = false;
}
}
/// <summary>
/// Unity窗口聚焦状态改变回调
/// </summary>
/// <param name="focus"></param>
private static void OnEditorFocus(bool focus)
{
if (focus)
{
//Debug.LogErrorFormat("编辑器激活状态:{0}", focus);
if(!EditorApplication.isPlaying && !EditorApplication.isPlayingOrWillChangePlaymode)
{
Refresh();
}
}
}
private void OnPreprocessAsset()
{
//Debug.LogError("Asset下文件改变时回调");
}
//[MenuItem("File/RefreshManual")]
static void Refresh()
{
bool needRefresh = false;
MD5File md5 = new MD5File();
System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
sw.Reset();
sw.Start();
string path = Path.Combine($"{Application.dataPath}/../Library", "md5Refresh.dat");
if(File.Exists(path))
{
FileStream fs = new FileStream(path, FileMode.OpenOrCreate);
BinaryFormatter bin = new BinaryFormatter();
md5 = (MD5File)bin.Deserialize(fs);
fs.Close();
}
string scriptPath = Path.Combine($"{Application.dataPath}", "Scripts");
DirectoryInfo dinfo = new DirectoryInfo(scriptPath);
FileInfo[] fileInfos = dinfo.GetFiles("*.cs", SearchOption.AllDirectories);
foreach(FileInfo file in fileInfos)
{
string timestr = file.LastWriteTime.ToLongTimeString();
string value = string.Empty;
if(md5.m_DicMD5.TryGetValue(file.FullName, out value))
{
System.DateTime dt = System.DateTime.Parse(value);
System.DateTime dt2 = System.DateTime.Parse(timestr);
if(!System.DateTime.Equals(dt, dt2))
{
needRefresh = true;
md5.m_DicMD5[file.FullName] = timestr;
Debug.LogError(file.FullName + " - " + value + " -- " + timestr);
}
}
else
{
needRefresh = true;
md5.m_DicMD5.Add(file.FullName, timestr);
Debug.LogError(file.FullName + " -------- " + timestr);
}
}
{
FileStream fs = new FileStream(path, FileMode.OpenOrCreate);
BinaryFormatter bin = new BinaryFormatter();
bin.Serialize(fs, md5);
fs.Close();
}
sw.Stop();
string str = "C#变更检查结束,不需要刷新!";
if (needRefresh)
{
str = "C#变更检查结束,需要刷新!";
string t = (sw.Elapsed.TotalMilliseconds / 1000).ToString("N2");
Debug.LogError($"{str}FileCount:{fileInfos.Length} Time:{t}秒");
AssetDatabase.Refresh();
EditorUtility.RequestScriptReload();
}
}
}
#endif
using System.Collections;
using System.Collections.Generic;
[System.Serializable]
public class MD5File
{
public Dictionary<string, string> m_DicMD5 = new Dictionary<string, string>();
}
这种方法只需要检查少部分资源自动刷新,基本没有卡顿,体验相对比较好!