本教程主要通過搭建一個橫版搖桿八方向移動的實例,讓大家如何用Cocos2dx-Js來做一款
游戲,從基礎了解Cocos2dx-Js的基本實現原理,從創建工程,到各個知識點的梳理。
教程分為上下兩講:
上講有2個小節:
1,工程的創建;
2,Cocos2dx-Js目錄及Cocos2dx運行原理;
下講有2個小節:
1,Cocos2dx-Js的事件處理機制;
2,搖桿的、八方向、精靈移動的實現;
Js環境搭載傳送門:
輕松搭建完后,開始用JS寫一個橫版搖桿動作游戲的Demo,聽起來貌似很高大上~~。
首先要做好幾個准備:
1,角色精靈,我准備了一個骨骼動畫精靈1個,cocosstiduo2.0.6制作的;
2,地圖,也是用cocosstiduo2.0.6制作,生成出MainScene.csb 文件;

3,搖桿的PNG素材;

下面開始創建一個新的工程GoFighting,創建主場景MainLayer.js文件;
MainLayer繼承BaseLayer.js,BaseLayer中處理這個層基本的頁面處理,包括彈出的新層的遮罩處理;
BaseLayer.js:
1 var BaseLayer=cc.Layer.extend({ 2 _bgFrame:null, 3 _notShowAnimation:null, 4 _directorSteps:null, 5 _showAnied:false, 6 init:function(notShowAnimation){ 7 var bret=false; 8 if(this._super()){ 9 //不可刪除
10 var bgFrame = cc.LayerColor(cc.color(0,0,0,200)); 11 this.addChild(bgFrame); 12 this._bgFrame=bgFrame; 13 this._notShowAnimation=notShowAnimation; 14 this.setAnchorPoint(cc.p(0.5,0.5)); 15 this.ignoreAnchorPointForPosition(false); 16 if(!this._notShowAnimation){ 17 this.setScale(0.8); 18 } 19 this.setContentSize(winSize); 20 this.setPosition(cc.p(winSize.width/2,winSize.height/2)); 21
22 cc.eventManager.addListener({ 23 event: cc.EventListener.TOUCH_ONE_BY_ONE, 24 swallowTouches: true, 25 //onTouchMoved: this.onTouchMoved,
26 onTouchBegan: function(){return true;} 27 }, this); 28
29 bret=true; 30 } 31 return bret; 32 }, 33 setBgColor:function(color){ 34 this._bgFrame.setColor(color); 35 }, 36
37 onEnter:function(){ 38 this._super(); 39 if(!this._notShowAnimation&&!this._showAnied){ 40 var sl=cc.EaseIn.create(cc.ScaleTo.create(0.15,1.1),2); 41 var sl2=cc.ScaleTo.create(0.15,1); 42 var seq=cc.Sequence.create(sl,sl2); 43 this.runAction(seq); 44 this._showAnied=true; 45 } 46 }, 47
48 onExit:function(){ 49 this._super(); 50 MemoryManager.getInstance().releaseMeoryFromOther(); 51 } 52 }); 53
54 BaseLayer.OpenActionFs=function(obj){ 55 obj.setScale(0.8); 56 if(obj!=null){ 57 var sl=cc.EaseIn.create(cc.ScaleTo.create(0.15,1.1),2); 58 var sl2=cc.ScaleTo.create(0.15,1); 59 var seq=cc.Sequence.create(sl,sl2); 60 obj.runAction(seq); 61 } 62 };
首先我們加載主場景必須得背景圖片,而主場景背景圖片由cocosstiduo2.0.6制作,如何綁定呢?
在3.2引擎終目前還不支持直接使用widgetFromBinaryFile方法加載CSB,那么換成另外一種加載創建Node的方式:
ccs.csLoader.createNode(res.MainScene_CSB);
使用該方法需要自己去添加全路徑
/* cocostidio制作的CSB文件加載,注: 在3.2引擎終目前還不支持直接使用widgetFromBinaryFile方法加載CSB */
var baseroot = ccs.csLoader.createNode(res.MainScene_CSB); baseroot.setAnchorPoint(cc.p(0.5,0.5)); baseroot.setPosition(this.getContentSize().width/2,this.getContentSize().height/2); this.baseroot=baseroot; this.addChild(baseroot,1,9001); BaseLayer.OpenActionFs(baseroot);
然后Run看一下效果:

