UI游戏框架(三)

来源:互联网 发布:康佳网络电视售后电话 编辑:程序博客网 时间:2024/05/16 09:59

UI游戏框架(三)

UI框架中UI窗体的“层级管理”,最核心的问题是如何进行窗体的显示管理。窗体(预设)的显示我们前面定义了三种类型: 普通、隐藏其他、反向切换。代码如下:

 

 

/// <summary>

/// UI窗体显示类型

/// </summary>

public enum UIFormsShowMode

{

Normal, //普通显示

ReverseChange, //反向切换

HideOther, //隐藏其他界面

}

 

“普通显示”模式允许多个窗体同时显示,这种类型应用最多。例如RPG中的主城界面(见下图)。

  计


“隐藏其他界面” 模式一般应用于全局性的窗体。我们在开发此类窗体时,为了减少UI渲染压力、提高Unity渲染效率,则设置被覆盖的窗体为“不可见”状态。(即: this.gameObject.SetActive(false))。例如一般的登录窗体、选择英雄窗体等。

  计

  

“反向切换”模式类型,一般都大量应用于“弹出窗体”中。此类窗体的特点是:显示弹出窗体时不完全覆盖底层窗体,一般在屏幕的四周会露出底层窗体。之所以命名“反向切换”是因为: 程序员要维护一种“后进先出”的“栈”的数据结构特点,即我们一般要求玩家必须先关闭弹出的顶层窗体,再依次关闭下一级窗体。如下图所示。

 计

 

  上图即一种典型的弹出窗体。一般我们都要求玩家先处理弹出窗体中的信息,然后关闭此窗体。一般不允许在没有关闭子窗体的情况下,直接点击父窗体。(关于弹出窗体时,不允许玩家点击父窗体的功能实现,笔者在下节[“模态窗体管理”]一章着重讲解)。

  以上说了这么多了,我们对于“层级管理”的核心代码实现,基本都体现在“UI管理器脚本” (UIManager.cs )中。以下给出具体实现代码:

 

 

 

1 /***

2 * Title: "SUIFW"框架

3 *主题: UI管理器

4 * Description:

5 *功能:整个UI框架的核心,用户程序通过调用本类,来调用本框架的大多数功能。

6 *功能1:关于入与出UI窗体4个状态的定义逻辑

7 *入栈状态:

8 * Freeze();(上一个UI窗体)冻结

9 * Display();(本UI窗体)显示

10 *出栈状态:

11 * Hiding(); (UI窗体)隐藏

12 * Redisplay(); (上一个UI窗体)重新显示

13 *功能2:增加非栈缓存集合。

14 */

15 using UnityEngine;

16 using UnityEngine.UI;

17 using System;

18 using System.Collections.Generic;

19 

20 

21 namespace SUIFW

