欢迎访问移动开发之家(rcyd.net),关注移动开发教程。移动开发之家  移动开发问答|  每日更新
页面位置 : > > 内容正文

使用Promise/Deffered模式优化coco2d html5中的游戏动画!

来源: 开发者 投稿于  被查看 39001 次 评论:185

使用Promise/Deffered模式优化coco2d html5中的游戏动画!


问题:


在使用cocos2d html编写一系列的战斗动画时经常遇到一个精灵动作完成时需要继续播放另一个精灵动作 如下:


//动作1
actionSetp1: function() {
        ...
var move = cc.MoveTo.create(1, cc.p(100,100));
  //移动完后执行,actionStep2函数
var call = cc.CallFunc.create(this.onSetp2, this); 
var seq = cc.Sequence.create([move, call]);
this._sprite1.runAction(seq );
}


//动作2actionSetp1:
function() {
....
var scale= cc.ScaleTo.create(1, 1.5);
//移动完后执行,actionStep3函数
var call = cc.CallFunc.create(this.onSetp3, this); 
var seq = cc.Sequence.create([scale, call]); 
this._sprite2.runAction(seq );
}


//动作3
actionSetp3: function() {
....
//没有后继动作了,没有用cc.CallFunc
var move= cc.MoveTo.create(1, cc.p(100,100));
this._sprite.runAction(seq );
}






使用cc.CallFunc可以很好的解决这个问题. 但是当动作序列比较多超过7个后,感觉就有些力不从心了,
每个动作函数需要知道自己接下来的动作,无疑增加了代码之间的耦合度.


解决方法:
这两天周未正好看了一下《深入浅出 node.js》一书中讲到在node中解决异步编程的问题使用Promise/Deffered模式解决异步函数深度嵌套的问题.
一下子就联想到自己在cocos2d html中游戏动画的问题. 于是将代码使用Deffer重构一下(下面代码使用了q.js 库 使用 npm install q 安装 )效果不错:


playAction: function() {

//这里需要将当前this对象传入
//动作按actionSetp1, actionSetp2, actionSetp3 顺序执行
this.actionSetp1(this)
.then(this.actionSetp2)
.then(this.actionSetp3);
}


//动作1
actionSetp1: function(self) { 
...
//使用q.js创建defer对象
var defer = Q.defer();
var move = cc.MoveTo.create(1, cc.p(100,100));
var call = cc.CallFunc.create(function() {
//执行defer.resolve()函数, 表示当前动作已经完成
//不需要知道下一个动作函数是什么
defer.resolve(self); 
}, self); 

var seq = cc.Sequence.create([move, call]);
self._sprite1.runAction(seq ); 
return defer .promise; //这里返回promise, 用于形成promise.then的调用链}

//动作2
actionSetp1: function(self) {
....
var defer = Q.defer(); //创建defervar 
var scale= cc.ScaleTo.create(1, 1.5); 
var call = cc.CallFunc.create(function() {
defer.resolve(self); 
}, self);
var seq = cc.Sequence.create([scale, call]);
self._sprite2.runAction(seq );

//这里返回promise, 用于形成promise.then的调用链
return defer .promise; 
}


//动作3
actionSetp3: function(self) {
....
//同上
var defer = Q.defer();            
var move= cc.MoveTo.create(1, cc.p(100,100));  
  var call = cc.CallFunc.create(function() {
defer.resolve(self);                    
}, self); 
    self._sprite.runAction(seq );

//这里返回promise, 用于形成promise.then的调用链
return defer .promise;
}






上面代码运行起来和之前版本完全一样, 咋一看代码还多一些. 但是后面这个版本中的每一个动作函数不需要关心动画链,
只关注自己需要完成的动作.


我们复制两行动作, 动作链如下:
  this.actionSetp1(this)                    
       .then(this.actionSetp2)          
  .then(this.actionSetp3);  //复制
  .then(this.actionSetp2);  //复制
       .then(this.actionSetp3);


我们修改一下,添加新动作, 动作链如下:
  this.actionSetp1(this)                    
       .then(this.actionSetp2)          
  .then(this.actionSetp3); 
  .then(this.actionSetp4);  //新增
       .then(this.actionSetp5);  //新增






相信大家已经明白其中的好处了吧!


---------------------------------------------------------------
注意:
1. 在cocos2d html中使用q.js 是没有问题的, 但在jsb中使用q.js时会提示 setTimeout没有定义, 我是这样解决的:
mySetTimeout = function(callback, interval) {
    var director = cc.Director.getInstance();
    director.getScheduler().scheduleCallbackForTarget(director, callback, 0, 1, interval, false);
};


var setTimeout = setTimeout || mySetTimeout ;




这里是使用cocos2d中的schedule来模拟的setTimeout函数


2. 还有在 this.actionSetp1(this) .then(...).then(...) 由then调用链回调的函数this上下文并不是你当前类对象
所以这里每一个 defer.resolve(self); 使用self将当前类对象向下传递.

相关频道:

用户评论