然后繼續加載角色的骨骼動畫
//角色骨骼動畫加載
var charname = "Char_014_1"; var nowcharurl = resRole+charname+".ExportJson"; if(jsb.fileUtils.isFileExist(nowcharurl)==true) { cc.log("nowcharurl =" + nowcharurl); ccs.ArmatureDataManager.getInstance().addArmatureFileInfo(nowcharurl); var hero = ccs.Armature.create(charname); this._hero_donghua = hero; hero.setPosition(cc.p(330, 260)); hero.getAnimation().play("stand"); hero.getAnimation().setMovementEventCallFunc(this.overStand, this); baseroot.addChild(hero, 3,99999); }
角色hero有回調,如跑動后停下來的回調:
//移動完后回調
overStand:function() { if(this._hero_donghua.getAnimation().getCurrentMovementID()=="") { this._hero_donghua.getAnimation().play("stand"); } },
單單一個角色植入場景是否顯得邏輯太單調,我們可以拖動這個精靈豈不更好,加一個簡單的事件,讓精靈活一點吧!!
//主角監聽
var listener_Role = cc.EventListener.create({ event: cc.EventListener.TOUCH_ONE_BY_ONE, swallowTouches: true, onTouchBegan: function (touch, event) { var target = event.getCurrentTarget(); var locationInNode = target.convertToNodeSpace(touch.getLocation()); var s = target.getContentSize(); var rect = cc.rect(0, 0, s.width, s.height); if (cc.rectContainsPoint(rect, locationInNode)) { cc.log("sprite began... x = " + locationInNode.x + ", y = " + locationInNode.y); target.setOpacity(180); target.getAnimation().play("move"); return true; } return false; }, onTouchMoved: function (touch, event) { var target = event.getCurrentTarget(); var delta = touch.getDelta(); target.x += delta.x; target.y += delta.y; }, onTouchEnded: function (touch, event) { var target = event.getCurrentTarget(); cc.log("sprite onTouchesEnded.. "); target.setOpacity(255); target.getAnimation().play("stand"); } });
在ctor構造中添加角色事件的注冊方法:
//人物
cc.eventManager.addListener(listener_Role, this._hero_donghua);
OK,我們再Run起來看看效果:

還可以拖動的呢!
然后,我們繼續實現搖桿模式:
搖桿與事件有關,JS中搖桿須繼承cc.EventListener去創建事件,事件類型cc.EventListener.TOUCH_ONE_BY_ONE(單點觸摸方式);
看代碼:
//搖桿監聽
var listener_YaoGan = cc.EventListener.create({ event: cc.EventListener.TOUCH_ONE_BY_ONE, swallowTouches: true, onTouchBegan: function (touch, event) { var target = event.getCurrentTarget(); var locationInNode = target.convertToNodeSpace(touch.getLocation()); //創建搖桿
this.sprite_yaogan = new cc.Sprite(res.YaoGan_png); this.sprite_yaogan.attr({ x: locationInNode.x, y: locationInNode.y }); target.addChild(this.sprite_yaogan, 4,90099); //創建搖桿點
this.sprite_yaogan_dian = new cc.Sprite(res.YaoGan_Dian_png); this.sprite_yaogan_dian.attr({ x: locationInNode.x, y: locationInNode.y }); target.addChild(this.sprite_yaogan_dian, 4,90999); return true; }, onTouchMoved: function (touch, event) { //搖桿點
var target = event.getCurrentTarget(); var sp_dian = target.getChildByTag(90999); var sp_yaoganbd = target.getChildByTag(90099); var sp_hero = target.getChildByTag(99999); //搖起來
if(sp_dian!=null&&sp_yaoganbd!=null) { var p_dian = sp_yaoganbd.getPosition(); var bd_width =sp_yaoganbd.getContentSize().width*0.5; cc.log("bd_width>>=="+bd_width); var point = touch.getLocation(); var p_rad = this.getRad(p_dian,point); cc.log("p_rad>>=="+p_rad); //計算兩個圓心之間距離
var juli =Math.sqrt(Math.pow((p_dian.x - point.x),2) + Math.pow((p_dian.y - point.y),2)); //距離不超過半徑
if(juli>=bd_width) { cc.log("go111>>>"); sp_dian.setPosition(cc.pAdd(this.getAngelePosition(bd_width,p_rad),cc.p(p_dian.x,p_dian.y))); } else { cc.log("go2222>>>"); var delta = touch.getDelta(); sp_dian.x += delta.x; sp_dian.y += delta.y; } // //判斷方向---四方向 // if(p_rad>=-PI/4&&p_rad<PI/4) // { // R_Direction="right"; // } // else if(p_rad>=PI/4&&p_rad<3*PI/4) // { // R_Direction="up"; // } // else if((p_rad>=3*PI/4&&p_rad<=PI)||(p_rad>=-PI&&p_rad<-3*PI/4)) // { // R_Direction="left"; // } // else if(p_rad>=-3*PI/4&&p_rad<-PI/4) // { // R_Direction="down"; // }
//判斷方向---八方向
var move_x = parseInt(p_dian.x -point.x); var move_y = parseInt(p_dian.y -point.y); if(move_x>=10&&move_y<=-10) { //左上
R_Direction = "left_up"; } else if(move_x>=10&&move_y>=10) { //左下
R_Direction = "left_down"; } else if(move_x<=-10&&move_y<=-10) { //右上
R_Direction = "rigth_up"; } else if(move_x<=-10&&move_y>=10) { //右下
R_Direction = "rigth_down"; } else if(move_x>-10&&move_x<10&&move_y>0) { //下
R_Direction = "down"; } else if(move_x>-10&&move_x<10&&move_y<0) { //上
R_Direction = "up"; } else if(move_x>0&&move_y>-10&&move_y<10) { //左
R_Direction = "left"; } else if(move_x<0&&move_y>-10&&move_y<10) { //右
R_Direction = "right"; } R_Action="move"; cc.log("R_Direction>>>"+R_Direction); } }, //獲取半徑坐標
getAngelePosition:function(r,angle){ return cc.p(r*Math.cos(angle),r*Math.sin(angle)); }, //判斷兩點之間夾角
getRad:function(pos1,pos2) { var px1 = pos1.x; var py1 = pos1.y; var px2 = pos2.x; var py2 = pos2.y; //得到兩點x的距離
var x = px2 - px1; //得到兩點y的距離
var y = py1 - py2; //算出斜邊長度
var xie = Math.sqrt(Math.pow(x,2) + Math.pow(y,2)); //得到這個角度的余弦值(通過三角函數中的店里:角度余弦值=斜邊/斜邊)
var cosAngle = x / xie; //通過反余弦定理獲取到期角度的弧度
var rad = Math.acos(cosAngle); //注意:當觸屏的位置Y坐標<搖桿的Y坐標,我們要去反值-0~-180
if (py2 < py1) { rad = -rad; } return rad; }, onTouchEnded: function (touch, event) { var target = event.getCurrentTarget(); if(target.getChildByTag(90099)!=null) { target.removeChildByTag(90099); } if(target.getChildByTag(90999)!=null) { target.removeChildByTag(90999); } R_Action="stand"; var sp_hero = target.getChildByTag(99999); sp_hero.getAnimation().play("stand"); } });
在上面這個Js類中,包含了幾個方法如,兩點之間夾角的計算公式和最大半徑坐標的計算公式;
因為我們需要在搖桿和搖桿點上面去做坐標處理,計算出夾角來對角色進行坐標位移操作,達到我們所需要的效果
跑起來的搖桿效果如下:

