前言
在游戏开发接近尾声的时候, 大部分的游戏都会接入新手引导功能, 提升玩家的游戏体验, 不至于让玩家进入游戏有冷场或者不知所措的感觉.
对于新手引导的做法估计一百个人有一百种方式, 接下来我将分享一下自己的使用方式, 并伴随一些问题的讨论.
教学引导
1. 使用简单的遮罩聚焦.
这种方式可以转移玩家的注意力, 毕竟进入游戏的时候内容有很多, 但是人的接受能力有限.
可以根据配置表设置决定是否有遮罩
2. 将引导放到最上层, 屏蔽触摸事件
这种方式比较省事, 也避免了玩家乱点导致的引导错误. 但是我们可以通过配置表的方式, 决定这一步是否为强制引导, 如果不是那么可以不屏蔽事件.
3. 手指位置如何获得
通过配置好的界面节点名称, 控件名称直接获得节点.
这里边使用的数组的形式配置, 是预留的为了实现拖拽教学. 让手指从一个位置滑动到另一个位置.
- setWidget() {
- if (this.widget) {
- return;
- }
- let parent = EngineHelper.findChild(this.className, UIManager.instance().getRoot())
- if (parent) {
- if (this.widgetName) {
- if (this.widgetName == 'this') {
- this.widget = parent;
- } else {
- this.widget = EngineHelper.findChild(this.widgetName, parent)
- }
- if (this.index>= 0) {
- this.widget = this.widget.children[this.index]
- if (this.index2>= 0) {
- this.widget = this.widget.children[this.index2]
- }
- }
- } else {
- this.widget = parent;
- }
- }
- }
然后将节点的坐标经过转换赋值给手指
3. 如何触发函数.
在数据表中配置好节点, 组件, 和函数名
当用户点击手指时, 通过代码直接调用
- trigger() {
- if (this.widget) {
- let comp = this.widget.getComponent(this.compName)
- if (comp) {
- comp[this.funcName]();
- }else{
- cc.warn('comp is null',this.compName)
- }
- }
- }
完整教学数据表
事件管理器
游戏中可能触发各种各样的事件, 教学只是其中之一, 还有可能弹出提示, 设置节点隐藏, 指定某个角色走向某个点, 等等.
事件管理器根据特定的情况和判定条件决定是否开启.
可能的类型有
对比类型:
通过触发时传递进来的数值与数据表中的需求值进行对比, 判断第一阶段是否成立. 如果成立在判断附加条件是否成立, 如果成立, 那么事件启动. 执行事件表中的每一步. 这里之所以添加两段判断是为了效率考虑, 当触发一个类型的事件时只检查此类型对应的事件.
4. 事件处理
在数据表中配置好每一步要做的事情以及参数
第一列为事件执行序号, 唯一标识.
第二列为事件 ID, 是一个索引列, 如果你传入 1 会直接得到一个含有 [1,2,3] 的数组
第三列为是否存档的设置, 也就是在哪一步存档, 如果是网络游戏, 就是哪一步告知服务器事件结束.
第四列 就是操作类型了,
通过代码将所有的功能组织起来. 所以说, 教学只是事件管理系统的一个很小的部分.
- update() {
- let item = this.event.getItemModel()
- // cc.log('update ================= step', this.step, 'this.eventID', this.eventID)
- switch (item.getOperateType()) {
- case OperateType.OPEN_DIALOG:
- break;
- case OperateType.OPEN_GUIDE:
- GuideManager.instance().start(item.getParam())
- break;
- case OperateType.OPEN_TIP:
- TipController.instance().showTip(item.getParam(), () => {
- this.event.next()
- })
- break;
- case OperateType.IN_VISIBLE:
- let list = item.getParam().split(':')
- let parent = UIManager.instance().getRoot()
- while (list.length> 0) {
- let name = list.shift();
- let node = EngineHelper.findChild(name, parent)
- if (node) {
- parent = node;
- } else {
- break;
- }
- }
- cc.log('list.length ===========', list.length)
- if (parent && list.length == 0) {
- parent.active = false;
- this.event.next()
- }
- break;
- default:
- this.emit(GameEventName.EVENT_UPDATE, item)
- break;
- }
- }
根据自己定义的处理类型, 在数据表中配置不同的参数, 代码中做不同的处理. 之所以有 defualt 是因为有些操作不是管理器能触及的. 比如对游戏中的角色的操作, 应该是仿真器的事情, 所以仿真器监听事件, 然后根据不同 的操作调用不同的函数, 实现不同的逻辑.
5. 何时检查事件
事件的检查时机是根据定义的触发类型而定的, 当你的条件成立时, 需要主动调用事件管理器的 checkEvent 函数, 传入对应的触发条件类型, 和特定的值即可. 下面举几个例子.
进入界面后在 start 函数中主动检查
在界面已经打开时通过事件接收事件管理器触发的通知.
当 UI 关闭时. 比如刚进入大厅时可能会弹出离线奖励, 签到等界面, 当这些界面都关闭时触发.
总结
以上就是我在游戏开发中使用的事件管理系统, 理论上可以实现你想要的任何操作.
代码已经提交到框架项目中. 感兴趣的可以自己研究研究.?
来源: http://www.bubuko.com/infodetail-3654008.html