QualityModule.cs 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. using System;
  2. using UnityEngine;
  3. namespace XGame.Framework.Quality
  4. {
  5. public class QualityModule : IQualityModule, IDisposable
  6. {
  7. private XQualityLevel _recommendQuality;
  8. public XQualityLevel RecommendQuality { get { return _recommendQuality; } }
  9. private XQualityLevel _curQuality;
  10. public XQualityLevel CurQuality { get { return _curQuality; } set { if (value != _curQuality) ChangeQualityLevel(value); } }
  11. public Action<XQualityLevel> OnQualityLevelChanged { get; set; }
  12. private Vector2Int _originalScreenSize;
  13. private const string SaveCurQualityKey = "CurQuality";
  14. //private static IQualityModule _instance;
  15. //public static IQualityModule Instance
  16. //{
  17. // get
  18. // {
  19. // if (_instance == null) _instance = new QualityModule();
  20. // return _instance;
  21. // }
  22. //}
  23. public QualityModule()
  24. {
  25. _originalScreenSize = new Vector2Int(Screen.width, Screen.height);
  26. _curQuality = (XQualityLevel)PlayerPrefs.GetInt(SaveCurQualityKey, (int)XQualityLevel.UnKnow);
  27. CalcRecommendQuality();
  28. InnerReset();
  29. if (MacroDefine.IsEditor) Application.targetFrameRate = 60;
  30. else
  31. {
  32. Application.targetFrameRate = _curQuality == XQualityLevel.UltraHD ? 60 : 30;
  33. }
  34. Log.Info($"设备推荐的游戏品质:{_recommendQuality},用户设置的游戏品质:{_curQuality}");
  35. }
  36. float IQualityModule.GetScreenScale()
  37. {
  38. return Screen.width * 1f / _originalScreenSize.x;
  39. }
  40. private float RecommendScreenScale(XQualityLevel level)
  41. {
  42. var scale = 1f;
  43. if (MacroDefine.IsAndroid)
  44. {
  45. switch (level)
  46. {
  47. case XQualityLevel.High:
  48. scale = 0.8f;
  49. break;
  50. case XQualityLevel.Medium:
  51. scale = 0.7f;
  52. break;
  53. case XQualityLevel.Low:
  54. scale = 0.7f;
  55. break;
  56. }
  57. }
  58. else if (MacroDefine.IsiOS)
  59. {
  60. switch (level)
  61. {
  62. case XQualityLevel.High:
  63. case XQualityLevel.Medium:
  64. scale = 0.8f;
  65. break;
  66. case XQualityLevel.Low:
  67. scale = 0.7f;
  68. break;
  69. }
  70. }
  71. return scale;
  72. }
  73. /// <summary>
  74. /// 判断是否模拟器函数
  75. /// 通常Android才有模拟器
  76. /// 模拟器可以模拟很多传感器信息
  77. /// 此处选用光传感器判断
  78. /// 实测雷电模拟器,夜神模拟器,网易mumu,腾讯手游助手都成功判断为模拟器
  79. /// </summary>
  80. /// <returns>是否模拟器</returns>
  81. private static bool IsSimulator()
  82. {
  83. #if UNITY_ANDROID
  84. try
  85. {
  86. AndroidJavaClass unityPlayerClass = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
  87. AndroidJavaObject currentActivity = unityPlayerClass.GetStatic<AndroidJavaObject>("currentActivity");
  88. AndroidJavaObject sensorManager = currentActivity.Call<AndroidJavaObject>("getSystemService", "sensor");
  89. AndroidJavaObject sensor = sensorManager.Call<AndroidJavaObject>("getDefaultSensor", 5); //光传感器
  90. return sensor == null;
  91. }
  92. catch (Exception e)
  93. {
  94. return false;
  95. }
  96. #endif
  97. return false;
  98. }
  99. private void CalcRecommendQuality()
  100. {
  101. //显存
  102. int graphicsMemorySize = SystemInfo.graphicsMemorySize;
  103. //内存
  104. int systemMemorySize = SystemInfo.systemMemorySize;
  105. //cpu核心数
  106. int cpuCount = SystemInfo.processorCount;
  107. //cpu频率
  108. int cpuFrequency = SystemInfo.processorFrequency;
  109. if (MacroDefine.IsEditor)
  110. {
  111. _recommendQuality = XQualityLevel.UltraHD;
  112. }
  113. else if (MacroDefine.IsAndroid)
  114. {
  115. //模拟器
  116. if (IsSimulator())
  117. {
  118. _recommendQuality = XQualityLevel.High;
  119. }
  120. //分辨率低于1344,4核心以下,主频低于1.5GHz,内存低于2GB,一律视为低端机
  121. else if (Math.Max(_originalScreenSize.x, _originalScreenSize.y) < 1344 || cpuCount < 4 || cpuFrequency < 1500 || systemMemorySize <= 2048)
  122. {
  123. _recommendQuality = XQualityLevel.Low;
  124. }
  125. // 6核,内存4G,显存达到2G 高配
  126. else if (cpuCount >= 6 && systemMemorySize > 3072 && graphicsMemorySize >= 2048)
  127. {
  128. _recommendQuality = XQualityLevel.High;
  129. }
  130. else
  131. {
  132. _recommendQuality = XQualityLevel.Medium;
  133. }
  134. }
  135. else if (MacroDefine.IsiOS)
  136. {
  137. //iphone 8s以上
  138. if (SystemInfo.systemMemorySize > 2048)
  139. {
  140. _recommendQuality = XQualityLevel.High;
  141. }
  142. else
  143. {
  144. _recommendQuality = XQualityLevel.Medium;
  145. }
  146. }
  147. else
  148. {
  149. _recommendQuality = XQualityLevel.High;
  150. }
  151. if (_curQuality == XQualityLevel.UnKnow)
  152. ChangeQualityLevel(_recommendQuality);
  153. }
  154. private void ChangeQualityLevel(XQualityLevel ql)
  155. {
  156. // 保存
  157. _curQuality = ql;
  158. PlayerPrefs.SetInt(SaveCurQualityKey, (int)_curQuality);
  159. // 内部逻辑设置
  160. InnerReset();
  161. // 外部逻辑设置
  162. OnQualityLevelChanged?.Invoke(ql);
  163. Log.Info($"游戏品质等级切换到:{_curQuality}");
  164. }
  165. private void InnerReset()
  166. {
  167. // 引擎设置
  168. QualitySettings.SetQualityLevel((int)_curQuality);
  169. // 分辨率设置
  170. ResetResolution();
  171. // ShaderLod设置
  172. Shader.globalMaximumLOD = _curQuality.ShaderLodLevel();
  173. }
  174. // 分辨率设置
  175. private void ResetResolution()
  176. {
  177. if (MacroDefine.IsEditor)
  178. return;
  179. if (MacroDefine.IsAndroid || MacroDefine.IsiOS)
  180. {
  181. //var refSize = new Vector2Int(1920, 1080);
  182. var refLength = 1080;
  183. var scale = RecommendScreenScale(_curQuality);
  184. if (Screen.orientation == ScreenOrientation.Portrait || Screen.orientation == ScreenOrientation.PortraitUpsideDown)
  185. {
  186. //竖屏
  187. var width = (int)(refLength * scale);
  188. if (width >= _originalScreenSize.x)
  189. {
  190. width = _originalScreenSize.x;
  191. }
  192. if (width != Screen.width)
  193. {
  194. var height = (int)(width * _originalScreenSize.y * 1f / _originalScreenSize.x);
  195. Screen.SetResolution(width, height, Screen.fullScreen);
  196. }
  197. }
  198. else
  199. {
  200. //横屏
  201. var height = (int)(refLength * scale);
  202. if (height >= _originalScreenSize.y)
  203. {
  204. height = _originalScreenSize.y;
  205. }
  206. if (height != Screen.height)
  207. {
  208. var width = (int)(height * _originalScreenSize.x * 1f / _originalScreenSize.y);
  209. Screen.SetResolution(width, height, Screen.fullScreen);
  210. }
  211. }
  212. }
  213. }
  214. void IDisposable.Dispose()
  215. {
  216. if (OnQualityLevelChanged != null)
  217. {
  218. OnQualityLevelChanged = null;
  219. }
  220. }
  221. }
  222. }