搖桿可以活動了,並且不能超過底下的背景半徑,達到了我們需要的效果,下面就繼續實現搖桿操控精靈移動的功能
可以繼續在onTouchMoved: function (touch, event)事件終寫方法獲取一些判定參數:
//方向
var R_Direction = ""; //動作
var R_Action = "stand"; //移動速度
var R_speed = 4;
繼續看listener_YaoGan類中的方向判斷,我寫了2種角色移動方法:
1,根據PI=3.1415 來計算 ,做了4方向的標識判斷
2,根據坐標差值來計算,做了8方向的標識判斷
OK,兩種方法都可以行,可以自己拓展。
有了標識我們需要啟動一個定時器來執行人物的操作
下面是定時器部分的代碼:
//更新狀態
runGame:function(){ if(R_Action=="move") { if(this._hero_donghua!=null) { if(this._hero_donghua.getAnimation().getCurrentMovementID()!="move") { this._hero_donghua.getAnimation().play("move"); } var p_hero_old = this._hero_donghua.getPosition(); if(R_Direction=="right") { this._hero_donghua.setScaleX(-1); this._hero_donghua.setPosition(cc.p(p_hero_old.x+R_speed,p_hero_old.y)); } else if(R_Direction=="up") { this._hero_donghua.setPosition(cc.p(p_hero_old.x,p_hero_old.y+R_speed)); } else if(R_Direction=="left") { this._hero_donghua.setScaleX(1); this._hero_donghua.setPosition(cc.p(p_hero_old.x-R_speed,p_hero_old.y)); } else if(R_Direction=="down") { this._hero_donghua.setPosition(cc.p(p_hero_old.x,p_hero_old.y-R_speed)); } else if(R_Direction=="left_up") { this._hero_donghua.setScaleX(1); this._hero_donghua.setPosition(cc.p(p_hero_old.x-R_speed,p_hero_old.y+R_speed)); } else if(R_Direction=="left_down") { this._hero_donghua.setScaleX(1); this._hero_donghua.setPosition(cc.p(p_hero_old.x-R_speed,p_hero_old.y-R_speed)); } else if(R_Direction=="rigth_up") { this._hero_donghua.setScaleX(-1); this._hero_donghua.setPosition(cc.p(p_hero_old.x+R_speed,p_hero_old.y+R_speed)); } else if(R_Direction=="rigth_down") { this._hero_donghua.setScaleX(-1); this._hero_donghua.setPosition(cc.p(p_hero_old.x+R_speed,p_hero_old.y-R_speed)); } } } }
OK,人物可以根據搖桿八方向的跑動起來了,我們Run起來看看效果,應該很贊!

嗯,該Demo就開發完畢了,下面是整個DEMO的下載地址,希望能大家對大家起到幫助;
cocos2d-x 3.2 - JS -橫版搖桿八方向移動DEMO下載地址
自己創建一個新的工程,將ZIP解壓文件拷貝到工程根目錄就可以Run起來,替換main.js和project.json;

