【目标】:给扫雷游戏增加一个结果展示层,当取胜或失败时展示结果,并让用户选择重来或是退出
【参考】:
1、《Cocos2D - X 权威指南》
2、《Cocos2d-x学习(六):cocos2d-x中的模态对话框简单实现》: http://blog.youkuaiyun.com/onerain88/article/details/7608496
一、基于抽象的架构再调整
场景 | 场景层次 | 场景元素 | ||
游戏场景 | —— | 雷区游戏层 | —— | 雷区 |
| | —— | 计时 | ||
—— | 剩余雷数 | |||
| | —— | 菜单 | ||
| | —— | 游戏结果层 | —— | 游戏结果【本版本实现】 |
—— | 重启按钮【本版本实现】 |
这次需要实现的是 游戏结果层,类名取为 GameOverLayer(不是特别合适,因为GameOver一般是失败时用的)。
下面要考虑一下功能的分配。
由于在扫雷游戏进行的时候,触摸事件是在 雷区游戏层 MineArea 中处理的,逻辑运算也是在其中实现,那么最先知道游戏胜负结果的,当然就是 MineArea 了。但是从逻辑上讲,当触发胜负手的时候,处理者就不应当是游戏层了,而是整个游戏的管理者,在我们这里,由于只有一个场景,所以把这个任务交给了 游戏场景 MineSweepScene ,如果有多个场景的话,则应该考虑交给更高级的管理者 AppDelegate。
当游戏结束时,场景类将游戏结果层显示出来,这时会显示 retry 或者是 quit 选项给用户选择。用户选择的结果在游戏结果层获取,同样应该上交 场景类。
由于有了层级之间的交互,所以交互者双方应该互相持有引用,以便呼叫。这里处理的策略是每个layer重载一个create函数,要求传入场景类引用,例如对于原来的游戏层 MineArea :
MineArea * MineArea::create(MineSweepScene * parent) {
MineArea * ret = MineArea::create();
ret->mParent = parent;
return ret;
}
这样就解决了层级间的交互问题。
二、游戏结果层的显示
由于我对这个层的设想比较简单,所以就使用类似于模态对话框来做就好。所谓模态对话框,就是出现的时候,你只能对这个对话框进行操作, 不能点击其背景的原场景。
借鉴参考的那个资料,我这里也使用 CCLayerColor 来做,其实就是在背景蒙一层半透明的灰色。然后在上面加一个提示的HINT标示胜利或失败,再加两个按钮 retry 和 quit
bool GameOverLayer::init() {
CCLayerColor::initWithColor(ccc4(0, 0, 0, 125));
CCSize size = CCDirector::sharedDirector()->getWinSize();
mHint = CCLabelTTF::create("", "", 64);
mHint->setPosition(ccp(size.width/2, size.height/2));
addChild(mHint, 3);
//menu按钮 继续或者退出
CCMenuItemFont * retryMenu = CCMenuItemFont::create("Retry", this, menu_selector(GameOverLayer::onRetryClicked));
retryMenu->setPosition(size.width/2 - 100, size.height/2 - 50);
CCMenuItemFont * quitMenu = CCMenuItemFont::create("Quit", this, menu_selector(GameOverLayer::onQuitClicked));
quitMenu->setPosition(size.width/2 + 100, size.height/2 - 50);
//menu 要放在最上面
pMenu = CCMenu::create(retryMenu, quitMenu, NULL);
pMenu->setPosition(CCPointZero);
addChild(pMenu, 4);
setVisible(false);
return true;
}
三、重启游戏
下面来实现那两个菜单按钮(retry 和 quit),其中quit很容易,直接调用:
CCDirector::sharedDirector()->end();
而要重启游戏,则稍微麻烦一点点。
我这里采用的方式是重新创建一个扫雷场景,然后进行场景切换,使用默认的切换方式,是没有动画的。其实不这样做也可以,重新刷一遍布局也可以,我估计这样效率应该更高,但是一来比较麻烦,二是并不通用,如果以后游戏大了,需要刷新的东西就会很多,不如直接进行这样的场景重刷:
void MineSweepScene::restartGame() {
log("restart");
CCDirector::sharedDirector()->purgeCachedData();
CCDirector::sharedDirector()->replaceScene(MineSweepScene::create());
}
这里是照着权威指南上来的,适用于所有简单的场景切换,总共三个步骤:1、清cache;2、创建scene;3、replaceScene
到此为止,简单的游戏结果层就已经添加上去了。