背景:一个人物模型Actor与一张地图map,在地图上人物随意移动,比如能从A点到B点,或A点到B点过程中用户点击C点,那么改变移动方向到C点,在移动结束后执行其它人物动作Action
路径移动
首先我们能联想到的是cc.moveBy或cc.moveTo实现一格的移动,通过给出的路径path[ point1 , point2, ..., B]到达B点。
1. 生成路径path: generatePath(A, B, map?)(函数实现略)
2. 添加路径并移动: Actor.move(path)
move(
path){
if(
path ==
null ||
path ==
undefined ||
path.
length ==
0 )
return;
else{
this
.
path
=
path
;
this.
_move(
path);
}
}
3. 一格移动: Actor._move(point)
_move(
path){
// path = [ point1 , point2, ..., B]
if(
this.
moveActions!=
null && !
this.
moveActions.
isDone()) {
// 上个动作没有完成,记录下path等之后完成
this.
path =
path;
return;
}
else{
this.
moveActions =
new
cc.
ActionInterval();
let
nextSite =
this.
path.
splice(
0,
1)[
0];
if(
nextSite){
// 换算成网格移动所需要的x, y
let
x = (
nextSite.
x -
this.
actor.
x) *
this.
node.
width,
y = - (
nextSite.
y -
this.
actor.
y) *
this.
node.
height;
// cc.moveBy移动一格,通过cc.sequence与cc.callFunc组合,实现移动一格结束后的回调
this.
moveActions =
cc.
sequence(
cc.
moveBy(
MOVE_SPEED,
x,
y),
this.
moveActions);
this.
moveActions =
cc.
sequence(
this.
moveActions,
cc.
callFunc(
this.
_moveFinished,
this, nextSite));
this.
node.
runAction(
this.
moveActions);
}
}
}
_moveFinished(
targetNode, nextSite){
//移动一格,更新自己的位置
this.
actor.
x =
nextSite.
x;
this.
actor.
y =
nextSite.
y;
//目标路径没有移动完,继续移动
if(
this.
path &&
this.
path.
length){
this.
_move(
this.
path);
}
else{
cc.
log(
'Promise: move is done');
}
}
路径1:用户点击B点,生成path(A->B),调用Actor.move(path),_move移动到B点结束
路径2:用户点击B点,生成path(A->B),调用Actor.move(path(A->B)),_move向着B点移动;中途用户再次点击C点,生成当前位置到C点的路径path(_point->C),调用Actor.move(path(_point->C)),_move改变方向向着C点移动。
添加Promise
关于在人物移动结束后还要执行的Action动作,则需要为整个移动添加一个promise了:
move(
path){
let
promise =
new
Promise((
resolve,
reject)
=>{
if(
path ==
null ||
path ==
undefined ||
path.
length ==
0 )
reject(
'path is null');
else{
this.
path =
path;
this.
_move(
path,
resolve);
}
});
return
promise;
}
_move(
path,
resolve){
if(
this.
moveActions!=
null && !
this.
moveActions.
isDone()) {
// 上个动作没有完成,记录下path等之后完成
this
.
path
=
path
;
return;
}
else{
this.
moveActions =
new
cc.
ActionInterval();
let
nextSite =
this.
path.
splice(
0,
1)[
0];
if(
nextSite){
let
x = (
nextSite.
x -
this.
actor.
x) *
this.
node.
width,
y = - (
nextSite.
y -
this.
actor.
y) *
this.
node.
height;
// cc.moveBy移动一格,通过cc.sequence与cc.callFunc组合,实现移动一格结束后的回调
this.
moveActions =
cc.
sequence(
cc.
moveBy(
MOVE_SPEED,
x,
y),
this.
moveActions);
// cc.callFunc回调里加入resolve作为
参数
this.
moveActions =
cc.
sequence(
this.
moveActions,
cc.
callFunc(
this.
_moveFinished,
this, {
nextSite,
resolve}));
this.
node.
runAction(
this.
moveActions);
}
}
}
_moveFinished(
targetNode, {
nextSite,
resolve}){
this.
actor.
x =
nextSite.
x;
this.
actor.
y =
nextSite.
y;
if(
this.
path &&
this.
path.
length){
this.
_move(
this.
path,
resolve);
}
else{
cc.
log(
'Promise: move is done');
resolve(
'');
}
}
以上加入了promise的丑陋的代码看似完成了完成动作后的回调,你只需要
Actor.move(path).then(()=>{
//这里写下一个动作
})
就能在move结束后执行其它相关操作了。
但但但但但但 是:
对于路径二,在用户第二次点击改变path的同时,_move方法会执行第一个if判断:
_move(
path,
resolve){
if(
this.
moveActions!=
null && !
this.
moveActions.
isDone()) {
// 上个动作没有完成,记录下path等之后完成
this
.
path
=
path
;
return;
}
也就是说,路径二的promise几乎永远不会被resolve,而
cc.callFunc(this._moveFinished, this, {nextSite, resolve})
中的resolve还是从A->B时的promise的resolve,因为它被闭包了。
调整代码,加入this.movePromise记录当前promise,使resolve从闭包中脱离:
move(
path){
let
promise =
new
Promise((
resolve,
reject)
=>{
if(
this.
movePromise){
// 上个未完成动作会被直接reject
this.
movePromise.
reject(
'');
cc.
log(
'Move Promise reject');
}
this.
movePromise = {
resolve,
reject};
if(
path ==
null ||
path ==
undefined ||
path.
length ==
0 )
reject(
'path is null');
else{
this
.
path
=
path
;
this.
_move(
path);
}
});
return
promise;
}
_move(
path){
if(
this.
moveActions!=
null && !
this.
moveActions.
isDone()) {
this
.
path
=
path
;
return;
}
else{
this.
moveActions =
new
cc.
ActionInterval();
let
nextSite = this.
path.
splice(
0,
1)[
0];
if(
nextSite){
let
x = (
nextSite.
x -
this.
actor.
x) *
this.
node.
width,
y = - (
nextSite.
y -
this.
actor.
y) *
this.
node.
height;
this.
moveActions =
cc.
sequence(
cc.
moveBy(
MOVE_SPEED,
x,
y),
this.
moveActions);
this.
moveActions =
cc.
sequence(
this.
moveActions,
cc.
callFunc(
this.
_moveFinished,
this, {
nextSite}));
this.
node.
runAction(
this.
moveActions);
}
}
}
_moveFinished(
targetNode, {
nextSite}){
this.
actor.
x =
nextSite.
x;
this.
actor.
y =
nextSite.
y;
if(
this.
path &&
this.
path.
length){
this.
_move(
this.
path);
}
else{
cc.
log(
'Promise: move is done');
this.
movePromise.
resolve(
'');
this.
movePromise =
null;
}
}
这下就能开开心心的使用move了
Actor.move(path).then(()=>{
//这里写下一个动作
})