《游戏脚本的设计与开发》-(RPG部分)3.5 游戏背包和任务系统
注意:本系列教程为长篇连载无底洞,半路杀进来的朋友,如果看不懂的话,请从第一章开始看起,文章目录请点击下面链接。
http://blog.csdn.net/lufy_legend/article/details/8888787
本节重点来讲一下背包系统,以及简单的先来认识一下任务系统。
先看一下背包系统的效果预览:
背包系统在游戏中是必不可少的,在游戏中,所有获得的物品都会储存在背包里面。背包的种类,我一般将它分成两大类,一种是类似于《吞食天地》的“个人背包”,在游戏中每个人物都有一个背包,每个人的背包都互不影响,并且每个人只能使用自己背包中的物品。另一种是“集体背包”,游戏中所有己方的人物都共用一个背包,大多数游戏都采用这种形势。下面我们就来实现一下“集体背包”。
我们先来做一个按钮,用来打开游戏菜单,按钮的添加很简单,界面如下。
根据我制作《三国记》的经验,游戏菜单的UI需要注意的是,按钮要尽量大一些,否则在手机上就很难被点到。先来创建游戏菜单的相关文件。
控制器MenuController,模型MenuModel和视图MenuView。
https://github.com/lufylegend/lsharp/blob/3.5/Controllers/MenuController.js
https://github.com/lufylegend/lsharp/blob/3.5/Models/MenuModel.js
https://github.com/lufylegend/lsharp/blob/3.5/Views/MenuView.js
关于菜单,我们需要有一个下面这样的背景框
并且这个背景框在其他许多地方也都会被用到,所以我们把它做成一个共同的外部类,如下。
https://github.com/lufylegend/lsharp/blob/3.5/Libraries/window/WindowBackground.js
这个类的实现原理如下,将一个只有左上角的图片,通过分割,旋转,拉伸等操作,组合成一个背景框
也就是说,我们只需要多准备几张类似于如下的图片,就可以实现不同的背景框了。
游戏菜单中的按钮,由图标和文字两部分组成,为了方便,我们也封装一个外部类。
https://github.com/lufylegend/lsharp/blob/3.5/Libraries/button/ButtonText.js
接下来准备好相应的菜单按钮图标,在菜单的视图中添加如下一系列代码。
......
var backpack = new ButtonText("backpack","背包",true);backpack.x = startX + xindex*step;backpack.y = startY + yindex*step;self.menuLayer.addChild(backpack);backpack.addEventListener(LMouseEvent.MOUSE_UP, function(event){LTweenLite.to(self.menuLayer,0.3,{x:LGlobal.width,onComplete:function(){self.controller.showBackpack();}});});
......
最后,给画面中的菜单按钮添加打开菜单的点击事件,打开菜单的代码如下。
MapController.prototype.openmenuClick = function(){var self = this;self.loadMvc("Menu",self.openmenuComplete);
};
MapController.prototype.openmenuComplete = function(){var self = this;var menu = new MenuController();menu.baseView = self.view;self.view.parent.addChild(menu.view);//移动端的时候,为了提高效率,将地图隐藏if(LGlobal.canTouch){self.view.visible = false;}
};
下面是菜单效果。
为了好看,我临时添加了背包,装备,武将,任务,设置等几个功能按钮,本次只讲一下背包部分的具体实现,其他部分我们后面再慢慢讲。
背包部分我们也为其创建相关的文件。
控制器BackpackController,模型BackpackModel和视图BackpackView。
从文章开头的预览图片中,我们看到恢复用品,武器装备,特殊物品三个按钮其实是tab选项卡,有是否被选中两种状态,所以我们为这个功能封装下面一个类。
https://github.com/lufylegend/lsharp/blob/3.5/Libraries/button/ButtonSelect.js
其中的GetButton是我另创建的一个辅助函数,功能就是返回一个带文字或者不带文字的按钮,代码如下
https://github.com/lufylegend/lsharp/blob/3.5/Helpers/GetButton.js
在背包的视图中首先添加背景框,然后添加类似于下面一系列代码。
......var closeButton = GetButton(LMvc.datalist["BtnClose01"],null,0);closeButton.x = 710;closeButton.y = 25;self.addChild(closeButton);closeButton.addEventListener(LMouseEvent.MOUSE_UP, function(){self.controller.closeBackpack();});var recoveryButton = new ButtonSelect("BtnSelect01",{label:"恢复用品",width:180,height:48},1);recoveryButton.x = 550;recoveryButton.y = 110;self.addChild(recoveryButton);self.recoveryButton = recoveryButton;recoveryButton.addEventListener(LMouseEvent.MOUSE_UP, function(){self.controller.recoveryPropsSelect();});
......
效果如下。
按钮选项卡的选中和非选中状态,我们只要像下面这样。
specialButton.setSelected(true);
选项卡是否处于选中状态,我们也可以很轻松的判断。
if(specialButton.selected)return;
好了,接下来为了给背包中添加物品,我们需要先定义物品,在script/initialization文件夹下添加props.json文件,先简单的来定义三个物品。
{
"props1":{"Index":1,"Name":"包子","Type":"Recovery","Max":99,"Icon":1,"Hp":30,"Mp":0,"Force":0,"Intelligence":0,"Command":0,"Agile":0,"Luck":0,"Introduction":"普通的馒头,可以恢复一点HP。"},
"props2":{"Index":2,"Name":"天书残卷","Type":"Special","Max":1,"Icon":2,"Introduction":"特殊物品之天书残卷,暂时没有详细介绍。"},
"props3":{"Index":3,"Name":"倚天剑","Type":"Weaponry","Max":1,"Icon":3,"Introduction":"倚天剑,介绍略。"}
}
几个属性分别代表Index:物品序号,Name:物品名称,Type:物品分类,Max:背包中一个物品位可盛放的最大数量,Icon:图标。这几个属性只是为了能在背包中显示,其他的属性,等用到的时候我再具体说。
为了更方便在游戏程序中操作它们,我们为物品的每个种类,分别创建相应的类。
恢复物品
function PropsRecovery(data){var self = this;self.index = data.Index;self.name = data.Name;self.type = data.Type;self.icon = data.Icon;self.max = data.Max;self.count = 1;self.data = data;
}
武器装备
function PropsWeaponry(data){var self = this;self.index = data.Index;self.name = data.Name;self.type = data.Type;self.icon = data.Icon;self.max = data.Max;self.count = 1;self.data = data;
}
特殊物品
function PropsSpecial(data){var self = this;self.index = data.Index;self.name = data.Name;self.type = data.Type;self.icon = data.Icon;self.max = data.Max;self.count = 1;self.data = data;
}
然后给LRPGObject类添加物品数组,用来盛放所有的物品。
LRPGObject.propsList = [];
我们再继续给LRPGObject类添加两个函数,分别是添加物品和删除物品,操作很简单,就是往propsList里添加和删除元素。
LRPGObject.addProps = function(index){var propsData = LMvc.datalist["props"]["props"+index],i,l,props;if(!propsData)return;for(i=0,l=LRPGObject.propsList.length;i<l;i++){props = LRPGObject.propsList[i];if(props.index == propsData.Index){if(props.count < props.max){props.count = props.count + 1;return;}}}switch(propsData.Type){case "Recovery":LRPGObject.propsList.push(new PropsRecovery(propsData));break;case "Special":LRPGObject.propsList.push(new PropsSpecial(propsData));break;case "Weaponry":LRPGObject.propsList.push(new PropsWeaponry(propsData));break;}
};
LRPGObject.removeProps = function(index){var propsData = LMvc.datalist["props"]["props"+index],i,l,props;if(!propsData)return;for(i=LRPGObject.propsList.length - 1;i>=0;i--){props = LRPGObject.propsList[i];if(props.index == propsData.Index){props.count--;if(props.count <= 0){LRPGObject.propsList.splice(i,1);break;}}}
};
当点击不同的选项卡的时候,我们需要先把LRPGObject.propsList数组中的物品筛选出来,如下
BackpackModel.prototype.propsSelect=function(propsType){var self = this,i,l,props;self.data.length = 0;self.dataIndex = 0;for(i=0,l=LRPGObject.propsList.length;i<l;i++){props = LRPGObject.propsList[i];if(props.type == propsType){self.data.push(props);}}
};
然后规定几个物品一组,来分页获取需要显示的物品列表。
BackpackModel.prototype.getProps=function(){var self = this,i,l,props,list=[];if(self.dataIndex < 0 || self.dataIndex >= self.data.length){return [];}for(i=self.dataIndex,l=self.data.length>i+self.dataMax?i+self.dataMax:self.data.length;i<l;i++){props = self.data[i];list.push(props);}return list;
};
得到了物品列表之后,将物品添加到背包的视图中就行了。
BackpackView.prototype.showProps=function(){var self = this,num,l,icon,props;var list = self.model.getProps();num = 0;l = list.length;self.propsLayer.die();self.propsLayer.removeAllChild();for(var i=0;i<3 && num<l;i++){for(var j=0;j<2 && num<l;j++){props = list[num];icon = new PropsIcon(props);icon.x = self.propsStartX + 120*i;icon.y = self.propsStartY + 135*j;self.propsLayer.addChild(icon);num++;}}
};
效果。
接下来就是脚本了,我们如何来利用脚本添加或者删除一个物品呢?看下面的脚本。
//添加一个物品,参数:物品序号RPGProps.add(1);//删除一个物品,参数:物品序号RPGProps.remove(2);
下面是脚本解析,很简单不是吗
/*
* LRPGPropsScript.js
**/
LRPGPropsScript = function(){};
LRPGPropsScript.analysis=function(value){var start = value.indexOf("(");var end = value.indexOf(")");switch(value.substr(0,start)){case "RPGProps.add":LRPGPropsScript.add(value,start,end);break;case "RPGProps.remove":LRPGPropsScript.remove(value,start,end);break;default:LGlobal.script.analysis();}
};
LRPGPropsScript.add = function (value,start,end){var params = value.substring(start+1,end).split(",");LRPGObject.addProps(params[0]);LGlobal.script.analysis();
};
LRPGPropsScript.remove = function (value,start,end){var params = value.substring(start+1,end).split(",");LRPGObject.removeProps(params[0]);LGlobal.script.analysis();
};
好了,背包系统,基本上就是这样了。
下面我们来介绍另一个非常重要的功能,就是任务系统,任务系统其实是比较复杂的,涉及到任务列表,任务奖励,任务的不同阶段的判定等等,这些我们后面会单独写一篇来详细讲解,本次先来利用现有的变量功能来完成一个简单的任务功能。
我假设关羽借了酒店老板一样东西,自己又懒得去还,想让刘备当个跑腿儿的,去帮忙把书还上,然后刘备拿着这个东西去还给酒店老板,然后老板给了刘备两个包子作为奖励。
在这一过程中,我们首先需要判断是否有任务,任务是否在进行中,任务是否已经结束等。
看下面点击关羽时的脚本
function characterclick2();if(@task1000==1); RPGTalk.set(2,0,你知道lufy吗,听说那家伙除了做游戏,啥都不会。);RPGTalk.set(1,0,怪不得啊,哈哈哈。);elseif(@task1001==1); RPGTalk.set(2,0,《天书残卷》交给酒店老板了吗?); else; RPGTalk.set(2,0,这本《天书残卷》是我前两天从酒店老板那里借来的,你能帮我还回去吗?); RPGTalk.set(1,0,好啊,我正想去酒店喝点儿酒呢。);RPGProps.add(2);Var.set(task1001,1); RPGMessageBox.show(得到了《仙书残卷》。请到酒店把它交给酒店老板吧。);endif;
endfunction;
变量task1000=1表示任务已经结束,task1001=1表示任务正在进行中,否则就是任务还没有开始。
当任务没有开始的时候,所做的处理是先让刘备接受任务,然后把东西《仙书残卷》交给刘备。然后把变量task1001设置为1,表示任务开启,正在进行。
再看点击酒店老板的脚本。
function characterclick6();RPGTalk.set(6,0,欢迎光临小店,客官要点儿什么?);if(@task1001==1);RPGTalk.set(1,0,关羽让我把这本《天书残卷》还给你。);RPGTalk.set(6,0,哎呀,太谢谢了,我正想去跟他要呢。);RPGProps.remove(2);Var.set(task1000,1); Var.set(task1001,2); RPGProps.add(1);RPGProps.add(1);RPGMessageBox.show(获得奖励:两个包子。);else;RPGTalk.set(1,0,我比较关心那边弹琴的美女是谁。);RPGTalk.set(6,0,她天下第一美女貂蝉啊。);endif;
endfunction;
当task1001=1任务正在进行的时候,老板会接收刘备拿来的东西,然后给刘备两个包子作为奖励。最后把变量task1000设置为1,表示任务结束。然后为了防止任务再次出发,把task1001设置为2。
好了,上面的脚本的效果如下。
眼尖的朋友可以看到,我在脚本里用到了 RPGMessageBox . show这个脚本,这个脚本会弹出提示框,如下
MessageBox的代码如下
https://github.com/lufylegend/lsharp/blob/3.5/Helpers/MessageBox.js
脚本解析部分
/*
* LRPGMessageBoxScript.js
**/
LRPGMessageBoxScript = function(){};
LRPGMessageBoxScript.analysis=function(value){var start = value.indexOf("(");var end = value.indexOf(")");switch(value.substr(0,start)){case "RPGMessageBox.show":LRPGMessageBoxScript.show(value,start,end);break;default:LGlobal.script.analysis();}
};
LRPGMessageBoxScript.show = function (value,start,end){var params = value.substring(start+1,end).split(",");MessageBox.show(params[0]);
};
这样,一个简单的任务就完成了,当然这个不是任务系统的全部,这只是我用变量来完成一个任务的简单的小例子,关于任务,我后面再详细说。
另外,有朋友反映,图片不好找,好不容易找到了图片,又不能用,所以我修改了一下 Character类和Action类,代码如下
https://github.com/lufylegend/lsharp/blob/3.5/Libraries/Character.js
https://github.com/lufylegend/lsharp/blob/3.5/Libraries/Action.js
这样就可以根据实际的图片,在chara.json里定义相关的参数了
https://github.com/lufylegend/lsharp/blob/3.5/script/initialization/chara.json
比如刘备
"peo1":{"Index":1,"Name":"刘备","Face":1,"R":1,"RRect":[140,95,40,90],"Introduction":"刘备即蜀汉昭烈帝,字玄德,汉中山靖王刘胜的后代,三国时期蜀汉开国皇帝。"}
RRect表示人物在一个动作图片中的有用范围,
另外默认的每贞动作图片的大小是320x240,如果你的图片大小不一样,那还需要定义一下图片的大小,比如下面这样
"peo8":{"Index":8,"Name":"测试","Face":3,"R":6,"RRect":[10,6,50,82],"RWidth":70,"RHeight":92,"Introduction":"测试"}
要想看看自己定义的大小是不是正确的话,开启debug模式就可以看到效果了,效果如下
好了,还是自己测试一下效果吧。
http://lufylegend.com/demo/test/lsharp/rpg-lsharp-05/index.html
最后,给出本次的代码下载:
https://github.com/lufylegend/lsharp/archive/3.5.zip
预告:下次讲一下人物列表和人物属性,为战斗画面做准备。
《游戏脚本的设计与开发》系列文章目录
http://blog.csdn.net/lufy_legend/article/details/8888787
转载请注明:转自lufy_legend的博客http://blog.csdn.net/lufy_legend
《游戏脚本的设计与开发》-(RPG部分)3.5 游戏背包和任务系统相关推荐
- 《游戏脚本的设计与开发》-(RPG部分)3.6 队员列表和人物属性
注意:本系列教程为长篇连载无底洞,半路杀进来的朋友,如果看不懂的话,请从第一章开始看起,文章目录请点击下面链接. http://blog.csdn.net/lufy_legend/article/de ...
- 《游戏脚本的设计与开发》-(RPG部分)3.8 通过脚本来自由控制游戏(一)
注意:本系列教程为长篇连载无底洞,半路杀进来的朋友,如果看不懂的话,请从第一章开始看起,文章目录请点击下面链接. http://blog.csdn.net/lufy_legend/article/de ...
- 《游戏脚本的设计与开发》-(RPG部分)3.1 RPG地图到底怎么做?
http://blog.csdn.net/lufy_legend/article/details/17417085 话说好久没有更新博客了,其实这段时间主要是工作忙,没时间.那又是什么刺激了我呢,为什 ...
- 《游戏脚本的设计与开发》-(RPG部分)3.4 地图跳转
注意:本系列教程为长篇连载无底洞,半路杀进来的朋友,如果看不懂的话,请从第一章开始看起,文章目录请点击下面链接. http://blog.csdn.net/lufy_legend/article/de ...
- 《游戏脚本的设计与开发》-目录序
本系列文章目录 章节 标题 连接 序 游戏脚本简介 http://blog.csdn.net/lufy_legend/article/details/8888787 第一章 基本功能 1.1 读取和解 ...
- 《游戏脚本的设计与开发》-第一部分总结 文字脚本的功能扩展和一个游戏测试...
脚本系列文章写了好几篇了,大家可能都不清楚这些脚本有什么用,游戏中如何能应用到这些东西.当然,目前所介绍的内容还只是个简单的开头,说到做游戏还远远不够.不过,本次就使用前几章所介绍的内容,先来尝试一下 ...
- 《游戏脚本的设计与开发》-1.1 读取和解析一个脚本文件
上一篇<游戏脚本的设计与开发>-序中我介绍了游戏脚本的基本概念和准备工作,本篇来说说具体如何解析一个脚本 所谓解析脚本,就是按照自己定义的语法,将每一个脚本命令还原成不同的代码逻辑进行执行 ...
- 《游戏脚本的设计与开发》-第一章总结 文字脚本的功能扩展和一个游戏测试
脚本系列文章写了好几篇了,大家可能都不清楚这些脚本有什么用,游戏中如何能应用到这些东西.当然,目前所介绍的内容还只是个简单的开头,说到做游戏还远远不够.不过,本次就使用前几章所介绍的内容,先来尝试一下 ...
- 《游戏脚本的设计与开发》-1.6 按钮,脚本的暂停和标签
按钮 按钮在任何程序中都是必不可少的,本次先来看看如何脚本来实现按钮的各种功能.文章中要实现的几个脚本如下. /* 游戏脚本的设计与开发 第六章 */ //添加按钮 Button.add(layer0 ...
最新文章
- mysql user表添加记录_《MySQL数据操作与查询》- 返校复习课练习题,创建数据库user_system,创建数据表user及user_ext...
- Parallels Desktop 16 Win11虚拟机将继续正常运作,但将无法连接网络
- 10没有基于策略的qos_基于强化学习的用户移动场景下空中基站3D位置高效部署...
- 用户可以使用三种方式使用计算机,计算机操作系统期末复习笔记
- 科学计算机化弧度,弧度与角度换算工具
- linux java调优
- python基础题目练习,购买猕猴桃
- MySQL 自联结 自连接
- 一文读懂|什么是dToF激光雷达技术?
- Ubuntu安装搜狗fcitx无法正常安装的问题
- 软件测试工程实训综合管理平台
- Storm - Trident
- torchtext使用-- 单标签多分类任务TREC
- 计算机毕业设计SSM电商后台管理系统【附源码数据库】
- 软考知识点——Gant图与Pert图、McCabe复杂度计算
- 解决网页版网易云别人歌单只能听二十首
- dozer对象Mapping框架
- 你真的理解计算机时间吗?
- 自创打油诗【我是程序猿】 --作者:君君
- 实验四 应用层和传输层协议分析(PacketTracer)
热门文章
- strcat函数与strncat函数——追加字符串
- Excel-财务函数2
- k8s-核心概念与API原语
- 简述一下你对HTML语义化的理解
- 考研学生应该知道:研究方向和开发技术
- [附源码]Java计算机毕业设计SSM党史知识竞赛系统
- 如何快速的学好英语(Aprial)
- 音量控制软件Sound Control for mac
- 软件项目技术点(2)——Canvas之获取Canvas当前坐标系矩阵
- 无法创建新虚拟机: 无法打开配置文件“E:\Linux\“: 拒绝访问