RPG游戏新手引导

有些朋友可能是用cocos cretror做的一个2D的ARPG游戏,那在这类游戏的新手引导该怎么做呢?下面就把RPG游戏新手引导实现方式给大家分享下。

设计

引导一般会由各种操作组成,如npc对白、屏幕对白、剧情动画、强制玩家点击某个按钮,打开某个界面等,首先要做的是将引导都抽象出来,变成一个个可配置的项,如下:

操作类型参数说明1 屏幕对白无2 npc对话npc编号3 剧情动画图片名;时长;图片名;时长4 点击按钮UI名;控件名5 打开界面UI名6 自动移动场景编号;x;y7 杀怪怪物编号;数量8 手动移动场景编号;x;y

根据这些操作类型,来配置一个玩家创建完角色进入游戏之后的引导,如下:

// 引导操作配置表,导出:GuideOpConfig.js

编号操作类型对白参数备注13jq1;2;jq2;2;jq3;2创建完角色,播放动画21恶魔将毁灭世界,去阻止他381;10;15教玩家使用摇杆41击败前方的几个小恶魔54点击攻击按钮攻击敌人UIOperation;skillButtonAtk教玩家使用技能61恶魔出现了,打败他们771;5杀死5只小怪81传送门之后是恶魔老巢,Boss就在那里962;10;10跳转到下一个场景102恶魔Boss:哪来的小子n我:我世界守护者nBoss:找死111打败Boss1273:1杀死Boss131恶魔Boss逃掉了142村民:英雄,请你不要走n我:我会找到Boss的155UIStartGame点击正式开始游戏

然后要做的就是将这些引导操作串起来,下面用一个新的配置表,包含上表中各个操作:

// 引导配置表, 导出:GuideConfig.js

编号操作列表备注11;2;3;4;5;6;7;8;10;11;12;13;14;15创建完角色之后的引导

这样,这些操作就串起来了,每个编号对应的就是一个引导流程。

实现

根据上面的设计过程,来写代码。有几个点先说明下:

以一个流程为单位,来播放和记录进度。用一个队列保存将要播放的引导,如果当前没有正在播放的引导,就从队列从去一个出来播放。所有引导操作完成之后,都需要抛出一个事件。

主要的代码如下:

