想到新手引导的功能时可能很多人都会觉得头痛,难以下手。特别是在游戏本身功能或需求还不稳定的情况,更是难以应付,本人就是在这种情况下接受了一个艰巨的任务。在痛定思痛之后,开始了引导功能开发。在做的过程中一点点发现很多有意思的东西,想分享给大家。

一、痛点:新手引导制作的难点及弊端

  1. 需要在具有引导功能的代码单元插入引导代码或逻辑判断,干扰正常流程。

  2. 引导代码的加入会影响原有的代码逻辑与流程,使代码变得复杂加大维护难度。

  3. 界面或需求发生变化后引导功能需要大幅修改或重新制作。

  4. 指引(手指提示)对应的矩形区定位麻烦,特别是需要适应不同尺寸屏幕的时候更加困难。

  5. 编写引导配置文件也很头痛,需要策划、程序的高度配合。

二、期望:新手引导编程体验

笔者进入游戏开发应该说是手机游戏开发并不是很长时间,虽然参于过多个项目,但亲自编写新手引导这还是头一次。当时接到新人引导任务时,我们的项目只完成了:登录->主界面->抽卡->布阵->章节->关卡->战斗这样一个基本流程,界面美术、功能需求都极不稳定。但在公司的硬性要求下,冒着九死一生的危险开始了新手引导功能开发。在了解到传统的引导制作过程中的难点与弊端后,一直在思考没有更好的实现方式,我心中的引导编程的方式有以下几点:

  1. 不需要在每个单元中去插入引导代码,游戏代码与引导代码应该尽量分离。本人很难忍受漂亮的代码被无情引导打乱,更难忍受本来糟糕的代码被引导弄得支离破碎。

  2. 界面只发生简单UI位移、节点层次改变不需要修改引导代码。

  3. 定位指引矩形区应该尽量的简单,且自适应不同尺寸屏幕。最好能做到策划人员都可以来制作部分流程引导。

  4. 在引导需求明确、游戏功能正常的情况下,制作一个常规的引导步骤应该是非常快捷的,不会超过3分钟,快的话1分钟内就应该搞定(不是笔者说大话,确实已经实现)。

三、思想:引导功能的设计思路

在描述引导功有设计思路之前,有个重要的前题:命名规范

命名规范主要有两个方面:

  1. cocostudio中的控件名字

  2. 代码中动态创建的控件名字,以及类成员变量的名字。

在笔者的项目中使用了sz.UILoader来管理cocostudio的UI命名和事件。如不了解请参见我的另外一篇blog

《在cocos2d-js实现自动绑定cocostudioUI控件与事件》

我们这里引入两个概念:任务与任务组。任务:把引导中的一个最小步骤称之为一个任务,比如提示点击某个按钮。任务组:把一系列的任务放在一个任务组中,当这个任务组中的任务全部完成,我们会保存一次任务进度。此时重新进入游戏将不会再执行这个任务,而是执行它的下一个任务组中的任务。可以理解任务组是引导中的一个步骤。

用json格式表示如:

{

1: [{任务1},{任务2},{任务3}]

3: [{任务7},{任务8},{任务9}]

2: [{任务4},{任务5},{任务6}]

}

当从一个任务组中的任务中断后,再次进入引导 需要重新从这个任务组的第一个任务开始。

见下图演示了一个从主界面点击召唤->灵石召唤一次->点击获得->确定->仙玉召唤一次->点击获得->确定->点击空白退出召唤界面的流程。

上图演示的引导我分成两个任务组:灵石召唤、仙玉召唤。 任务配置如下:

"3":[
  {
    "name": "4.提示指向灵石召唤按钮","command": "手型提示""tag": "_oneMoneyButton"  }"保存进度""保存进度"  }"5.提示指向角色确定按钮""_UILotteryHero > _confirmBtn"  }"6.提示指向角色图标确定按钮""_UILotteryTimes > _confirmBtn"  }
]"4":[
  {
    "7.提示指向仙玉召唤按钮""_oneGoldButton"  }"8.提示指向角色确定按钮""_UILotteryHero/Panel_33/Image_10/_confirmBtn"  }"9.提示指向角色图标确定按钮""_UILotteryTimes/Panel_11/Image_1/_confirmBtn"  }

其中每个任务中的name用于调试打印的对引导本身无实际用处,在任务开始和结速都会有提示,如果出错方便定位。 command这里应该叫做指令,对应一段具体功能的代码或函数,我这里设置了两个:手型提示、保存进度。

