关于界面栈系统

  |   0 评论   |   0 浏览

概述

游戏内,关于界面的跳转逻辑,一般是有一定规则的,例如

  1. 从主界面
  2. 打开全屏界面A
  3. 打开弹出框B
  4. 关闭A和B后,打开C
  5. 关闭C,弹出A,再弹出B
  6. 关闭界面B
  7. 关闭界面A
  8. 打开主界面
  9. 打开副本界面中,点击某副本
  10. 弹出副本详情,点开战
  11. 关闭所有界面,进入战斗场景
  12. 等战斗结束,弹结算界面,清理战场
  13. 弹回之前的副本和详情界面,并恢复当时的状态

很啰嗦,但是这比较常见的流程,这里面有什么可以抽象出来的?可以达成什么目标?

目标

  • 开发者不需要特别关注打开一个界面时,后面的界面是个什么状态
  • 开发者不需要特别关注在关闭一个界面的时候,该打开什么界面(除非有特殊跳转)
  • 进战斗前,开发者不必每个人都记录当前打开的界面
  • 出战斗后,开发者并不需要自己打开进战斗前的界面
  • 但是,界面内的还原工作,还是需要每个人自己做

抽象

1.界面类别:
  • A级全屏界面
  • B级半屏界面
  • C级不重要的弹出界面(确认框,飘字等)
2.记录一个当前已经打开的Main层的界面queue(或list) standBy
3.记录一个当前已关闭的所有界面,用数据结构-栈,pageStack
4.根(Root),定义HomePage为根界面,每次打开HomePage,清理掉pageStack和standBy,降低复杂度与栈的深度
5.正向打开逻辑
  • 如果是打开半屏界面,别的事什么也不做
  • 如果是打开全屏界面,那么之前打开的所有界面都可以回对象池了,同时记录一个当时的数据包,push到pageStack中,并将当前界面放入standBy中
6.反向后退逻辑
  • 如果是关闭弹出界面,只关闭,别的事什么也不做
  • 如果是关闭全屏界面,那要从记录的数据包合集里从后往前查找,逻辑如下:
    • 先创建一个local的tempStack的栈
    • 如果pageStack是空的,直接弹出根界面
    • pageStack:pop() ,如果是半屏界面,压入tempStack,还需要继续往前弹
    • pageStack:pop() ,如果是全屏界面,压入tempStack,不需要再弹了
    • 一次把tempStack再pop完,就是我们想要的先全屏,再半屏界面了
7. 避免循环弹栈
  • Root->A->B 这时候栈内为A,standBy里为B
  • 关闭B,这时候把A弹出来,没问题,但是回把B再入栈
  • 这时候关闭A,我们期待回到HomePage并且清空PageStack,但是实际会把B弹出来,同时A又入栈里造成循环弹AB
  • 处理办法:如果是单纯Close界面,先把自己从standBy干掉

解释

1. 为什么存储已关闭界面要用stack

这里是后进先出的原则,最后压进去的数据,最先弹出来,来判断是否为全屏界面

2. stash 和pop的原理是什么

stash和pop的灵感来自git,我们在工作中,经常会被插入一些临时的活,但是我们手里还有着原来的工作,那怎么办?使用git的处理流程如下:

  • 我们可以执行命令:git stash 就把我们的本地修改扔到缓存中了
  • 等我们这边处理完插入的事物并提交后,这时现在的工作区又是一个干净的了
  • 我们再执行命令:git stash pop
  • 把之前暂存的本地修改弹出来,再继续我们原来的工作

同理,对比我们游戏内的流程

  • 我们再要插入一个事务之前(比方说进战斗),我们执行PageStack:StashAll(),把当前状态catch住,
  • 然后完成这个事务
  • 执行PageStack:StashPop(),这个方法会把界面清理干净,然后把之前暂存的界面分别弹出来,达到了还原的目的

不过,我们的stash不支持多次执行,也没必要多次执行


标题:关于界面栈系统
作者:kyochow
地址:https://kyochow.github.io/articles/2020/10/23/1603418345984.html