给宝宝做一个cocos免费游戏
第一章 背景和开发框架介绍
第二章 Node树和场景制作
第三章 UI、地图和关卡文本制作
第四章 摇杆、按键和角色动画制作
第五章 敌人和AI制作
第六章 角色和敌人行为互动脚本制作
第七章 游戏打包、发布和调试
第三章 cocs UI、地图和关卡文本制作
请下载上一章代码:https://download.csdn.net/download/sinat_29014637/17854872?spm=1001.2014.3001.5503。本章节上上一章代码基础上开发
一、UI-设置、equipment和item栏
1.设置tab
原理:通过cc.sys.localstorage来设定参数作为设定值(HTML平台清空缓存会被清理),jsb操作json在h5平台不受支持,所以我们项目暂时使用前者。
1.1在Canva节点右击创建节点-创建UI节点-layout,然后在layout上添加一个botton三个editBox
1.2 添加加载、写入和显示layout的代码
既然是全局的代码,我们放到canvasjs.js上
//1.显示和隐藏setting
showOrHideSetting:function(e){
var setl = cc.find('Canvas').getChildByName('settingLayout');
if(setl){
setl.active = setl.active? false:true;
}
},
//2.显示配置内容
loadSetting:function(e){
var setl = cc.find('Canvas').getChildByName('settingLayout');
var pname = cc.sys.localStorage.getItem('pname');
if(setl && pname){
setl.getChildByName('EditBox1').getComponent(cc.EditBox).string = pname;
setl.getChildByName('EditBox1').getChildByName('LABEL').string = 'pname';
//voice
//graphic
//action
}
var uinode = cc.find('Canvas').getChildByName('UI');
var userinfo = uinode.getChildByName('playerinfo');
if(userinfo){
userinfo.getChildByName('pname').getComponent(cc.Label).string = pname? pname:'notnamed';},
//3.修改配置内容
setSetting:function(e){
var setl = cc.find('Canvas').getChildByName('settingLayout');
var value = setl.getChildByName('EditBox1').getComponent(cc.EditBox).string ;
var keys = setl.getChildByName('EditBox1').getChildByName('LABEL').string;
cc.sys.localStorage.setItem(keys,value);
},
1.3 在场景加载时候加载这个配置内容
onLoad(){
this.loadSetting();//加载setting,显示在右上角头像和三围
}
2.item栏和equipment tab
现在开始做物品和装备栏,上一章我们建立了equipment节点:头身体和四肢+3个技能栏组成和scrollview,因为我们日常都是拖动物品到装备栏,故建议把equipment节点放到scrollview子节点下,方便在同一个js上写触摸拖动、碰撞、碰撞后填入栏位的功能。
2.1加载ITEMS
LOAD和set读写items的代码公用性较强,可以写到canvasjs.js
(1)考虑scrollview导致node层级较多,这里把itemSrollView修改一下,把view节点改为grid,添加layout组件:
(2)添加后在grid节点添加子节点发现都会自动按照网格排列。所以清空grid的子对象,使用代码读取json和localstorage来添加相应的物品。
这里遇到一个问题,cc.sys.loalstorage是异步读取的,所以读取json时候重复读spriteframe图片,会发现读完spriteframe后,前面已经读取完,故只有最后一个json记录才有spritefram,这里先记录下来后面找找原因,知道解决方法的朋友也请留言告诉我一声。
虽然json遇到问题,项目还是要进行,那就替代方案走起:
1)js直接定义一个array变量记录初始的item
const TOOLS = [
{
id:'W1',//唯一值:type+序号
sname:'mainMap',//场景
type:'W',//类型 W-weapon I-ITEMS E-EQUIPMENT S-SKILL技能
name: '工具套装', // 名称
desc: '这是一个工具盒,撬门破解无所不能', // 点击显示介绍
owner:'player',//所在位置(拥有者)
eff:'at',//效果 at=attact hp=+-hp mp=+-mp lp=+-lp值
value:'10',//配合eff,eff的值,支持+-号
rotation:'0',//方向
icon: 'icons/png-0007' // 动态加载路径
},
{
id:'I1',//唯一值:type+序号
sname:'mainMap',//场景
type:'I',//类型 W-weapon I-ITEMS E-EQUIPMENT
name: '放大镜',
desc: '就是个放大镜,啥东西放上去都能变大',
owner:'player',//所在位置(拥有者)
eff:'at',//效果 at=attact hp=+-hp mp=+-mp lp=+-lp值
value:'10',//配合eff,eff的值,支持+-号
rotation:'0',//方向
icon: 'icons/png-0017'
},
{
id:'W2',//唯一值:type+序号
sname:'mainMap',//场景
type:'W',//类型 W-weapon I-ITEMS E-EQUIPMENT
name: '剪刀',
desc: '这是剪刀,当做武器不知道行不行',
owner:'player',//所在位置(拥有者)
eff:'at',//效果 at=attact hp=+-hp mp=+-mp lp=+-lp值
value:'20',//配合eff,eff的值,支持+-号
rotation:'0',//方向
icon: 'icons/png-0031'
},
{
id:'W3',//唯一值:type+序号
sname:'mainMap',//场景
type:'W',//类型 W-weapon I-ITEMS E-EQUIPMENT
name: '卷轴',
desc: '这是卷轴',
owner:'player',//所在位置(拥有者)
eff:'at',//效果 at=attact hp=+-hp mp=+-mp lp=+-lp值
value:'20',//配合eff,eff的值,支持+-号
rotation:'0',//方向
icon: 'icons/卷轴'
},
];
export {TOOLS}; // import {TOOLS} from './array'; //通过这个函数调用js
2)新建一个itemstab.js来编写加载spriteframe动态icon的代码
// update (dt) {},
setSpriteFrame:function(iconurl){
var self = this;
cc.loader.loadRes(iconurl,cc.SpriteFrame,function(err,res){
self.node.getComponent(cc.Sprite).spriteFrame = res;
});
},
3)定义一个物品的prefab方便实例化复制然后切换不同的icon来代码不同物品
a.在grid节点——新建节点——sprite,然后添加一个label
b.给item添加js组件
c.拖动item节点到资源管理器新建的prefab文件夹(任意都行,方便管理新建了prefab文件夹)
这样就完成了预制体的制作,后面通过cc.instance()来不断实例化和复制,重复利用
4)在canvasjs.js中编写代码,要加载icon图片时候,直接调用itemstab.js就可以同步加载,解决异步问题
//items和equipte相关代码
loadItems: function (e, customerData) {
var itemsview = cc.find('Canvas').getChildByName('UI').getChildByName('itemScrollView');
if (!itemsview) { cc.log('找不到itemScrollView'); return; }
//customerData:i类-formal items E类-equipment W类-weapon
//是否有缓存,有则取缓存的档案,没有取json的初始档案
var items = cc.sys.localStorage.getItem('items');
if (!items) {//from json
var url = 'json/main';//resources/json/..
// cc.loader.loadRes(url, cc.RawAsset, function (err, res) {//异步跟下面异步获取spriteframe有冲突
// if (!err) {
// var rs = res.json.items;//json的obj:mapobj items acts
for (var i = 0; i < TOOLS.length; i++) {
if (TOOLS[i].owner == 'player') {
var obj;
obj = cc.instantiate(this.item); //(new cc.Node());//this.floor无效
if (obj) {
obj.name = TOOLS[i].id;//TOOLS[i].name;
obj.angle = - TOOLS[i].rotation;//方向
// obj.addComponent(cc.Sprite);
// obj.parent = itemsview.getChildByName('grid'); //父本 sv-view-content-item
// obj.setPosition(cc.v2(rs[i].posx, rs[i].posy));
// cc.loader.loadRes(rs[i].icon,cc.SpriteFrame,function(err,res){
// obj.getComponent(cc.Sprite).spriteFrame = res;
// });
var itemjs = obj.getComponent('itemstab');
var icons = TOOLS[i].icon;
itemjs.setSpriteFrame(icons);//直接调用item的方法
itemsview.getChildByName('grid').addChild(obj);
}
}
}
// } else { cc.log(err); } //异步 往往会执行后面之后再回调函数
// });
} else {//from localstorage
}
},
setItems: function (e) {
},
最终效果:比较“斋”,目的达到就好,后面再找时间美化下
2.2拖动和排序实现
item拖动可以通过touch_move的方法实现,移动时候鼠标变为图片,停止时候执行排序,排列顺序呢目前是按照grad layout标准方法排列:新的放到最后,旧的不变
onLoad() {
var self = this;
this.initpos;
this.endpos;
this.node.on(cc.Node.EventType.TOUCH_START, function (e) {
this.initpos = e.getLocation;
}.bind(this), this);
this.node.on(cc.Node.EventType.TOUCH_MOVE, function (e) {
var dis = e.getDelta(); // cc.log(dis.x +':'+ dis.y);
if(self.node.parent.parent.name == 'equipment'){return;}
var dy = self.node.position.y + dis.y;
var dx = self.node.position.x + dis.x;
var isv = cc.find('Canvas').getChildByName('UI').getChildByName('itemScrollView');
// cc.log(self.node.parent);//需要添加不等于装备
self.node.parent = isv;//grid 里面是不能随便拖动的,转到别的父本
self.node.setPosition(cc.v2(dx, dy));
}.bind(this), this);
this.node.on(cc.Node.EventType.TOUCH_END, function (e) {
}.bind(this), this);
this.node.on(cc.Node.EventType.TOUCH_CANCEL, function (e) {
// self.node.removeFromParent();//移走
//没有移到其他栏目则回来原来grid
if (self.node.parent == cc.find('Canvas').getChildByName('UI').getChildByName('itemScrollView')) {
self.node.parent = cc.find('Canvas').getChildByName('UI').getChildByName('itemScrollView').getChildByName('grid');
}
}.bind(this), this);
},
2.3 equipment-碰撞实现加入栏位
而考虑交互事件较多、冒泡事件传递较复杂,我们需要在itemstab.js脚本文件来编写items的拖拉筛选等代码
原理剖析:首先我们是拖动item,故应该在每个item启用touch方法;拖动后放到装备栏或者使用按钮,有两种方法实现:a.判断坐标是否落入 b.直接使用碰撞,碰撞后从物品栏去掉,加载到具体装备栏。我选择b资源不用重复加载,换一个副本即可。另外我们需要把装备类item节点命名为E+名称,这样就可以简单判断。
2.3.1为equipment栏添加碰撞组件
2.3.2在itemstab.js添加碰撞检测代码
(1)开启碰撞
onLoad() {
//开启碰撞检测
var collider = cc.director.getCollisionManager();
collider.enabled = true;
// collider.enabledDebugDraw = true; //debug
// collider.enabledDrawBoundingBox = true;
...
检查碰撞组:UI之间还是要碰撞(也可以单独给item分配新的组)
(2)检测碰撞时候改变副本为具体的equipment栏
//碰撞检测
onCollisionEnter:function(other,self){
// cc.log('ot:'+other.node.name);
// cc.log('se:'+self.node.name.substr(0,1));
if(self.node.name.substr(0,1) != 'W' && self.node.name.substr(0,1) != 'S' && self.node.name.substr(0,1) != 'E'){return;}
var i = 0;
switch(other.node.name){//对应equipment节点所有的装备栏
case 'head':i =1;break;
case 'body':i =2;break;
case 'lhand':i =3;break;
case 'rhand':i =4;break;
case 'lfoot':i =5;break;
case 'rfoot':i =6;break;
case 'skill1':i =7;break;
case 'skill2':i =8;break;
case 'skill3':i =9;break;
// case '':break;
// case '':break;
// case '':break;
}
if(i!= 0 && other.node.children.length<1){
self.node.parent = other.node ;
// cc.log(other.node.name);
self.node.setPosition(cc.v2(0,0));
}
},
总结
有点复杂,花了较长时间只做了item栏和装备栏的互动,后面还要做数据运算等,地图和关卡文本放到(二)文章处理吧。
这里提供物品栏制作的文章供参考,非常感谢博主对我们这些菜鸟的指引:
https://blog.csdn.net/La_vie_est_belle/article/details/105147837