手型提示:需要配合tag字段的值,tag描述了一个当前任务状态下的一个node节点的索引。具体tag的编写方式请看下面一节"实现在节点树中定位控件"。

进度保存:手动进度保存是为了确保在任务中断后,游戏流程不受影响。 在招唤这个功能里,是只能召唤一次的,如果已经召唤成功了,服务器已经更新数据 ,后面的引导都是客户端的界面显示、关闭引导。如果在召唤之后,做一次进度保存,任务中断后再次进入引导会跳过这个任务组中的任务。

在理解了任务的功能后,需要有一个上层框架来一个一个的执行这些任务。

引导框架:在任务条件满足时(比如:等级要达到多少或者无任何条件),指示用户进行某项任务(比如按钮的点击)。当任务完成后,执行下一个任务,直接到全部任务被完成。它需要具有以下几点功能:

  1. 条件检查:检查是否该执行该任务,默认为无条件执行。这需要检查任务是否有onTaskBegan函数 ,不存在或返回ture才能执行任务指令

  2. UI 定位:找到出当前任务中UI节点对应的矩形区。在指引任务中准确编写UI定位描述,由框架去检索UI节点,当检索到节点后调用任务的onLocateNode函数,传入节点对像,这可以让整个引导可以有更多的扩展。

  3. 指引动画:当定位成功后,引导框播放指引提示动画,提示用户操作该矩形区。

  4. 触摸限制:屏蔽定位节点矩形区外的操作全部。

  5. 事件检查:矩形区对应的UI事件是否被执行。

  6. 任务完成:通知引导框架任务完成,进入下一个任务。

四、定位:实现在节点树中定位控件

以上几点中首要解决的是对UI控件的定位,对UI定位最直接有效的方法是在拿到这个UI控件对象,然后取出他的BoundingBox、锚点信息,进行座标转换。但如何才能拿到这个控件对象呢? 这里有两种实现方式:

1. 遍历场景树,把它搜索出来。

2. 事先把这个控件对象注册到你的引导框架中。

我采取的是第一种方法来定位控件,因为我不想在到处代码中添加游戏逻辑以外的东西。而且cocos2d-js中提供有现成的函数cc.helper.seekWidgetByName,如果你做的是手机游戏是不能直接使用这个函数的。在HTML5上这个函数可以遍历整个节点树,在jsb上只是遍历的Widget节点。 有两种方法解决这个问题:

1.把cc.helper.seekWidgetByName函数复制到自己代码文件中,重新取个名字叫:xxx.helper.seekNodeByName。在html5和jsb上都使用这个函数。

2.在c++ jsb上把cc.Helper.seekWidgetByName的参数修改成在Node节点上做遍历,或都重新封装一个jsb上的seekNodeByName函数 。

我这里偷懒还是使用第一种方法。通过上面的方法是否已经解决UI定位的问题呢?应该没那么简单吧!通过这种方法定位控件,就不用在引导配置文件里填写坐标或矩形数据,那是极其愚蠢的办法。

  1. 打住,他妈的还有问题!!!如果一个场景树中有两个相同节点名字怎搞?

这个问题确实问的很正确。因为我们经常会有名字相同的节点存在。比如下图:

如果他们名字都叫button,使用seekNodeByName是来定位控件的话只能找到其中一个。具体是那个是根据你addChild

的顺序来决定的。这个问题如何解决?能唯一确定一个控件在场景树中的方法就是他的“完整路径”,

像这样一下来描述两个button:

"招唤界面/灵石招唤/召唤一次"

"招唤界面/仙玉招唤/召唤一次"

其实我们已经能定位到灵石招唤和仙玉招唤了(我这里为了方便理解使用中文名字)只需要这样写:

"灵石招唤/召唤一次"

"仙玉招唤/召唤一次"

这样也能精确定位到你想要的那个按钮。


在这里我实现了一个简易的定位器描述规则,我们以后通过以下方式在任务中定位一个控件 :

  1. 名字描述:在场景中有独一无二的名字时,直接描述控件名如:'_loginButton'。

  2. 路径名描述:在场景中需要定位的节点可能有重名时,找到其父节点,确保父节点不会有重名时使用:'parentName/button'。如果父节点也有重名,那就再向上使用其父节点名的父节点以此类推。

  3. js属性描述: 有一种情况通过getChildByName无法直接访问的节点,如ccui.ScollView容器中的节点。我定义了一种简单的获取方式,例如 'layer1.button' 通过“.”这个符号来定位layer1下的一个属性为button。这种方式是在js中最为直接的方式。

  4. 子节点描述:使用完整路径描述一个控件时,有时会觉得比较长,例如:'mainLayer/layer1/button' 可以简写成 'mainLayer>button' 表示定位mainLayer下一个名字叫button的子节点,有可以是1级子节点,也可能为2、3、n级子节点。