/** * 文件名:GuideComponent.js * 组件说明:引导组件,挂载在场景节点上 */ var GuideConfig = require("GuideConfig"); var GuideOpConfig = require("GuideOpConfig"); cc.Class({ extends: cc.Component, init: function(){ this.guideList = [];// 待处理的引导编号 this.curGuideNo = null;// 当前正在播放引导编号 this.curGuideIndex = 0;// 当前正在播放剧情编号的下标 // 自动移动 this.targetScn = null;// 目标场景 this.targetPos = null;// 目标位置 this.checkReachPos = null;// 自动位置检测函数 // 手动移动 this.checkGoPos = null;// 自动位置检测函数 this.effectNode = null;// 目标点特效 // 打开UI this.targetUI = null;// 目标UI // 杀怪 this.killNo = null;// 要杀的怪物编号 this.killCnt = 0; // 已杀死的怪物数量 this.killTotalCnt = 0;// 要杀的怪物总数 }, start: function () { this.node.on(SceneEventType.ON_GUIDE_DONE, this.onGuideDone, this); gameScene.node.on(SceneEventType.ON_MAP_LOAD, this.onMapLoaded, this); gameScene.node.on(SceneEventType.ON_OPEN_UI, this.onOpenUI, this); gameScene.node.on(SceneEventType.ON_A_DIE, this.onActorDie, this); }, /** * 从服务器数据初始化 * */ initData: function () { var guideList = gameScene.player.blockDataComp.getValue(Const.BlockDataKey.GUIDE) || []; for (var i = 0; i < guideList.length; i++) { var val = guideList[i]; this._addGuide(val); } this.checkGuide(); }, /** * 添加一个引导 * */ _addGuide: function (no) { var index = this.guideList.indexOf(no); if (index >= 0) { return false; } this.guideList.push(no); return true; }, /** * 添加一个待播放的引导, 并坚持播放该引导 * @param no {number} 引导编号 * */ pushGuide: function (no) { if (this._addGuide(no)) { // 将新加入的引导保存到后端 gameScene.player.blockDataComp.setValue(Const.BlockDataKey.GUIDE, this.guideList); this.checkGuide(); } }, /** * 检测当前是否有正在播放的剧情和待播放的引导 * */ checkGuide: function () { if (this.guideList.length > 0 && this.curGuideNo === null) { var no = this.guideList.shift(); this.playGuide(no); } }, /** * 播放的引导 * @param no {number} 引导编号 * */ playGuide: function (no) { this.curGuideIndex = -1;// check的时候会加+ this.curGuideNo = no; this.checkNextGuideOp(); }, /** * 检测当前是下一个剧情操作 * */ checkNextGuideOp: function () { var cfg = GuideConfig[this.curGuideNo]; var opList = cfg.get("opList"); if (this.curGuideIndex < opList.length) { this.curGuideIndex += 1; var opNo = opList[this.curGuideIndex]; this.playGuideOp(opNo); } }, /** * 播放的引导操作 * @param opNo {number} 引导操作编号 * */ playGuideOp: function (opNo) { var cfg = GuideOpConfig[opNo]; var type = cfg.get("type"); var tip = cfg.get("tip"); var args = cfg.get("args"); switch (type) { case Const.Guide.TIPS: this.onGuideTypeTips(this.curGuideNo, this.curGuideIndex, tip, args); break; case Const.Guide.NPC: this.onGuideTypeNpc(this.curGuideNo, this.curGuideIndex, tip, args); break; case Const.Guide.ANI: this.onGuideTypeAni(this.curGuideNo, this.curGuideIndex, tip, args); break; case Const.Guide.TAP: this.onGuideTypeTap(this.curGuideNo, this.curGuideIndex, tip, args); break; case Const.Guide.UI: this.onGuideTypeUI(this.curGuideNo, this.curGuideIndex, tip, args); break; case Const.Guide.MOVE: this.onGuideTypeMove(this.curGuideNo, this.curGuideIndex, tip, args); break; case Const.Guide.KILL: this.onGuideTypeKill(this.curGuideNo, this.curGuideIndex, tip, args); break; case Const.Guide.GO: this.onGuideTypeGo(this.curGuideNo, this.curGuideIndex, tip, args); break; default: cc.error("unknown guide type"); break; } }, /** * 屏幕对白 */ onGuideTypeTips: function (guideNo, guideIndex, tip, args) { gameScene.uiOperation.showBottomTips(tip); var self = this; this.scheduleOnce(function () { self.node.emit(SceneEventType.ON_GUIDE_DONE, { no: guideNo, index: guideIndex }); }, 3); }, /** * npc对话 * */ onGuideTypeNpc: function (guideNo, guideIndex, tip, args) { uiManager.showPanel("UITaskNpcTalk", { guide: true, no: guideNo, index: guideIndex, tip: tip, args: args }); }, /** * 剧情动画 * */ onGuideTypeAni: function (guideNo, guideIndex, tip, args) { uiManager.showPanel("UIScreenAni", { no: guideNo, index: guideIndex, tip: tip, args: args }); }, /** * 点击提示 * */ onGuideTypeTap: function (guideNo, guideIndex, tip, args) { uiManager.showPanel("UITap", { noTouchable: true, no: guideNo, index: guideIndex, tip: tip, args: args }); }, /** * 跳转场景 * */ onGuideTypeMove: function (guideNo, guideIndex, tip, args) { var scn = Math.floor(eval(args[0])); if (args.length > 1) { var x = Math.floor(eval(args[1])); var y = Math.floor(eval(args[2])); if(scn === gameScene.mapComp.mapId){ this.targetPos = [x, y]; this.moveToPos(); } else { this.targetScn = scn; sockManager.send(0.2, CM.transferScene, scn, x, y); } } else { if(scn === gameScene.mapComp.mapId){ // 就在该场景,没有配地点,直接完成 this.node.emit(SceneEventType.ON_GUIDE_DONE, {no: this.curGuideNo, index: this.curGuideIndex}); } else { this.targetScn = scn; sockManager.send(0.2, CM.transferScene, scn); } } }, moveToPos: function () { gameScene.player.opRunTo(this.targetPos[0], this.targetPos[1], false); this.checkReachPos = function () { if (!this.targetScn || this.targetScn === gameScene.mapComp.mapId) { var actor = gameScene.player.actor; if (actor.cx === this.targetPos[0] && actor.cy === this.targetPos[1]) { this.targetScn = null; this.targetPos = null; this.node.emit(SceneEventType.ON_GUIDE_DONE, {no: this.curGuideNo, index: this.curGuideIndex}); this.unschedule(this.checkReachPos); this.checkReachPos = null; } else if (actor.state !== 'run') { gameScene.player.opRunTo(this.targetPos[0], this.targetPos[1], false); } } }; this.schedule(this.checkReachPos, 0.3);// 定时检测是否到达目标点 }, onMapLoaded: function (event) { if (this.targetScn && this.targetScn === gameScene.mapComp.mapId) { if (this.targetPos === null) { this.targetScn = null; this.node.emit(SceneEventType.ON_GUIDE_DONE, {no: this.curGuideNo, index: this.curGuideIndex}); } else { this.moveToPos(); } } }, /** * 打开UI * */ onGuideTypeUI: function (guideNo, guideIndex, tip, args) { var uiName = args[0]; var ui = uiManager.getPanel(uiName); if (ui) { this.node.emit(SceneEventType.ON_GUIDE_DONE, {no: this.curGuideNo, index: this.curGuideIndex}); } else { this.targetUI = uiName; uiManager.showPanel(uiName); } }, onOpenUI: function (event) { var uiName = event.detail; if (this.targetUI === uiName) { this.node.emit(SceneEventType.ON_GUIDE_DONE, {no: this.curGuideNo, index: this.curGuideIndex}); this.targetUI = null; } }, /** * 杀怪 * */ onGuideTypeKill: function (guideNo, guideIndex, tip, args) { this.killCnt = 0; this.killNo = Math.floor(eval(args[0])); this.killTotalCnt = Math.floor(eval(args[1])); }, onActorDie: function (event) { var arg = event.detail; if (this.killNo === arg.no) { this.killCnt += 1; if (this.killCnt === this.killTotalCnt) { this.node.emit(SceneEventType.ON_GUIDE_DONE, {no: this.curGuideNo, index: this.curGuideIndex}); } } }, /** * 手动移动 * */ onGuideTypeGo: function (guideNo, guideIndex, tip, args) { var scn = Math.floor(eval(args[0])); var x = Math.floor(eval(args[1])); var y = Math.floor(eval(args[2])); this.addEffect(x, y); this.checkGoPos = function () { var actor = gameScene.player.actor; if (scn === gameScene.mapComp.mapId && actor.cx === x && actor.cy === y) { this.node.emit(SceneEventType.ON_GUIDE_DONE, {no: this.curGuideNo, index: this.curGuideIndex}); this.unschedule(this.checkGoPos); this.checkGoPos = null; this.removeEffect(); } }; this.schedule(this.checkGoPos, 0.3);// 定时检测是否到达目标点 }, addEffect:function (x, y) { var self = this; var pixelPos = gameScene.cellToMapPos(x, y); gameScene.playEffect({ name: "diandimian", pos: pixelPos, loop: true }, function (effectNode) { self.effectNode = effectNode; } ); }, removeEffect: function () { if (this.effectNode) { gameScene.releaseEffect(this.effectNode); } }, /** * 一个引导完成之后的回调 * */ onGuideDone: function (event) { var data = event.detail; var guideNo = data.no; var index = data.index; if (this.curGuideNo !== guideNo || this.curGuideIndex !== index) { return; } var cfg = GuideConfig[guideNo]; var opList = cfg.get("opList"); var nextIndex = index + 1; if (nextIndex < opList.length) { this.curGuideIndex = nextIndex; var opNo = opList[nextIndex]; this.playGuideOp(opNo); } else { this.curGuideNo = null; // 完成一个引导之后,将其从后端数据删除 gameScene.player.blockDataComp.setValue(Const.BlockDataKey.GUIDE, this.guideList); this.checkGuide(); } }, });

主要的流程就是这样的,另外需要配置的,就是如何触发这些引导,可以在引导配置表里面加一列触发条件,如创建完角色,解锁新的功能等,然后监控这些条件的变化,触发相应的剧情。

相关知识

新手引导游戏新手引导
游戏新手引导 游戏新手引导怎么写
《大话西游2》游戏攻略之新手引导
游戏新手引导设计(下)
新手引导
游戏新手引导设计要点分析
游戏的新手引导,做到位了吗?
手机游戏新手引导策划案样例
永恒雷霆游戏中的新手引导系统详解
分享:游戏新手引导程序框架设计3要点

网址: RPG游戏新手引导 http://www.hyxgl.com/newsview340328.html

推荐资讯