还是先po一下效果咯~~
这次作业其实就是:将上次作业在Update()函数一帧帧改位置控制运动,改为类似cocos2d的一个Action方法控制物体自己运动,也就是所谓的面向对象的设计。但其实本质上还是在每一帧的时间里做改动。
课件上面那个设计框架基本上可以plug and play 即插即用,所以就直接套过来用了,只需要在CCActionManager处与上次作业的mainSceneController交互即可
(课件截图)
因此修改后的项目UML类图如下(CCActionManager那里即与上图连接)
由于在上次作业我都是在控制船运动的BoatBehaviour和控制人物运动的PersonStatus里修改位置,所以这次也只需要主要在这两个脚本里修改即可,很方便。
下面说一下与之前作业修改的地方:
1、添加interface接口IAddAction,有两个方法:增加单独动作和组合动作
public interface IAddAction {
void addSingleMoving(GameObject sourceObj, Vector3 target, float speed);
void addCombinedMoving(GameObject sourceObj, Vector3[] target, float[] speed);
}
2、在mainSceneController里实现IAddAction接口方法。但在这之前先把CCActionManager声明为其一个私有成员,并在CCActionManager里真正实现addSingleMoving()、addCombinedMoving()两个方法:
public void addSingleMoving(GameObject sourceObj, Vector3 target, float speed) {
this.runAction(sourceObj, CCMoveToAction.CreateSSAction(target, speed), this);
}
public void addCombinedMoving(GameObject sourceObj, Vector3[] target, float[] speed) {
List<SSAction> acList = new List<SSAction>();
for (int i = 0; i < target.Length; i++) {
acList.Add(CCMoveToAction.CreateSSAction(target[i], speed[i]));
}
CCSequeneActions MoveSeq = CCSequeneActions.CreateSSAction(acList);
this.runAction(sourceObj, MoveSeq, this);
}
而
mainSceneController里实现
IAddAction接口方法仅仅是通过CCActionManager私有成员调用自身的两个方法即可。
3、明显动作结束后会回调CCActionManager里面的SSActionEvent方法。所以需要在此回调函数里面告知mainSceneController动作(船/人)已经完成:
public void SSActionEvent(SSAction source, SSActionEventType eventType = SSActionEventType.Completed, int intParam = 0, string strParam = null, object objParam = null) {
if (source.gameObject.name.Equals("Boat")) { //船完成动作
scene.boatReachBank();
}
else { //人完成动作
scene.personFinishMoving();
}
}
4、添加动作的基本框架大概就做好了,只需要在控制船和人的脚本里调用即可
5、BoatBehaviour脚本
(1)之前是在此脚本的Update()方法里一帧帧的改位置,这次去掉
(2)之前是通过GenGameObjects调用BoatBehaviour的setBoatMove方法触发船移动。因此只需修改setBoatMove方法,把原来 直接更改位置变成:
addAction.addSingleMoving(this.gameObject, LOCATION_SET.boat_right_LOC, BOAT_SPEED);
6、PersonStatus脚本:
在这里由于人要上下船,所以移动会有两次,如先向上再向右。此时只需找到中间转折点的位置,将两个动作作为序列动作即可。以下为分解动作并添加的方法:
void divideThePosAndSetMove(Vector3 target, bool isGetOn) {
Vector3[] dividedPos = new Vector3[2];
float[] speedSet = new float[2];
if (isGetOn) {
dividedPos[0] = new Vector3(target.x, this.transform.position.y, 0);
dividedPos[1] = target;
}
else {
dividedPos[0] = new Vector3(this.transform.position.x, target.y, 0);
dividedPos[1] = target;
}
speedSet[0] = PERSON_SPEED;
speedSet[1] = PERSON_SPEED;
addAction.addCombinedMoving(this.gameObject, dividedPos, speedSet);
gameStatus.setObjMoving(MOVEMENT.Moving);
}
7、好了。分离动作的步骤应该就做完了。还有就是要设置船移动和人移动不能人机交互。
8、在上一次作业我已经在船的脚本里面设置了一个isMoving的私有变量来判断了。但是这次还有人的移动,在船/人两个脚本里面都设置这样的私有变量就有点累赘了,所以直接在场景控制脚本mainSceneController里设置一个公用的isGameObjectMoving私有变量。同时设置修改的public方法setObjMoving()。在船移动和人移动的开始时候调用此方法,说明正在有gameObjet移动,而此时其他的动作在启动前都会根据IQueryGameStatus 查询当前是否有其他物体在运动,如有即自身动作无效。
public void setObjMoving(bool isMoving) {
isGameObjectMoving = isMoving;
}
9、上面第3点也已经提到了,CCActionManager里面有个回调方法SSActionEvent,即每当有动作结束的时候会调用。所以只需要在这里调用mainSceneController的方法,修改isGameObjectMoving的值即可。之后又可以允许动作产生了。
public void boatReachBank() {
myGenGameObjects.boatReachBank();
isGameObjectMoving = MOVEMENT.NotMoving;
}
public void personFinishMoving() {
Debug.Log("person finish moving");
isGameObjectMoving = MOVEMENT.NotMoving;
}
10、这样就差不多了~这次作业比较简单就不放代码啦