5.复合描述:将以上几个方式组合使用,来描述一个控件:'mainLayer>homeLayer/layer1.button' 。用人话翻译下就是:mainLayer下有一个homeLayer子节点(不管是几级)下的一级子节点layer1下的一个变量名为button的节点.

描述符号总结 :

/ : 表示一级子节点

>: 表示一级~n级子节点

. : 表示属性名

这里就体现了为什么要注意名命规范的问题。有web开发经验的人一眼就能看出这里有一点css选择器的味道,呵呵!非常正确,正是借鉴了css选择器的思想,实现一个十分简单的选择器,我们这里可以称之为“定位器”,因为我们只需要定位出一个节点。


(未完待续)

使用cocos2d-js制作游戏新手引导一的更多相关文章

  1. HTML5 input新增type属性color颜色拾取器的实例代码

    type 属性规定 input 元素的类型。本文较详细的给大家介绍了HTML5 input新增type属性color颜色拾取器的实例代码,感兴趣的朋友跟随脚本之家小编一起看看吧

  2. amazeui模态框弹出后立马消失并刷新页面

    这篇文章主要介绍了amazeui模态框弹出后立马消失并刷新页面,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  3. 移动HTML5前端框架—MUI的使用

    这篇文章主要介绍了移动HTML5前端框架—MUI的使用的相关资料,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  4. AmazeUI 模态窗口的实现代码

    这篇文章主要介绍了AmazeUI 模态窗口的实现代码,代码简单易懂,非常不错,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  5. ios – UIPopoverController出现在错误的位置

    所以我花了一些时间寻找答案,但到目前为止还没有找到任何答案.我正在尝试从UIInputAccessoryView上的按钮呈现弹出窗口.UIBarButtonItem我想显示popover来自定制视图,所以我可以使用图像.我创建这样的按钮:当需要显示popover时,我这样做:但我得到的是:弹出窗口看起来很好,但它应该出现在第一个按钮上时出现在第二个按钮上.然后我发现了这个问题:UIBarButto

  6. ios – 关闭UIBarButtonItem上的突出显示

    我正在尝试使用UIBarButtonItem在我的UIToolbar上添加标题.我使用简单的风格,看起来很好,但我似乎无法让它停止突出显示触摸.“突出显示时触摸”选项不适用于条形按钮项目.有没有快速简便的方法来做到这一点?

  7. 以编程方式调整iOS中的按钮大小

    我正在使用XCode4.6.1并开发iOS6.我在故事板上添加了一个按钮.我在我的实现文件ViewController.m中创建了一个插座:我尝试按如下所示更改按钮b1的属性(在同一个文件中:ViewController.m):当我在模拟器中运行应用程序时,按钮的alpha成功设置为0.5.但是,按钮的位置和大小不会改变.我尝试了各种方法来实现它.然而似乎没有任何作用.我想知道我做错了什么.我对O

  8. 如何在iOS / Swift的顶部导航栏中添加“继续”按钮

    我想在导航栏的右侧添加一个“继续”按钮.如何实现这一目标?我一直在尝试使用UIBarButtonItem上的一些方法,但无法使其正常工作.我迄今为止的最大努力是:但我在第一行遇到错误.它不喜欢“style”参数.我也试过了但没有运气.仍然停留在样式参数上.有任何想法吗?

  9. ios – 将图像添加到界面构建器中的按钮

    我想在我的按钮而不是文本中添加图像.我可以在界面构建器中这样做吗?我可以看一下这个例子吗?

  10. ios – 自定义BackBarButtonItem

    主要原因是您丢失了标准后退按钮滑动动画以更改视图.此外,这意味着我不需要使用自定义按钮或编写自定义方法返回.它只是起作用.希望这也能解决别人的问题,我知道我已经坚持了3个小时!