22 {

23 public class UIManager : MonoBehaviour

24 {

25 /*字段 */

26 //本类实例

27 private static UIManager _Instance =null;

28 //存储所有“UI窗体预设(Prefab)”路径

29 //参数含义: 第1string表示窗体预设名称,后一个string表示对应的路径

30 private Dictionary<string,string> _DicUIFormsPaths;

31 //缓存所有已经打开的“UI窗体预设(Prefab)”

32 //参数含义: 第1string表示窗体预设名称,后一个BaseUI表示对应的窗体预设

33 private Dictionary<string, BaseUIForms> _DicALLUIForms;

34 //“结构表示的当前UI窗体集合。

35 private Stack<BaseUIForms> _StaCurrentUIForms;

36 //当前显示状态的UI窗体集合

37 private Dictionary<string, BaseUIForms> _DicCurrentShowUIForms;

38 //UI根节点

39 private Transform _CanvasTransform =null;

40 //普通全屏界面节点

41 private Transform _CanTransformNormal =null;

42 //固定界面节点

43 private Transform _CanTransformFixed =null;

44 //弹出模式节点

45 private Transform _CanTransformPopUp =null;

46 //UI脚本节点(加载各种管理脚本的节点)

47 private Transform _CanTransformUIScripts =null;

48 

49 

50 

51 

52 /// <summary>

53 /// 得到本类实例

54 /// </summary>

55 /// <returns></returns>

56 public static UIManager GetInstance()

57 {

58 if (_Instance ==null)

59 {

60 _Instance =new GameObject("_UIManager").AddComponent<UIManager>();

61 }

62 return _Instance;

63 }

64 

65 void Awake()

66 {

67 //字段初始化

68 _DicUIFormsPaths =new Dictionary<string,string>();

69 _DicALLUIForms =new Dictionary<string, BaseUIForms>();

70 _StaCurrentUIForms =new Stack<BaseUIForms>();

71 _DicCurrentShowUIForms =new Dictionary<string, BaseUIForms>();

72 

73 //初始化项目开始必须的资源加载

74 InitRootCanvasLoading();

75 

76 //得到UI根节点、及其重要子节点

77 _CanvasTransform = GameObject.FindGameObjectWithTag(SysDefine.SYS_TAG_CANVAS).transform;

78 //得到普通全屏界面节点、固定界面节点、弹出模式节点、UI脚本节点

79 _CanTransformNormal = UnityHelper.FindTheChild(_CanvasTransform.gameObject, SysDefine.SYS_CANVAS_NORMAL_NODE_NAME);

80 _CanTransformFixed = UnityHelper.FindTheChild(_CanvasTransform.gameObject, SysDefine.SYS_CANVAS_FIXED_NODE_NAME);

81 _CanTransformPopUp = UnityHelper.FindTheChild(_CanvasTransform.gameObject, SysDefine.SYS_CANVAS_POPUP_NODE_NAME);

82 _CanTransformUIScripts = UnityHelper.FindTheChild(_CanvasTransform.gameObject, SysDefine.SYS_CANVAS_UISCRIPTS_NODE_NAME);

83 

84 //把本脚本实例,作为Canvas的子节点

85 UnityHelper.AddChildToParent(_CanTransformUIScripts,this.gameObject.transform);

86 

87 //UI节点信息,场景转换时,不允许销毁

88 DontDestroyOnLoad(_CanvasTransform);

89 //初始化“UI窗体预设路径数据

90 InitUIFormsPathsData();

91 }

92 

93 /// <summary>

94 /// 显示UI窗体

95 /// </summary>

96 /// <param name="strUIFormName">UI窗体的名称</param>

97 public void ShowUIForms(string strUIFormName)

98 {

99 BaseUIForms baseUIForms;//UI窗体基类

100 

101 //参数检查

102 if (string.IsNullOrEmpty(strUIFormName))return;

103 

104 //加载“UI窗体名称,到所有UI窗体缓存

105 baseUIForms = LoadUIFormsToAllUIFormsCatch(strUIFormName);

106 if (baseUIForms ==null) return;

107 

108 //判断是否清空结构体集合

109 if (baseUIForms.CurrentUIType.IsClearReverseChange)

110 {

111 ClearStackArray();

112 }

113 

114 //判断不同的窗体显示模式,分别进行处理

115 switch (baseUIForms.CurrentUIType.UIForms_ShowMode)

116 {

117 case UIFormsShowMode.Normal:

118 EnterUIFormsCache(strUIFormName);

119 break;

120 case UIFormsShowMode.ReverseChange:

121 PushUIForms(strUIFormName);

122 break;

123 case UIFormsShowMode.HideOther:

124 EnterUIFormstToCacheHideOther(strUIFormName);

125 break;

126 default:

127 break;

128 }

129 }

130 

131 /// <summary>

132 /// 关闭或返回上一个UI窗体(关闭当前UI窗体)

133 /// </summary>

134 public void CloseOrReturnUIForms(string strUIFormName)

135 {

136 BaseUIForms baseUIForms =null; //UI窗体基类

137 

138 /*参数检查 */

139 if (string.IsNullOrEmpty(strUIFormName))return;

140 //“所有UI窗体缓存如果没有记录,则直接返回。

141 _DicALLUIForms.TryGetValue(strUIFormName,out baseUIForms);

142 if (baseUIForms ==null) return;

143 

144 /*判断不同的窗体显示模式,分别进行处理 */

145 switch (baseUIForms.CurrentUIType.UIForms_ShowMode)

146 {

147 case UIFormsShowMode.Normal:

148 ExitUIFormsCache(strUIFormName);

149 break;

150 case UIFormsShowMode.ReverseChange:

151 PopUIForms();

152 break;

153 case UIFormsShowMode.HideOther:

154 ExitUIFormsFromCacheAndShowOther(strUIFormName);

155 break;

156 default:

157 break;

158 }

159 

160 }

161 

162 #region 私有方法

163 /// <summary>

164 /// 根据指定UI窗体名称,加载到所有UI窗体缓存中。

165 /// </summary>

166 /// <param name="strUIFormName">UI窗体名称</param>

167 /// <returns></returns>

168 private BaseUIForms LoadUIFormsToAllUIFormsCatch(string strUIFormName)

169 {

170 BaseUIForms baseUI;//UI窗体

171 

172 //判断“UI预设缓存集合是否有指定的UI窗体,否则新加载窗体

173 _DicALLUIForms.TryGetValue(strUIFormName,out baseUI);

174 if (baseUI ==null)

175 {

176 //加载指定路径的“UI窗体

177 baseUI = LoadUIForms(strUIFormName);

178 }

179 

180 return baseUI;

181 }

182 

183 /// <summary>

184 /// 加载UI窗体到当前显示窗体集合缓存中。

185 /// </summary>

186 /// <param name="strUIFormsName"></param>

187 private void EnterUIFormsCache(string strUIFormsName)

188 {

189 BaseUIForms baseUIForms;//UI窗体基类

190 BaseUIForms baseUIFormsFromAllCache;//"所有窗体集合"中的窗体基类

191 

192 //“正在显示UI窗体缓存集合里有记录,则直接返回。

193 _DicCurrentShowUIForms.TryGetValue(strUIFormsName,out baseUIForms);

194 if (baseUIForms !=null) return;

195 

196 //把当前窗体,加载到正在显示UI窗体缓存集合里

197 _DicALLUIForms.TryGetValue(strUIFormsName,out baseUIFormsFromAllCache);

198 if (baseUIFormsFromAllCache !=null)

199 {

200 _DicCurrentShowUIForms.Add(strUIFormsName, baseUIFormsFromAllCache);

201 baseUIFormsFromAllCache.Display();

202 }

203 }

204 

205 /// <summary>

206 /// 卸载UI窗体从当前显示窗体集合缓存中。

207 /// </summary>

208 /// <param name="strUIFormsName"></param>

209 private void ExitUIFormsCache(string strUIFormsName)

210 {

211 BaseUIForms baseUIForms;//UI窗体基类

212 

213 //“正在显示UI窗体缓存集合没有记录,则直接返回。

214 _DicCurrentShowUIForms.TryGetValue(strUIFormsName,out baseUIForms);

215 if (baseUIForms ==null) return;

216 

217 //指定UI窗体,运行隐藏状态,且从正在显示UI窗体缓存集合中移除。

218 baseUIForms.Hiding();

219 _DicCurrentShowUIForms.Remove(strUIFormsName);

220 }

221 

222 /// <summary>

223 /// 加载UI窗体到当前显示窗体集合缓存中,且隐藏其他正在显示的页面

224 /// </summary>

225 /// <param name="strUIFormsName"></param>

226 private void EnterUIFormstToCacheHideOther(string strUIFormsName)

227 {

228 BaseUIForms baseUIForms;//UI窗体基类

229 BaseUIForms baseUIFormsFromAllCache;//"所有窗体集合"中的窗体基类

230 

231 //“正在显示UI窗体缓存集合里有记录,则直接返回。

232 _DicCurrentShowUIForms.TryGetValue(strUIFormsName,out baseUIForms);

233 if (baseUIForms !=null) return;

234 

235 //“正在显示UI窗体缓存栈缓存集合里所有窗体进行隐藏处理。

236 foreach (BaseUIForms baseUIFormsItemin _DicCurrentShowUIForms.Values)

237 {

238 baseUIFormsItem.Hiding();

239 }

240 foreach (BaseUIForms basUIFormsItemin _StaCurrentUIForms)

241 {

242 basUIFormsItem.Hiding();

243 }

244 

245 //把当前窗体,加载到正在显示UI窗体缓存集合里

246 _DicALLUIForms.TryGetValue(strUIFormsName,out baseUIFormsFromAllCache);

247 if (baseUIFormsFromAllCache !=null)

248 {

249 _DicCurrentShowUIForms.Add(strUIFormsName, baseUIFormsFromAllCache);

250 baseUIFormsFromAllCache.Display();

251 }

252 }

253 

254 /// <summary>

255 /// 卸载UI窗体从当前显示窗体集合缓存中,且显示其他原本需要显示的页面

256 /// </summary>

257 /// <param name="strUIFormsName"></param>

258 private void ExitUIFormsFromCacheAndShowOther(string strUIFormsName)

259 {

260 BaseUIForms baseUIForms;//UI窗体基类

261 

262 //“正在显示UI窗体缓存集合没有记录,则直接返回。

263 _DicCurrentShowUIForms.TryGetValue(strUIFormsName,out baseUIForms);

264 if (baseUIForms ==null) return;

265 

266 //指定UI窗体,运行隐藏状态,且从正在显示UI窗体缓存集合中移除。

267 baseUIForms.Hiding();

268 _DicCurrentShowUIForms.Remove(strUIFormsName);

269 

270 //“正在显示UI窗体缓存栈缓存集合里所有窗体进行再次显示处理。

271 foreach (BaseUIForms baseUIFormsItemin _DicCurrentShowUIForms.Values)

272 {

273 baseUIFormsItem.Redisplay();

274 }

275 foreach (BaseUIForms basUIFormsItemin _StaCurrentUIForms)

276 {

277 basUIFormsItem.Redisplay();

278 }

279 }

280 

281 /// <summary>

282 /// UI窗体入栈

283 /// 功能1: 判断栈里是否已经有窗体,有则冻结

284 /// 2: 先判断“UI预设缓存集合是否有指定的UI窗体,有则处理。

285 /// 3: 指定UI窗体入""

286 /// </summary>

287 /// <param name="strUIFormsName"></param>

288 private void PushUIForms(string strUIFormsName)

289 {

290 BaseUIForms baseUI;//UI预设窗体

291 

292 

293 //判断栈里是否已经有窗体,有则冻结

294 if (_StaCurrentUIForms.Count >0)

295 {

296 BaseUIForms topUIForms = _StaCurrentUIForms.Peek();

297 topUIForms.Freeze();

298 }

299 

300 //先判断“UI预设缓存集合是否有指定的UI窗体,有则处理。

301 _DicALLUIForms.TryGetValue(strUIFormsName,out baseUI);

302 if (baseUI !=null)

303 {

304 baseUI.Display();

305 }

306 else

307 {

308 Log.Write(GetType() +string.Format("/PushUIForms()/ baseUI==null!核心错误,请检查 strUIFormsName={0} ", strUIFormsName), Log.Level.High);

309 }

310 

311 //指定UI窗体入""

312 _StaCurrentUIForms.Push(baseUI);

313 }

314 

315 /// <summary>

316 /// UI窗体出栈逻辑

317 /// </summary>

318 private void PopUIForms()

319 {

320 if (_StaCurrentUIForms.Count >=2)

321 {

322 /*出栈逻辑 */

323 BaseUIForms topUIForms = _StaCurrentUIForms.Pop();

324 //出栈的窗体,进行隐藏处理

325 topUIForms.Hiding();

326 //出栈窗体的下一个窗体逻辑

327 BaseUIForms nextUIForms = _StaCurrentUIForms.Peek();

328 //下一个窗体"重新显示"处理

329 nextUIForms.Redisplay();

330 }

331 else if (_StaCurrentUIForms.Count ==1)

332 {

333 /*出栈逻辑 */

334 BaseUIForms topUIForms = _StaCurrentUIForms.Pop();

335 //出栈的窗体,进行"隐藏"处理

336 topUIForms.Hiding();

337 }

338 }

339 

340 /// <summary>

341 /// 加载与显示UI窗体

342 /// 功能:

343 /// 1:根据“UI窗体预设名称,加载预设克隆体。

344 /// 2:预设克隆体添加UI“根节点为父节点。

345 /// 3:隐藏刚创建的UI克隆体。

346 /// 4:新创建的“UI窗体,加入“UI窗体缓存

347 /// </summary>

348 private BaseUIForms LoadUIForms(string strUIFormsName)

349 {

350 string strUIFormsPaths =null; //UI窗体的路径

351 GameObject goCloneUIPrefab =null; //克隆的"窗体预设"

352 BaseUIForms baseUIForm;//UI窗体

353 

354 

355 //得到UI窗体的路径

356 _DicUIFormsPaths.TryGetValue(strUIFormsName,out strUIFormsPaths);

357 

358 //加载指定路径的“UI窗体

359 if (!string.IsNullOrEmpty(strUIFormsPaths))

360 {

361 goCloneUIPrefab = ResourcesMgr.GetInstance().LoadAsset(strUIFormsPaths,false);

362 }

363 

364 //设置“UI窗体克隆体的父节点,以及隐藏处理与加入“UI窗体缓存

365 if (_CanvasTransform !=null && goCloneUIPrefab != null)

366 {

367 baseUIForm = goCloneUIPrefab.GetComponent<BaseUIForms>();

368 if (baseUIForm ==null)

369 {

370 Log.Write(GetType() +string.Format("/LoadUIForms()/ baseUIForm==null,请先确认克隆对象上是否加载了BaseUIForms的子类。参数strUIFormsName='{0}' ", strUIFormsName), Log.Level.High);

371 return null;

372 }

373 switch (baseUIForm.CurrentUIType.UIForms_Type)

374 {

375 case UIFormsType.Normal:

376 goCloneUIPrefab.transform.SetParent(_CanTransformNormal,false);

377 break;

378 case UIFormsType.Fixed:

379 goCloneUIPrefab.transform.SetParent(_CanTransformFixed,false);

380 break;

381 case UIFormsType.PopUp:

382 goCloneUIPrefab.transform.SetParent(_CanTransformPopUp,false);

383 break;

384 default:

385 break;

386 }

387 

388 goCloneUIPrefab.SetActive(false);

389 //新创建的“UI窗体,加入“UI窗体缓存

390 _DicALLUIForms.Add(strUIFormsName, baseUIForm);

391 return baseUIForm;

392 }

393 else

394 {

395 Log.Write(GetType() +string.Format("/LoadUIForms()/‘_CanvasTransform’ Or ‘goCloneUIPrefab’==NULL! ,方法参数 strUIFormsName={0},请检查!", strUIFormsName), Log.Level.High);

396 }

397 

398 Log.Write(GetType() +string.Format("/LoadUIForms()/出现不可预知错误,请检查! 方法参数 strUIFormsName={0} ", strUIFormsName), Log.Level.High);

399 return null;

400 }

401 

402 /// <summary>

403 /// 初始化项目开始必须的资源加载

404 /// </summary>

405 private void InitRootCanvasLoading()

406 {

407 if (UnityHelper.isFirstLoad)

408 {

409 ResourcesMgr.GetInstance().LoadAsset(SysDefine.SYS_PATH_CANVAS,false);

410 }

411 }

412 

413 /// <summary>

414 /// 初始化“UI窗体预设路径数据

415 /// </summary>

416 private void InitUIFormsPathsData()

417 {

418 //测试也成功

419 IConfigManager configMgr =new ConfigManagerByJson(SysDefine.SYS_PATH_UIFormConfigJson);

420 if (_DicUIFormsPaths !=null)

421 {

422 _DicUIFormsPaths = configMgr.AppSetting;

423 }

424 }

425 

426 /// <summary>

427 /// 清空结构体集合

428 /// </summary>

429 /// <returns></returns>

430 private bool ClearStackArray()

431 {

432 if (_StaCurrentUIForms !=null && _StaCurrentUIForms.Count >= 1)

433 {

434 _StaCurrentUIForms.Clear();

435 return true;

436 }

437 return false;

438 }

439 

440 #endregion

441 

442 }//Class_end

443 }

 

 

 

以上代码解释:

    1: UIManager.cs  中定义的新的字段 ,“_StaCurrentUIForms” 就是一个“栈”数据类型,用于维护一种后进先出的数据结构。常见的方法如下:

      C#语言中提供 Stack<T> 泛型集合,来直接实现这种结构。 

常用属性与方法: 

· Count 属性  查询栈内元素数量

· Push()      压栈

· Pop()       出栈

· Peek()      查询栈顶元素

· GetEnumerator() 遍历栈中所有元素

 

   2: UIManager.cs 中的“ShowUIForms()”方法中的120行与123行,就是专门处理“反向切换”与“隐藏其他”窗体特性的实现方法。