随机推荐

  1. 【cocos2d-x 3.x 学习笔记】对象内存管理

    Cocos2d-x的内存管理cocos2d-x中使用的是上面的引用计数来管理内存,但是又增加了一些自己的特色。cocos2d-x中通过Ref类来实现引用计数,所有需要实现内存自动回收的类都应该继承自Ref类。下面是Ref类的定义:在cocos2d-x中创建对象通常有两种方式:这两中方式的差异可以参见我另一篇博文“对象创建方式讨论”。在cocos2d-x中提倡使用第二种方式,为了避免误用第一种方式,一般将构造函数设为protected或private。参考资料:[1]cocos2d-x高级开发教程2.3节[

  2. 利用cocos2dx 3.2开发消灭星星六如何在cocos2dx中显示中文

    由于编码的不同,在cocos2dx中的Label控件中如果放入中文字,往往会出现乱码。为了方便使用,我把这个从文档中获取中文字的方法放在一个头文件里面Chinese.h这里的tex_vec是cocos2dx提供的一个保存文档内容的一个容器。这里给出ChineseWords,xml的格式再看看ChineseWord的实现Chinese.cpp就这样,以后在需要用到中文字的地方,就先include这个头文件然后调用ChineseWord函数,获取一串中文字符串。

  3. 利用cocos2dx 3.2开发消灭星星七关于星星的算法

    在前面,我们已经在GameLayer中利用随机数初始化了一个StarMatrix,如果还不知道怎么创建星星矩阵请回去看看而且我们也讲了整个游戏的触摸事件的派发了。

  4. cocos2dx3.x 新手打包APK注意事项!

    这个在编译的时候就可以发现了比较好弄这只是我遇到的,其他的以后遇到再补充吧。。。以前被这两个问题坑了好久

  5. 利用cocos2dx 3.2开发消灭星星八游戏的结束判断与数据控制

    如果你看完之前的,那么你基本已经拥有一个消灭星星游戏的雏形。开始把剩下的两两互不相连的星星消去。那么如何判断是GameOver还是进入下一关呢。。其实游戏数据贯穿整个游戏,包括星星消除的时候要加到获得分数上,消去剩下两两不相连的星星的时候的加分政策等,因此如果前面没有做这一块的,最好回去搞一搞。

  6. 利用cocos2dx 3.2开发消灭星星九为游戏添加一些特效

    needClear是一个flag,当游戏判断不能再继续后,这个flag变为true,开始消除剩下的星星clearSumTime是一个累加器ONE_CLEAR_TIME就是每颗星星消除的时间2.连击加分信息一般消除一次星星都会有连击信息和加多少分的信息。其实这些combo标签就是一张图片,也是通过控制其属性或者runAction来实现。源码ComboEffect.hComboEffect.cpp4.消除星星粒子效果消除星星时,为了实现星星爆裂散落的效果,使用了cocos2d提供的粒子特效引擎对于粒子特效不了

  7. 02 Cocos2D-x引擎win7环境搭建及创建项目

    官网有搭建的文章,直接转载记录。环境搭建:本文介绍如何搭建Cocos2d-x3.2版本的开发环境。项目创建:一、通过命令创建项目前面搭建好环境后,怎样创建自己的Cocos2d-x项目呢?先来看看Cocos2d-x3.2的目录吧这就是Cocos2d-x3.2的目录。输入cocosnew项目名–p包名–lcpp–d路径回车就创建成功了例如:成功后,找到这个项目打开proj.win32目录下的Hello.slnF5成功了。

  8. 利用cocos2dx 3.2开发消灭星星十为游戏添加音效项目源码分享

    一个游戏,声音也是非常的重要,其实cocos2dx里面的简单音效引擎的使用是非常简单的。我这里只不过是用一个类对所有的音效进行管理罢了。Audio.hAudio.cpp好了,本系列教程到此结束,第一次写教程如有不对请见谅或指教,谢谢大家。最后附上整个项目的源代码点击打开链接

  9. 03 Helloworld

    程序都有一个入口点,在C++就是main函数了,打开main.cpp,代码如下:123456789101112131415161718#include"main.h"#include"AppDelegate.h"#include"cocos2d.h"USING_NS_CC;intAPIENTRY_tWinMain{UNREFERENCED_ParaMETER;UNREFERENCED_ParaMETER;//createtheapplicationinstanceAppDelegateapp;return

  10. MenuItemImage*图标菜单创建注意事项

    学习cocos2dx,看的是cocos2d-x3.x手游开发实例详解,这本书错误一大把,本着探索求知勇于发现错误改正错误的精神,我跟着书上的例子一起调试,当学习到场景切换这个小节的时候,出了个错误,卡了我好几个小时。

返回
顶部