本篇文章给大家谈谈火云开发课堂-《使用Cocos2d-x开发3D游戏》系列第二十五节:3D项目优化方案,同时本文还将给你拓展Cocos2d-x3.2大富翁游戏项目开发-第二十九部分游戏配音、Cocos
本篇文章给大家谈谈火云开发课堂 - 《使用Cocos2d-x 开发3D游戏》系列 第二十五节: 3D项目优化方案,同时本文还将给你拓展Cocos2d-x 3.2 大富翁游戏项目开发-第二十九部分 游戏配音、Cocos2d-x 3.2 大富翁游戏项目开发-第二十五部分 大富翁股市、Cocos2d-x 3.2 大富翁游戏项目开发-第二十八部分 游戏保存和载入存档游戏、Cocos2d-x 3.2 大富翁游戏项目开发-第二十部分 螃蟹挡路(code)等相关知识,希望对各位有所帮助,不要忘了收藏本站喔。
本文目录一览:- 火云开发课堂 - 《使用Cocos2d-x 开发3D游戏》系列 第二十五节: 3D项目优化方案
- Cocos2d-x 3.2 大富翁游戏项目开发-第二十九部分 游戏配音
- Cocos2d-x 3.2 大富翁游戏项目开发-第二十五部分 大富翁股市
- Cocos2d-x 3.2 大富翁游戏项目开发-第二十八部分 游戏保存和载入存档游戏
- Cocos2d-x 3.2 大富翁游戏项目开发-第二十部分 螃蟹挡路(code)
火云开发课堂 - 《使用Cocos2d-x 开发3D游戏》系列 第二十五节: 3D项目优化方案
《使用Cocos2d-x 开发3D游戏》系列在线课程
第二十五节:3D项目优化方案
视频地址:http://edu.csdn.net/course/detail/1330/20825?auto_start=1
交流论坛:http://www.firestonegames.com/bbs/forum.php
Cocos2d-x 3.2 大富翁游戏项目开发-第二十九部分 游戏配音
我从大富翁里提取出来里面的wav音效文件,放到我们的游戏中以增加趣味性,仅供学习研究之用
1、修改AppDelegate.cpp文件
// This function will be called when the app is inactive. When comes a phone call,it's be invoked too void AppDelegate::applicationDidEnterBackground() { Director::getInstance()->stopAnimation(); // if you use SimpleAudioEngine,it must be pause //后台暂停 SimpleAudioEngine::getInstance()->pauseBackgroundMusic(); } // this function will be called when the app is active again void AppDelegate::applicationWillEnterForeground() { Director::getInstance()->startAnimation(); // if you use SimpleAudioEngine,it must resume here //恢复播放 SimpleAudioEngine::getInstance()->resumeBackgroundMusic(); }
2、在resources 目录下新建sound文件夹,存放游戏声音文件
角色的声音文件定义到ConstUtil.h文件中,大体如下:
#define P1_DEYIDEYITIAN "sound/byelottery.wav"//拜拜 祝您中奖 #define P1_need1000 "sound/need1000.wav"//只要1000元 #define P1_select_lottery "sound/select_lottery.wav"//请圈选你要购买的彩票 #define P1_meirendejiang "sound/meirendejiang.wav"//sorry 本月份没有人得奖 #define P1_xiwangshini "sound/xiwangshini.wav"//希望下次得奖者就是您 #define P1_Speaking_00181 "sound/Speaking_00181.wav"//投资获利 #define P1_Speaking_00182 "sound/Speaking_00182.wav"//投资失败
角色相关声音大体依据如下内容进行分类定义:
//交过路费声音
//抢夺别人地块
//房屋被抢夺
//房屋被摧毁
//摧毁别人房屋
//螃蟹伤人
//看到别人住院
//收取过路费
//升级房子
//不交过路费
//买地
//捡到珍珠
//对方被罚收税
例如:角色1的文件定义
//交过路费声音 #define P1_Speaking_00435 "sound/Speaking_00435.wav"//oh 哈利路亚 #define P1_Speaking_00461 "sound/Speaking_00461.wav"//oh 我的血汗钱 #define P1_Speaking_00475 "sound/Speaking_00475.wav"//算了算了 老子有的是钱 #define P1_Speaking_01060 "sound/Speaking_01060.wav"//老本都快没了 #define P1_Speaking_001062 "sound/Speaking_001062.wav"//拿去了不用找了 //抢夺别人地块 #define P1_Speaking_00429 "sound/Speaking_00429.wav"//让我把他据为己有 //房屋被抢夺 #define P1_Speaking_00430 "sound/Speaking_00430.wav"//黄金地段 让给你 #define P1_Speaking_00464 "sound/Speaking_00464.wav"//太不给面子了 #define P1_Speaking_00469 "sound/Speaking_00469.wav"//你皮子痒啊 #define P1_Speaking_00470 "sound/Speaking_00470.wav"//竟敢在太岁头上动土 #define P1_Speaking_00476 "sound/Speaking_00476.wav"//算你狠 //房屋被摧毁 #define P1_Speaking_00462 "sound/Speaking_00462.wav"//好大的胆子 #define P1_Speaking_00463 "sound/Speaking_00463.wav"//谁敢动我的地 #define P1_Speaking_00466 "sound/Speaking_00466.wav"//竟敢破坏我的好事 #define P1_Speaking_00468 "sound/Speaking_00468.wav"//拆的还真干净 #define P1_Speaking_00474 "sound/Speaking_00474.wav"//你有没有搞错啊 #define P1_Speaking_001061 "sound/Speaking_001061.wav"//真没良心 //摧毁别人房屋 #define P1_Speaking_00433 "sound/Speaking_00433.wav"//不必谢我 #define P1_Speaking_00437 "sound/Speaking_00437.wav"//全部夷为平地 //螃蟹伤人 #define P1_Speaking_00449 "sound/Speaking_00449.wav"//快来帮我把 #define P1_Speaking_01054 "sound/Speaking_01054.wav"//我惨了 #define P1_Speaking_01055 "sound/Speaking_01055.wav"//哎呦喂啊 #define P1_Speaking_001071 "sound/Speaking_001071.wav"//我不要打针 //看到别人住院 #define P1_Speaking_001073 "sound/Speaking_001073.wav"//别闹了 //收取过路费 #define P1_Speaking_00453 "sound/Speaking_00453.wav"//小本经营 概不赊欠 #define P1_Speaking_01059 "sound/Speaking_01059.wav"//蝇头小利 #define P1_Speaking_01057 "sound/Speaking_01057.wav"//这是我应得的 //升级房子 #define P1_Speaking_01051 "sound/Speaking_01051.wav"//别嫉妒我 #define P1_Speaking_001066 "sound/Speaking_001066.wav"//我真佩服自己 //不交过路费 #define P1_Speaking_00446 "sound/Speaking_00446.wav"//有钱也不给你 #define P1_Speaking_00477 "sound/Speaking_00477.wav"//可别想占我便宜啊 //买地 #define P1_Speaking_00458 "sound/Speaking_00458.wav"//盖什么好呢 #define P1_Speaking_001067 "sound/Speaking_001067.wav"//我是个大地主 //捡到珍珠 #define P1_Speaking_01052 "sound/Speaking_01052.wav"//鸿运当头 #define P1_Speaking_001063 "sound/Speaking_001063.wav"//上帝保佑 //对方被罚收税 #define P1_Speaking_00452 "sound/Speaking_00452.wav"//别想偷漏税
3、
根据声音的分类把文件名称放入到Vector中,然后根据场景随机从Vector中取出声音进行播放。
在GameBaseScene.cpp的initAudioEffect方法中,据声音的分类把文件名称放入到Vector中
void GameBaseScene::initAudioEffect() { ......... player2EffectVec_1.pushBack(String::create(P2_SPEAKING01)); player2EffectVec_1.pushBack(String::create(P2_QISIWOLE)); player2EffectVec_1.pushBack(String::create(P2_XINHAOKONGA)); player2EffectVec_1.pushBack(String::create(P2_BUHUIBA)); player2EffectVec_1.pushBack(String::create(P2_PAYHIGH)); player2EffectVec_1.pushBack(String::create(P2_QIANGQIANA)); player2EffectVec_1.pushBack(String::create(P2_HEBAOCHUXIE)); .......... }在Util.cpp中定义声音播放方法,根据声音开关设置,进行声音的播放
void Util::playAudioEffect(const char* effectName,bool isLoop) { bool music_on = UserDefault::getInstance()->getBoolForKey(MUSIC_ON_KEY,true); if(music_on) { CocosDenshion::SimpleAudioEngine::getInstance()->playEffect(effectName,isLoop); } }
//随机从Vector中取出声音进行播放
void Util::playAudioEffectRandom(Vector<String*> effectVec,bool isLoop) { playAudioEffect(effectVec.at(rand() % effectVec.size())->getCString(),isLoop); } void Util::stopAudioPlay() { CocosDenshion::SimpleAudioEngine::getInstance()->stopBackgroundMusic(); CocosDenshion::SimpleAudioEngine::getInstance()->stopAllEffects(); }
4、添加背景音乐,共3首背景音乐,随机播放
void GameBaseScene::initAudioEffect() { bgMusicVector.push_back(BG01_MP3); bgMusicVector.push_back(BG02_MP3); bgMusicVector.push_back(BG03_MP3); for (int i = 0; i<bgMusicVector.size(); i++) { CocosDenshion::SimpleAudioEngine::getInstance()->preloadBackgroundMusic(bgMusicVector.at(i)); } this->schedule(schedule_selector(GameBaseScene::playerBgMusic),5.0f); ..... }
5、角色对话相关的音效,就是根据具体场景,添加相应的音效播放就可以了
关于音乐音效的比较简单,可以参考 http://cn.cocos2d-x.org/tutorial/show?id=2448
这篇文章http://cn.cocos2d-x.org/tutorial/show?id=2352 ,里面的转盘界面效果做得挺好,稍微修改一下,拿到我们大富翁中来吧。
代码同下一节一并发布.
Cocos2d-x 3.2 大富翁游戏项目开发-第二十五部分 大富翁股市
当角色走到股市图标时,进入股市界面。每走完一个回合,增加一条股票数据,
股市界面上半部分显示股票信息,包括代码,名称,当前价格,买入价格,涨跌百分比,角色持有的股票数量
下半部分显示股票价格走势,当点击一个股票时,显示相关股票的价格走势,共显示最新14条的价格走势。
每次点击购买,买入100股 。点击卖出,则卖出所持有的该股的所有股票。成交价格 等信息动态更新
点击返回,返回到游戏主界面,并更新角色资金值
1、首先添加股票类
包括代码,名称,买入价格,涨跌百分比,持仓数量等定义以及相关的get 、set方法
class Stock : public Sprite { ................ private: <span> </span>int stockCode; //股票代码 String* stockName;//股票名称 int NowPrice;//当前价格 int makedealprice;//成交价格 float percent;//涨跌百分比 int storeNumber;//持仓数量 };
2、VisibleRect类,主要是为了方便的获取屏幕的尺寸等信息
class VisibleRect { public: static cocos2d::Rect getVisibleRect(); ................... private: static void lazyInit(); static cocos2d::Rect s_visibleRect; };
3、股票记录中的单元格类StockCellCard,包括单元格背景和显示文字的label。同彩票类card大体相同,不再解释了
4、在RicherPlayer的init方法中,给角色创建股票持有信息,主要是股票代码和持仓数量和买入价格。其他信息无关紧要
bool RicherPlayer::init(char* name,int tag,bool enemy,int money,int strength) { ........... stockMap.insert(0,Stock::create(800100,LanguageString::getInstance()->getLanguageString(RICH_TECHNOLOGY),10,100)); stockMap.insert(1,Stock::create(800200,20,200)); stockMap.insert(2,Stock::create(800300,70,800)); stockMap.insert(3,Stock::create(800400,400)); stockMap.insert(4,Stock::create(800500,0)); .......... }
5、当角色走到股票图标时RicherGameController 控制器,发送进入股市的消息
if(passId == GameBaseScene::stock_tiledID) { String * str = String::createWithFormat("%d-%f-%f-%d-%d",MSG_STOCK_TAG,1.0f,_richerPlayer->getTag(),MOVEPASS); NotificationCenter::getInstance()->postNotification(MSG_STOCK,str); return; }
6、GameBaseScene类定义了股票容器类,存放所以股票相关信息
vector<float> GameBaseScene::stock_pointvec1;
vector<float> GameBaseScene::stock_pointvec2;
vector<float> GameBaseScene::stock_pointvec3;
vector<float> GameBaseScene::stock_pointvec4;
vector<float> GameBaseScene::stock_pointvec5;
在更新回合计数时,调用updateStockVec()方法,添加股票一条新纪录
void GameBaseScene::refreshRounddisplay()
{
..........
updateStockVec()
.......
}
//最多纪录14条纪录,超过的会被覆盖掉 void GameBaseScene::updateStockVec() { float valule1 = rand()%800+10; float valule2 = rand()%800+10; float valule3 = rand()%800+10; float valule4 = rand()%800+10; float valule5 = rand()%800+10; if(stock_pointvec1.size()>13) { for(int i=0;i<13;i++) { stock_pointvec1.at(i)=stock_pointvec1.at(i+1); stock_pointvec2.at(i)=stock_pointvec2.at(i+1); stock_pointvec3.at(i)=stock_pointvec3.at(i+1); stock_pointvec4.at(i)=stock_pointvec4.at(i+1); stock_pointvec5.at(i)=stock_pointvec5.at(i+1); } stock_pointvec1.at(13) =valule1; stock_pointvec2.at(13) =valule2; stock_pointvec3.at(13) =valule3; stock_pointvec4.at(13) =valule4; stock_pointvec5.at(13) =valule5; }else { stock_pointvec1.push_back(valule1); stock_pointvec2.push_back(valule2); stock_pointvec3.push_back(valule3); stock_pointvec4.push_back(valule4); stock_pointvec5.push_back(valule5); } }
7、当GameBaseScene收到进入股市界面的消息时,添加股市layer,显示股市
case MSG_STOCK_TAG: { auto lineView = LineChart::createChart(player1); lineView->setPosition(Point(0,0)); moveTag = messageVector.at(4)->intValue(); lineView->moveTag = moveTag; addChild(lineView); .............. break; }
8、LineChart类是股票界面类
(1)initChart方法
bool LineChart::initChart(RicherPlayer* player) { if ( !LayerColor::initWithColor(Color4B(0,255))) //黑色背景 { return false; } richerPlayer = player; //角色 playerStockMap = player->stockMap;//角色持有的股票容器 initStockVector(playerStockMap); drawNode = DrawNode::create();//创建DrawNode ,准备画图 this->addChild(drawNode); tv = TableView::create(this,Size(650,160));//创建TableView对象 tv->setAnchorPoint(Point(0,0)); tv->setPosition(10,VisibleRect::getVisibleRect().size.height * 1 /2); tv->setDelegate(this); addChild(tv); initMenu();//创建菜单,包括买入,卖出,返回Menu selectedTag =0; float tableY = VisibleRect::getVisibleRect().size.height * 1/2; //选择股票时,箭头移动到相关股票 arrowSprite_left->setPosition(600+arrowSprite_left->getContentSize().width,tableY +selectedTag*32); arrowSprite_right->setPosition(10,tableY + selectedTag*32); setData(getsock_pointVec(selectedTag));//设置股票数据 drawpic();//画走势图 return true; }
(2)initMenu方法创建菜单,包括买入,卖出,返回Menu,以及箭头提示
void LineChart::initMenu() { Menu* menu = Menu::create(); menu->setPosition(CCPointZero); setMenu(menu); MenuItemImage* buyMenuItemButton = MenuItemImage::create("images/buy_normal.png","images/buy_pressed.png",this,menu_selector(LineChart::buttonCallback)); buyMenuItemButton->setPosition(ccp(700,VisibleRect::getVisibleRect().size.height-110)); buyMenuItemButton->setAnchorPoint(ccp(0,0)); buyMenuItemButton->setTag(buy_button); menu->addChild(buyMenuItemButton); ............ arrowSprite_left = Sprite::create("images/arrow_left.png"); arrowSprite_left->setPosition(ccp(-500,-500)); arrowSprite_left->setAnchorPoint(ccp(0,0)); addChild(arrowSprite_left); arrowSprite_right = Sprite::create("images/arrow_right.png"); arrowSprite_right->setPosition(ccp(-500,-500)); arrowSprite_right->setAnchorPoint(ccp(0,0)); addChild(arrowSprite_right); }
(3)initStockVector()添加股票上半部分表格的标题,以及给股票容器添加各个股票信息
void LineChart::initStockVector(Map<int,Stock*> stockMap) { float percent = 0; if(GameBaseScene::stock_pointvec1.size()>1) { percent = (GameBaseScene::stock_pointvec1.at(GameBaseScene::stock_pointvec1.size()-1) - GameBaseScene::stock_pointvec1.at(GameBaseScene::stock_pointvec1.size()-2))/GameBaseScene::stock_pointvec1.at(GameBaseScene::stock_pointvec1.size()-2)*100; } stockVector.pushBack(Stock::create(800100,GameBaseScene::stock_pointvec1.at(GameBaseScene::stock_pointvec1.size()-1),stockMap.at(0)->getMakedealprice(),percent,stockMap.at(0)->getStoreNumber())); .................. Label* code = Label::createWithSystemFont(LanguageString::getInstance()->getLanguageString(STOCK_CODE)->getCString(),"",20); code->setPosition(Point(20,410 )); code->setAnchorPoint(ccp(0,0)); addChild(code); Label* name = Label::createWithSystemFont(LanguageString::getInstance()->getLanguageString(STOCK_NAME)->getCString(),20); name->setPosition(Point(stockCellWidth+20,410 )); name->setAnchorPoint(ccp(0,0)); addChild(name); Label* Nowprice = Label::createWithSystemFont(LanguageString::getInstance()->getLanguageString(STOCK_NowPRICE)->getCString(),20); Nowprice->setPosition(Point(stockCellWidth*2+20,410 )); Nowprice->setAnchorPoint(ccp(0,0)); addChild(Nowprice); Label* dealprice = Label::createWithSystemFont(LanguageString::getInstance()->getLanguageString(STOCK_DEALPRICE)->getCString(),20); dealprice->setPosition(Point(stockCellWidth*3+20,410 )); dealprice->setAnchorPoint(ccp(0,0)); addChild(dealprice); Label* percentLabel = Label::createWithSystemFont(LanguageString::getInstance()->getLanguageString(STOCK_PERCENT)->getCString(),20); percentLabel->setPosition(Point(stockCellWidth*4+20,410 )); percentLabel->setAnchorPoint(ccp(0,0)); addChild(percentLabel); Label* store = Label::createWithSystemFont(LanguageString::getInstance()->getLanguageString(STOCK_STORE)->getCString(),20); store->setPosition(Point(540,410 )); store->setAnchorPoint(ccp(0,0)); addChild(store); playerMoneyLabel = Label::createWithSystemFont( String::createWithFormat("%s %d",LanguageString::getInstance()->getLanguageString(PLAYER_MONEY)->getCString(),richerPlayer->getMoney())->getCString(),20); playerMoneyLabel->setPosition(Point(20,450 )); playerMoneyLabel->setAnchorPoint(ccp(0,0)); addChild(playerMoneyLabel); }
(4)buttonCallback(),点击买入 ,卖出,返回的回调方法
void LineChart::buttonCallback(CCObject* pSender)
{
.............
}
(5)TableView 相关实现方法
//当点击股票时,移动箭头,更新数据,重画走势图 void LineChart::tableCellTouched(cocos2d::extension::TableView *table,cocos2d::extension::TableViewCell *cell) { for(int i=0;i<30;i++) { this->removeChildByTag(100+i); } int tag = cell->getTag(); selectedTag =tag; log("******click id = %d",tag); float height = VisibleRect::getVisibleRect().size.height; float tableY = VisibleRect::getVisibleRect().size.height * 1/2; arrowSprite_left->setPosition(600+arrowSprite_left->getContentSize().width,tableY +tag*32); arrowSprite_right->setPosition(10,tableY + tag*32); log("all height is %f",height); log("all cellY is %f",tableY); setData(getsock_pointVec(tag)); drawpic(); }
//创建tableview相关单元格,当股市上涨时,背景色为红色,下跌时为绿色 TableViewCell* LineChart::tableCellAtIndex(cocos2d::extension::TableView *table,ssize_t idx) { TableViewCell *cell = table->dequeueCell(); LabelTTF *label; int colorTag = 0; if(stockVector.at(idx)->getPercent()>0) { colorTag = 1; }else { colorTag = -1; } if (cell==NULL) { cell = TableViewCell::create(); cell->setTag(idx); for(int i=0; i<6; i++) { switch(i) { case 0: { StockCellCard* card = StockCellCard::createCardSprite(String::createWithFormat("%d",stockVector.at(idx)->getCode()),stockCellWidth,stockCellHeight,stockCellWidth*i+10,colorTag); cell->addChild(card); break; } case 1: { StockCellCard* card = StockCellCard::createCardSprite(stockVector.at(idx)->getStockName(),colorTag); cell->addChild(card); break; } .................................... } } } return cell; }
//共5支股票
ssize_t LineChart::numberOfCellsInTableView(cocos2d::extension::TableView *table){
return 5;
}
(6)画走势图
void LineChart::drawpic() { drawNode->clear(); int maxValue = getMaxValue(pointvec); int maxValue2 = int((maxValue+100) / 100)* 100 ; maxValue1 = maxValue2 / 10; spaceRatio = 0.08f; //y轴间距系数 leftRatioX = 0.1f; //x轴左侧间距系数 int fontSize = 20; string fontName = StringUtils::format("Thonburi"); Size layerSize = Size(VisibleRect::getVisibleRect().size.width,VisibleRect::getVisibleRect().size.height * 1 /2); layerHeight1 = 30; float layerHeight = layerHeight1; float layerWidth = layerSize.width; int count = layerSize.width /50; /***********************画xy轴标签*************************************/ for (int i = 0; i < 11; i++) { Point bPoint = Point(layerWidth* leftRatioX,layerHeight ); Point ePoint = Point(layerWidth* leftRatioX+(count-2) * 50,layerHeight ); Label* label = Label::createWithSystemFont(StringUtils::format("%d",maxValue1* i).c_str(),fontName.c_str(),fontSize); label->setPosition(Point(layerWidth* 0.05f,layerHeight )); label->setTag(100+i); addChild(label); drawNode->drawSegment(bPoint,ePoint,0.5,Color4F(100,100,200,200)); layerHeight += layerSize.height * spaceRatio; } float layer_wd = layerSize.width * leftRatioX; for (int i = 0; i < count; i++) { Point bPoint = Point(layer_wd,layerHeight1); Point ePoint = Point(layer_wd,layerSize.height * spaceRatio*10+layerHeight1); if(i%2 == 0) { drawNode->drawSegment(bPoint,200)); } auto labelX = Label::createWithSystemFont(StringUtils::format("%d",i).c_str(),"Thonburi",20); labelX->setPosition(Point(ePoint.x,0)); labelX->setAnchorPoint(ccp(0,0)); labelX->setTag(100+11+i); this->addChild(labelX); layer_wd += 50; } drawLine(pointvec,Color4B(0,255,255),Color4B(255,255)); }
//画走势线条
void LineChart::drawLine(vector<Point> vec,Color4B lineColor,Color4B dotColor) { Size layerSize = Size(VisibleRect::getVisibleRect().size.width,VisibleRect::getVisibleRect().size.height * 1 /2); float layerWidth = layerSize.width; float tempWidth = layerSize.height * spaceRatio; float tempWidth2 = 0; float tempHeight1 = maxValue1 ; double ratio = tempWidth/tempHeight1; /**********************开始画线**********************/ std::vector<Point>::iterator beforePoint; std::vector<Point>::iterator currentPoint; beforePoint = vec.begin(); for (currentPoint = vec.begin() + 1;currentPoint != vec.end() ; currentPoint++) { Point bPoint = *beforePoint; bPoint = Point(bPoint.x + layerWidth* leftRatioX,bPoint.y * ratio + layerHeight1 +tempWidth2); Point ePoint = *currentPoint; ePoint = Point(ePoint.x + layerWidth* leftRatioX,ePoint.y * ratio + layerHeight1 +tempWidth2); drawNode->drawSegment(bPoint,0.8,Color4F::RED); beforePoint = currentPoint; } /**********************结束画线**********************/ /********************开始画点**********************************************/ beforePoint = vec.begin(); DrawPrimitives::setDrawColor4B(dotColor.r,dotColor.g,dotColor.b,dotColor.a); Point bPoint = *beforePoint; bPoint = Point(bPoint.x +layerWidth* leftRatioX,bPoint.y * ratio + layerHeight1 +tempWidth2); drawNode->drawDot(bPoint,5,Color4F::YELLOW); int i = 2; for (currentPoint = vec.begin() + 1;currentPoint != vec.end() ; currentPoint++) { Point ePoint = *currentPoint; ePoint = Point(ePoint.x + layerWidth* leftRatioX,ePoint.y * ratio + layerHeight1 + tempWidth2); drawNode->drawDot(ePoint,Color4F::YELLOW); i++; } /********************结束画点*********************************************END**/ }
//设置股票数据
void LineChart::setData(vector<float> data) { pointvec.clear(); vector<float>::iterator it; int i = 0; for (it = data.begin();it != data.end();it++) { float f = *it; pointvec.push_back(Point(50 * (i+1),f)); i++; } }
//获取最大值 double LineChart::getMaxValue(std::vector<Point> vec) { double maxY =1; for (int i = 0; i < vec.size(); i++) { float num = vec.at(i).y; if (maxY < abs(num)) { maxY = abs(num); } } return maxY; }
这就是大体代码,详细内容,请参考代码,如下效果图
点击下载代码
未完待续...................
Cocos2d-x 3.2 大富翁游戏项目开发-第二十八部分 游戏保存和载入存档游戏
1、游戏保存如图,在右下角增加保存图标,点击后进行游戏的保存。
游戏保存采用json格式,具体如下: { "map_level":2,// 游戏关卡 "gameRoundCount":66,// 游戏回合数 "players":[ //角色信息 { "playerTag":1,//角色1 "playerPosition_x":320,//角色所处的x坐标 "playerPosition_y":192,//角色所处的y坐标 "restTimes":3,//角色休息回合数 "stop_x":0,//角色停留的x坐标 "stop_y":0,//角色停留的y坐标 "money":509000,//角色资金 "strength":100,//角色体力 "comeFromeRow":4,//角色从上一个位置的行 "comeFromCol":10,//角色从上一个位置的列 "isMyTurn":false,//角色是否该行走 "skill":"1-2-2",//角色技能等级 "lottery":"",//角色购买的彩票号码 "stocks":[ //角色持有的股票信息 {"stockCode":800100,"makedealprice":10,"storeNumber":100},{"stockCode":800200,"makedealprice":0,"storeNumber":0},{"stockCode":800300,{"stockCode":800400,"storeNumber":400},{"stockCode":800500,"storeNumber":0} ] },{ "playerTag":2,//角色2的保存信息,同上 "playerPosition_x":423.635,"playerPosition_y":96,"restTimes":0,"stop_x":10,"stop_y":13,"money":410300,"strength":80,"comeFromeRow":2,"comeFromCol":15,"isMyTurn":false,"skill":"3-2-1","lottery":"","stocks":[ {"stockCode":800100,"makedealprice":20,"storeNumber":200},"storeNumber":0} ] } ],"landlayer":[ //地块的信息,在x行,y列 地块的gid值 {"x":5,"y":7,"gid":12},{"x":5,"y":12,{"x":6,"y":9,"y":10,"gid":11},{"x":7,"gid":1},"y":13,{"x":8,"y":11,{"x":9,"y":8,{"x":10,"y":6,{"x":11,"gid":13},"gid":15},{"x":12,"gid":14},{"x":13,{"x":14,"gid":10},{"x":15,{"x":16,{"x":17,"gid":10} ] }
//在添加go按钮的方法中同时添加保存按钮 void GameBaseScene::addGoButton() { ...... saveMenuItemButton = MenuItemImage::create("map/save_normal.png","map/save_pressed.png",this,menu_selector(GameBaseScene::goButtonCallback)); saveMenuItemButton->setPosition(ccp(winSize.width,0)); saveMenuItemButton->setAnchorPoint(ccp(1,0)); saveMenuItemButton->setTag(saveButtonTag); menu->addChild(saveMenuItemButton); } void GameBaseScene::goButtonCallback(cocos2d::CCObject *pSender) { ......... //当点击后调用saveGame()方法保存游戏 if(tag == saveButtonTag) { if(saveGame()) { CocosToast::createtoast(this,LanguageString::getInstance()->getLanguageString(SAVE_SUCESS)->getCString(),TOAST_SHOW_TIME,winSize/2); }else { CocosToast::createtoast(this,LanguageString::getInstance()->getLanguageString(SAVE_FAIL)->getCString(),winSize/2); } } }
saveGame()进行具体的游戏保存
cocos2dx使用了rapidjson库来替换原来的jsoncpp,我们就用这个cocos2dx自带的json库
//*** 生成 json 文件,存储在 getWritablePath 文件夹下 *** ,当前在proj.win32\Debug.win32目录下
bool GameBaseScene::saveGame() { rapidjson::Document writedoc; //创建Document writedoc.Setobject(); rapidjson::Document::AllocatorType& allocator = writedoc.GetAllocator(); rapidjson::Value players(rapidjson::kArrayType);//创建players数组 writedoc.AddMember("map_level",map_level,allocator); //添加map_level属性值 writedoc.AddMember("gameRoundCount",gameRoundCount,allocator); //添加gameRoundCount回合数 int playerNumber=1; rapidjson::Value player1_json(rapidjson::kObjectType); //创建player1的json对象 rapidjson::Value player2_json(rapidjson::kObjectType); //创建player2的json对象 rapidjson::Value player3_json(rapidjson::kObjectType); //创建player3的json对象 //保存各个角色的信息 for(auto it=players_vector.begin();it!=players_vector.end();it++) { RicherPlayer* richerPlayer = dynamic_cast<RicherPlayer*>(*it); switch(playerNumber) { case 1: { //在player1_json对象中添加角色各个属性值,json object 格式 “名称/值” player1_json.AddMember("playerTag",richerPlayer->getTag(),allocator); player1_json.AddMember("playerPosition_x",richerPlayer->getPosition().x,allocator); player1_json.AddMember("playerPosition_y",richerPlayer->getPosition().y,allocator); player1_json.AddMember("restTimes",richerPlayer->restTimes,allocator); player1_json.AddMember("stop_x",richerPlayer->stop_x,allocator); player1_json.AddMember("stop_y",richerPlayer->stop_y,allocator); player1_json.AddMember("money",richerPlayer->getMoney(),allocator); player1_json.AddMember("strength",richerPlayer->getStrength(),allocator); player1_json.AddMember("comeFromeRow",richerPlayer->getComeFromeRow(),allocator); player1_json.AddMember("comeFromCol",richerPlayer->getComeFromCol(),allocator); player1_json.AddMember("isMyTurn",richerPlayer->getIsMyTurn(),allocator); player1_json.AddMember("skill",String::createWithFormat("%d-%d-%d",richerPlayer->skill_vector.at(0),richerPlayer->skill_vector.at(1),richerPlayer->skill_vector.at(2))->getCString(),allocator); std::string tempstr; tempstr = ""; for(auto i=0;i<richerPlayer->lottery_vector.size();i++) { tempstr.append(String::createWithFormat("%02d",richerPlayer->lottery_vector.at(i))->getCString()).append("_"); } player1_json.AddMember("lottery",String::createWithFormat("%s",tempstr.c_str())->getCString(),allocator); rapidjson::Value stocks(rapidjson::kArrayType); for(auto i=0;i<richerPlayer->stockMap.size();i++) { rapidjson::Value stock(rapidjson::kObjectType); stock.AddMember("stockCode",richerPlayer->stockMap.at(i)->getCode(),allocator); stock.AddMember("makedealprice",richerPlayer->stockMap.at(i)->getMakedealprice(),allocator); stock.AddMember("storeNumber",richerPlayer->stockMap.at(i)->getStoreNumber(),allocator); stocks.PushBack(stock,allocator); } player1_json.AddMember("stocks",stocks,allocator); // 将player1_json加入到players数组 players.PushBack(player1_json,allocator); break; } case 2: { //添加角色2属性值 player2_json.AddMember("playerTag",allocator); player2_json.AddMember("playerPosition_x",allocator); player2_json.AddMember("playerPosition_y",allocator); player2_json.AddMember("restTimes",allocator); player2_json.AddMember("stop_x",allocator); player2_json.AddMember("stop_y",allocator); player2_json.AddMember("money",allocator); player2_json.AddMember("strength",allocator); player2_json.AddMember("comeFromeRow",allocator); player2_json.AddMember("comeFromCol",allocator); player2_json.AddMember("isMyTurn",allocator); player2_json.AddMember("skill",allocator); std::string tempstr; tempstr = ""; for(auto i=0;i<richerPlayer->lottery_vector.size();i++) { tempstr.append(String::createWithFormat("%02d",richerPlayer->lottery_vector.at(i))->getCString()).append("_"); } player2_json.AddMember("lottery",allocator); } player2_json.AddMember("stocks",allocator); players.PushBack(player2_json,allocator); break; } case 3: { //添加角色3属性值 player3_json.AddMember("playerTag",allocator); player3_json.AddMember("playerPosition_x",allocator); player3_json.AddMember("playerPosition_y",allocator); player3_json.AddMember("restTimes",allocator); player3_json.AddMember("stop_x",allocator); player3_json.AddMember("stop_y",allocator); player3_json.AddMember("money",allocator); player3_json.AddMember("strength",allocator); player3_json.AddMember("comeFromeRow",allocator); player3_json.AddMember("comeFromCol",allocator); player3_json.AddMember("isMyTurn",allocator); player3_json.AddMember("skill",richerPlayer->lottery_vector.at(i))->getCString()).append("_"); } player3_json.AddMember("lottery",allocator); } player3_json.AddMember("stocks",allocator); players.PushBack(player3_json,allocator); break; } } playerNumber++; } //将players数组写入到writedoc writedoc.AddMember("players",players,allocator); // 保存地块json rapidjson::Value landlayerjson(rapidjson::kArrayType); Size _landLayerSize = landLayer->getLayerSize(); for (int j = 0; j < _landLayerSize.width; j++) { for (int i = 0; i < _landLayerSize.height; i++) { Sprite* _sp = landLayer->tileAt(Point(j,i)); if (_sp) { rapidjson::Value landJson(rapidjson::kObjectType); int gid = landLayer->getTileGIDAt(Point(j,i)); landJson.AddMember("x",j,allocator); landJson.AddMember("y",i,allocator); landJson.AddMember("gid",gid,allocator); landlayerjson.PushBack(landJson,allocator); } } } writedoc.AddMember("landlayer",landlayerjson,allocator); //把json数据保存到path路径文件下,文件名称为saveJsonName ,saveJsonName在SeaScene.cpp中赋值 StringBuffer buffer; rapidjson::Writer<StringBuffer> writer(buffer); writedoc.Accept(writer); auto path = FileUtils::getInstance()->getWritablePath(); path.append(saveJsonName); FILE* file = fopen(path.c_str(),"wb"); if(file) { fputs(buffer.GetString(),file); fclose(file); } cclOG("%s",buffer.GetString()); return true; }
2、载入存档
效果如图
//在addMenuSprites()增加载入游戏按钮 void MenuScene:: addMenuSprites() { ............. LabelTTF* loadGameTTF = LabelTTF::create(LanguageString::getInstance()->getLanguageString(LOAD_GAME)->getCString(),FONT_MENU,Btn_FontSize); ControlButton* loadGameBtn = ControlButton::create(loadGameTTF,btnnormal4); loadGameBtn->setBackgroundSpriteForState(btnPress4,Control::State::SELECTED); loadGameBtn->setPosition(ccp(visibleSize.width/2,visibleSize.height-360)); loadGameBtn->setPreferredSize(Size(Btn_Width,Btn_Height)); loadGameBtn->addTargetWithActionForControlEvents(this,cccontrol_selector(MenuScene::menuTouchDown),Control::EventType::TOUCH_DOWN); loadGameBtn->setTag(Btn_Load_Game_TAG); addChild(loadGameBtn); ........ }
//点击后进入到popupLoadGameLayer(),弹出游戏存档的界面 void MenuScene::popupLoadGameLayer() { PopupLayer* popDialog = PopupLayer::create(DIALOG_BG); popDialog->setContentSize(CCSizeMake(Quit_Dialog_Size_Width,winSize.height)); popDialog->setTitle(LanguageString::getInstance()->getLanguageString(LOAD_GAME)->getCString()); popDialog->setContentText(LanguageString::getInstance()->getLanguageString(DIALOG_CONTENT)->getCString(),20,60,250); popDialog->setPopType(LOADGAME); popDialog->setCallbackFunc(this,callfuncN_selector(MenuScene::quitButtonCallback)); popDialog->addButton(BUTTON_BG2,BUTTON_BG3,LanguageString::getInstance()->getLanguageString(CANCEL)->getCString(),Btn_Quit_Cancel_TAG); this->addChild(popDialog); }
PopupLayer会根据pop类型,调用setLoadGameContext(),创建载入游戏的对话框界面 void PopupLayer::onEnter() { ...... case LOADGAME: { setLoadGameContext(contentSize); break; } ...... }
//该方法主要是判断path路径下是否有存档文件。如果没有存档,显示无存档,有则显示关卡图片 void PopupLayer::setLoadGameContext(Size size) { Menu* menu = Menu::create(); menu->setPosition(CCPointZero); //判断是否有夏日海滩的存档文件 auto beach_path = FileUtils::getInstance()->getWritablePath(); beach_path.append("beach_save.json"); FILE* beach_file = fopen(beach_path.c_str(),"r"); //有则显示海滩图片,否则显示无存档 if(beach_file) { beachLoadGameMenuItem = MenuItemImage::create("map/beach_load_normal.png","map/beach_load_pressed.png",menu_selector(PopupLayer::loadGameButtonCallback)); beachLoadGameMenuItem->setPosition(winSize/2+Size(0,120)); beachLoadGameMenuItem->setTag(save_beach_tag); menu->addChild(beachLoadGameMenuItem); fclose(beach_file); }else { beachLoadGameMenuItem = MenuItemImage::create("map/blank.png","map/blank.png",menu_selector(PopupLayer::loadGameButtonCallback)); beachLoadGameMenuItem->setPosition(winSize/2+Size(0,120)); menu->addChild(beachLoadGameMenuItem); } //判断是否有海底世界的存档文件 auto sea_path = FileUtils::getInstance()->getWritablePath(); sea_path.append("sea_save.json"); FILE* sea_file = fopen(sea_path.c_str(),"r"); if(sea_file) { seaLoadGameMenuItem = MenuItemImage::create("map/sea_load_normal.png","map/sea_load_pressed.png",menu_selector(PopupLayer::loadGameButtonCallback)); seaLoadGameMenuItem->setPosition(winSize/2+Size(0,20)); seaLoadGameMenuItem->setTag(save_sea_tag); menu->addChild(seaLoadGameMenuItem); fclose(sea_file); }else { seaLoadGameMenuItem = MenuItemImage::create("map/blank.png",menu_selector(PopupLayer::loadGameButtonCallback)); seaLoadGameMenuItem->setPosition(winSize/2+Size(0,20)); menu->addChild(seaLoadGameMenuItem); } //判断是否有空中花园的存档文件 auto garden_path = FileUtils::getInstance()->getWritablePath(); garden_path.append("garden_save.json"); FILE* garden_file = fopen(garden_path.c_str(),"r"); if(garden_file) { gardenLoadGameMenuItem = MenuItemImage::create("map/garden_load_normal.png","map/garden_load_pressed.png",menu_selector(PopupLayer::loadGameButtonCallback)); gardenLoadGameMenuItem->setPosition(winSize/2+Size(0,-80)); gardenLoadGameMenuItem->setTag(save_garden_tag); menu->addChild(gardenLoadGameMenuItem); fclose(garden_file); }else { gardenLoadGameMenuItem = MenuItemImage::create("map/blank.png",menu_selector(PopupLayer::loadGameButtonCallback)); gardenLoadGameMenuItem->setPosition(winSize/2+Size(0,-80)); menu->addChild(gardenLoadGameMenuItem); } addChild(menu); }
//当点击各个存档文件图片后,载入相应的游戏存档,恢复游戏 void PopupLayer::loadGameButtonCallback(cocos2d::CCObject *pSender) { int tag = ((Node*)pSender)->getTag(); if(tag == save_beach_tag) { log("beach load"); } if(tag == save_sea_tag) { //点击海底世界图片,首先进入海底世界关卡 TransitionFadeBL* scene = TransitionFadeBL::create(1,SeaScene::createScene()); Director::getInstance()->pushScene(scene); //然后发送载入游戏的消息 String * str = String::createWithFormat("%d-%d",MSG_LOAD_GAME_TAG,tag); NotificationCenter::getInstance()->postNotification(MSG_LOAD_GAME,str); log("sea load"); } if(tag == save_garden_tag) { log("garden load"); } }
//GameBaseScene收到载入的消息后,调用reloadGame()方法,载入游戏存档 void GameBaseScene::receivednotificationOMsg(Object* data) { ........ case MSG_LOAD_GAME_TAG: { int map_level = messageVector.at(1)->intValue(); reloadGame(map_level); break; } ....... }
//开始具体游戏的载入恢复 bool GameBaseScene::reloadGame(int map_level) { //根据关卡,载入相应的存档文件 auto path = FileUtils::getInstance()->getWritablePath(); switch(map_level) { case 1: { path.append("beach_save.json"); break; } case 2: { path.append("sea_save.json"); break; } case 3: { path.append("garden_save.json"); break; } } //*** 读取 json 文件 *** rapidjson::Document readdoc; bool bRet = false; ssize_t size = 0; std::string load_str; // getFileData 如果不指定,读取根目录是 Resource 文件夹 unsigned char* titlech = FileUtils::getInstance()->getFileData(path,"r",&size); load_str = std::string((const char*)titlech,size); readdoc.Parse<0>(load_str.c_str()); if(readdoc.HasParseError()) { cclOG("GetParseError%s\n",readdoc.GetParseError()); } if(!readdoc.IsObject()) return 0; //回合数载入 rapidjson::Value& _gameRoundCount = readdoc["gameRoundCount"]; gameRoundCount = _gameRoundCount.GetInt(); refreshRounddisplay(); //土地等级载人 rapidjson::Value& _landlayer = readdoc["landlayer"]; if(_landlayer.IsArray()) { for(int i=0; i<_landlayer.Capacity(); i++) { rapidjson::Value& arraydoc = _landlayer[i]; int x = arraydoc["x"].GetInt(); cclOG("x:%d",x); int y = arraydoc["y"].GetInt(); cclOG("y:%d",y); int gid = arraydoc["gid"].GetInt(); cclOG("gid:%d",gid); landLayer->setTileGID(gid,ccp(x,y)); } } //人物信息载人 rapidjson::Value& _players = readdoc["players"]; if(_players.IsArray()) { for(int i=0; i<_players.Capacity(); i++) { rapidjson::Value& arraydoc = _players[i]; RicherPlayer* _richerPY = players_vector.at(i); int _restTimes = arraydoc["restTimes"].GetInt(); float _playerPositionX = arraydoc["playerPosition_x"].GetDouble(); float _playerPositionY = arraydoc["playerPosition_y"].GetDouble(); int _stop_x = arraydoc["stop_x"].GetInt(); int _stop_y = arraydoc["stop_y"].GetInt(); int _money = arraydoc["money"].GetInt(); int _strength = arraydoc["strength"].GetInt(); int _comeFromeRow = arraydoc["comeFromeRow"].GetInt(); int _comeFromCol = arraydoc["comeFromCol"].GetInt(); bool _isMyTurn = arraydoc["isMyTurn"].GetBool(); const char* _skill = arraydoc["skill"].GetString(); const char* _lottery = arraydoc["lottery"].GetString(); Vector<String*> lotteryVector = Util::splitString(_lottery,"_"); for(int i=0;i<lotteryVector.size();i++ ) { _richerPY->lottery_vector.push_back(lotteryVector.at(i)->intValue()); } _richerPY->restTimes = _restTimes; _richerPY->setPosition(ccp(_playerPositionX,_playerPositionY)); _richerPY->setComeFromeRow(_comeFromeRow); _richerPY->setComeFromCol(_comeFromCol); _richerPY->setIsMyTurn(_isMyTurn); _richerPY->stop_x = _stop_x; _richerPY->stop_y = _stop_y; _richerPY->setMoney(_money); _richerPY->setStrength(_strength); Vector<String*> skillVs = Util::splitString(_skill,"-"); _richerPY->skill_vector.at(0) = skillVs.at(0)->intValue(); _richerPY->skill_vector.at(1) = skillVs.at(1)->intValue(); _richerPY->skill_vector.at(2) = skillVs.at(2)->intValue(); refreshMoneyLabel(_richerPY,0); refreshStrengthLabel(_richerPY,0); } } //股票载入 for(int i=0; i<players_vector.size(); i++) { RicherPlayer* _richerPY = players_vector.at(i); rapidjson::Value& _stocks = _players[i]["stocks"]; if(_stocks.IsArray()) { for(int i=0; i<_stocks.Capacity(); i++) { rapidjson::Value& arraydoc = _stocks[i]; int _stockCode = arraydoc["stockCode"].GetInt(); int _makedealprice = arraydoc["makedealprice"].GetInt(); int _storeNumber = arraydoc["storeNumber"].GetInt(); _richerPY->stockMap.at(i)->setMakedealprice(_makedealprice); _richerPY->stockMap.at(i)->setStoreNumber(_storeNumber); } } } return 0; }
至此,游戏从保存文档中恢复完毕。
点击下载代码 未完待续................
Cocos2d-x 3.2 大富翁游戏项目开发-第二十部分 螃蟹挡路(code)
该部分我们添加螃蟹伤人事件,道路位置随机添加螃蟹精灵,当角色行走完毕如果停留位置碰到了螃蟹,首先播放伤人动画,然后是播放救护车把角色带走动画。如果轮流到该角色行走时,吐司提示住院还有几天,当住院天数到期,该角色才可以继续行走
新建了几个精灵类
Item_crab.cpp 螃蟹
Item_emergency.cpp 救护车
Item_fog.cpp 烟雾
Item_stretcher.cpp 担架
//该方法在场景中添加这几个精灵 void GameBaseScene::initItemSprite() { item_crab = (Item_crab*)Item::create(ITEM_CRAB); addChild(item_crab); item_crab->runAction(RepeatForever::create(item_crab->getnormal_anmi())); item_crab->setVisible(false); emerg = Item_emergency::create(); addChild(emerg); emerg->setVisible(false); fog = Item_fog::create(); addChild(fog); fog->setVisible(false); strentcher = Item_stretcher::create(); addChild(strentcher); strentcher->setVisible(false); strentcher->setAnchorPoint(ccp(0,0.9)); } 定义了定时器,每隔100秒调用该方法,更新螃蟹位置 void GameBaseScene::registerBlockWaySchedule() { schedule(schedule_selector(GameBaseScene::updateBlockWaySprites),100.0f); } void GameBaseScene::updateBlockWaySprites(float dt) { int _rand1 = rand()%(wayLayerPass_vector.size()); Vec2 position = wayLayerPass_vector.at(_rand1); position.x -= 5; position.y +=tiledHeight; item_crab->setVisible(true); item_crab->setPosition(position); item_crab->setAnchorPoint(ccp(0,0.6)); }
1、首先在RicherPlayer.cpp中,添加 restTimes 属性,记录受伤后,角色需要住院停留的回合数
2、修改void RicherGameController::endGo()方法
当角色行走完毕,发送MSG_BLOCK_WAY_EVENT消息,该消息用来处理行走完毕后,检查道路上是否存在螃蟹等
void RicherGameController::endGo() { ........... if(stepHasGone >= stepsCount) { String * str = String::createWithFormat("%d-%f-%f-%d",MSG_BLOCK_WAY_EVENT_TAG,0.0f,_richerPlayer->getTag()); NotificationCenter::getInstance()->postNotification(MSG_BLOCK_WAY_EVENT,str); return; } ............. }
3、GameBaseScene.cpp注册MSG_BLOCK_WAY_EVENT消息观察者
void GameBaseScene::registerNotificationObserver() { ........... NotificationCenter::getInstance()->addobserver( this,callfuncO_selector(GameBaseScene::receivednotificationOMsg),MSG_BLOCK_WAY_EVENT,NULL); ............ }
4、receivednotificationOMsg 具体处理该消息,根据角色调用doblockWayEvent 方法
void GameBaseScene::receivednotificationOMsg(Object* data) { ........... case MSG_BLOCK_WAY_EVENT_TAG: { int playerTag = messageVector.at(3)->intValue(); switch(playerTag) { case PLAYER_1_TAG: { doblockWayEvent(player1); break; } case PLAYER_2_TAG: { doblockWayEvent(player2); break; } } break; } ............. }
5、doblockWayEvent方法,就是根据角色判断是否碰到了螃蟹,如果碰到了,播放受伤等一系列动画,动画播放完毕后,设置角色不可见,并发送MSG_PICKONE_TOGO消息,让控制器取出下一个角色继续行走。
void GameBaseScene::doblockWayEvent(RicherPlayer* player) { if(player->getBoundingBox().containsPoint(item_crab->getPosition()+ccp(item_crab->getContentSize().width/2,-item_crab->getContentSize().height/2))) { //碰到了螃蟹,设置螃蟹位置,让其不可见 item_crab->setPosition(ccp(-200,-200)); //设置角色随机停留回合数 player->restTimes = rand()%(5) + 1;; log("doblockWayEvent intersetcRect"); //救护车变为可见 emerg->setVisible(true); //救护车从右往左移动的距离 int distance = tableStartPosition_x-player->getPosition().x; //救护车的位置 emerg->setPosition(player->getPosition()+ccp(distance,0)); //螃蟹和角色打架的烟雾动画 fog->setVisible(true); fog->setPosition(player->getPosition()); Repeat* repeate0 = Repeat::create(fog->getnormal_anmi(),2); fog->runAction(repeate0); //救护车的移动动画 MoveBy* moveBy = MoveBy::create(1.0f,ccp(-distance,0)); MoveBy* moveBy2 = MoveBy::create(0.5f,ccp(-60,0)); Repeat* repeate = Repeat::create(emerg->getCar_go_anmi(),5); Repeat* repeate2 = Repeat::create(emerg->getCar_stop_anmi(),1); Sequence* spawnAction = Sequence::create(Spawn::create(moveBy,repeate,NULL),Spawn::create(moveBy2,repeate2,CallFunc::create(CC_CALLBACK_0(GameBaseScene::endCarGo,this)),NULL); spawnAction->retain(); emerg->runAction(spawnAction); //根据动画播放的时间设置角色不可见 if(player->getTag() == PLAYER_1_TAG) { scheduleOnce(schedule_selector(GameBaseScene::setPlayer1InVisible),2.5f); }else if(player->getTag() == PLAYER_2_TAG) { scheduleOnce(schedule_selector(GameBaseScene::setPlayer2InVisible),2.5f); } //Toast显示角色受伤住院天数信息 CocosToast::createtoast(this,String::createWithFormat("%s %d %s",LanguageString::getInstance()->getLanguageString(PLAYER_HURT)->getCString(),player->restTimes,LanguageString::getInstance()->getLanguageString(RICH_DAY)->getCString())->getCString(),TOAST_SHOW_TIME,player->getPosition()); } else { //如果没有碰到螃蟹,角色继续发送消息用于处理停留位置事件:是否有问号时间,然后是上下左右相邻位置房屋是否需要购买升级缴纳过路费等 NotificationCenter::getInstance()->postNotification(MSG_HANDLE_PROP_EVENT,String::createWithFormat("%d",MSG_HANDLE_PROP_EVENT_TAG)); } } //让角色和打架烟雾动画不可见 void GameBaseScene::setPlayer1InVisible(float dt) { player1->setVisible(false); fog->setVisible(false); } void GameBaseScene::setPlayer2InVisible(float dt) { player2->setVisible(false); fog->setVisible(false); } //救护车开来动画结束后调用该函数,播放小黄人抬担架动画 void GameBaseScene::endCarGo() { strentcher->setVisible(true); strentcher->setPosition(emerg->getPosition()); MoveBy* moveBy = MoveBy::create(0.5f,ccp(60,0)); ScaleBy* scaleBy = ScaleBy::create(0.5f,0.8); Repeat* repeate = Repeat::create(strentcher->getStretcher_empty_anmi(),1); ScaleBy* scaleBy2 = ScaleBy::create(0.5f,1.25); MoveBy* moveBy2 = MoveBy::create(0.5f,0)); Repeat* repeate2 = Repeat::create(strentcher->getStretcher_full_anmi(),1); Sequence* spawnAction = Sequence::create(Spawn::create(moveBy,scaleBy,scaleBy2,CallFunc::create(CC_CALLBACK_0(GameBaseScene::startCarGoAgain,NULL); spawnAction->retain(); strentcher->runAction(spawnAction); } //小黄人抬担架动画播放完毕后,播放救护车开走动画 void GameBaseScene::startCarGoAgain() { strentcher->setVisible(false); int distance = emerg->getPositionX(); MoveBy* moveBy = MoveBy::create(1.0f,0)); Repeat* repeate = Repeat::create(emerg->getCar_go_anmi(),5); Sequence* spawnAction = Sequence::create(Spawn::create(moveBy,CallFunc::create(CC_CALLBACK_0(GameBaseScene::endCarGoLast,NULL); spawnAction->retain(); emerg->runAction(spawnAction); } //救护车开走后,调用该方法,让救护车不可见,并发送MSG_PICKONE_TOGO消息,让其他角色继续行走 void GameBaseScene::endCarGoLast() { emerg->setVisible(false); NotificationCenter::getInstance()->postNotification(MSG_PICKONE_TOGO,MSG_PICKONE_TOGO_TAG)); }
6、查看控制器中pickOnePlayerToGo方法
void RicherGameController::pickOnePlayerToGo() { for(auto it=GameBaseScene::players_vector.begin();it!=GameBaseScene::players_vector.end();it++) { RicherPlayer* richerPlayer = dynamic_cast<RicherPlayer*>(*it); //如果轮流到该角色行走,但是在受伤休息,则发送MSG_REST 休息消息 if(richerPlayer->getIsMyTurn() && richerPlayer->restTimes > 0 ) { String * str = String::createWithFormat("%d-%f-%f-%d",MSG_REST_TAG,richerPlayer->getTag()); NotificationCenter::getInstance()->postNotification(MSG_REST,str); return; } //如果轮流到角色行走,并且不在休息 if(richerPlayer->getIsMyTurn() && richerPlayer->restTimes == 0) { richerPlayer->setVisible(true); //角色1 发送MSG_GO消息,显示go按钮 if(richerPlayer->getTag() == PLAYER_1_TAG ) { NotificationCenter::getInstance()->postNotification(MSG_GO,MSG_GO_SHOW_TAG)); return; } //其他角色 获取路径,自动行走 int randNumber = rand()%6 + 1; RouteNavigation::getInstance()->getPath(richerPlayer,randNumber,GameBaseScene::canPassGrid,GameBaseScene::tiledRowsCount,GameBaseScene::tiledColsCount); richerPlayer->startGo(RouteNavigation::getInstance()->getPathRow_vector(),RouteNavigation::getInstance()->getPathCols_vector()); return; } } oneRoundDone = true; //走到这里,说明角色都行走完毕,调用resetPlayerGoTurn方法,重新设置角色IsMyTurn为true等 resetPlayerGoTurn(); } //每一个回合结束后调用该方法,让角色的restTimes 减1 void RicherGameController::resetPlayerGoTurn() { for(auto it=GameBaseScene::players_vector.begin();it!=GameBaseScene::players_vector.end();it++) { RicherPlayer* richerPlayer = dynamic_cast<RicherPlayer*>(*it); richerPlayer->setIsMyTurn(true); richerPlayer->restTimes--; if(richerPlayer->restTimes < 0) { richerPlayer->restTimes = 0; } } //发送MSG_ROUND_COUNT 更新回合数 NotificationCenter::getInstance()->postNotification(MSG_ROUND_COUNT,MSG_ROUND_COUNT_TAG)); //设置完毕,继续调用pickOnePlayerToGo ,进行下一轮行走 pickOnePlayerToGo(); }
7、GameBaseScene.cpp注册MSG_REST消息观察者
void GameBaseScene::registerNotificationObserver() { ........... NotificationCenter::getInstance()->addobserver( this,MSG_REST,NULL); ............. }
8、处理MSG_REST消息
当收到休息的消息,首先设置IsMyTurn 为false,并吐司显示还需要休息几个回合,显示结束后调用GameBaseScene::sendMSGPickOnetoGO 方法,继续下一个角色行走
void GameBaseScene::receivednotificationOMsg(Object* data) { .......... case MSG_REST_TAG: { buy_land_x = messageVector.at(1)->floatValue(); buy_land_y = messageVector.at(2)->floatValue(); int playerTag = messageVector.at(3)->intValue(); switch(playerTag) { case PLAYER_1_TAG: { player1->setIsMyTurn(false); CocosToast::createtoast(this,LanguageString::getInstance()->getLanguageString(IN_HOSPITAL_REMAIN)->getCString(),player1->restTimes,player1->getPosition(),(SEL_CallFun)&GameBaseScene::sendMSGPickOnetoGO); break; } case PLAYER_2_TAG: { player2->setIsMyTurn(false); CocosToast::createtoast(this,player2->restTimes,player2->getPosition(),(SEL_CallFun)&GameBaseScene::sendMSGPickOnetoGO); break; } } break; } .......... }
9、CocosToast.cpp 文件,添加了SEL_CallFun method 函数指针,用来调用传进来的方法,如 GameBaseScene::sendMSGPickOnetoGO 发送行走消息。
typedef void (Layer::*SEL_CallFun)();
void CocosToast::createtoast(cocos2d::Node *node,const std::string &msg,const float &time,Vec2 point,SEL_CallFun method);
10、当角色行走完毕 停留位置的房屋所有者如果在住院,则免缴过路费。吐司提示,并调用GameBaseScene::sendMSGPickOnetoGO 发送行走消息
void GameBaseScene::payTolls(int payTag,float x,float y,int playerTag) { ............. if(landOwner->restTimes > 0) { CocosToast::createtoast(this,LanguageString::getInstance()->getLanguageString(IN_HOSPITAL)->getCString(),(SEL_CallFun)&GameBaseScene::sendMSGPickOnetoGO); return; } ............. }
部分效果图
点击下载代码
http://download.csdn.net/detail/lideguo1979/8369525
未完待续..................
今天关于火云开发课堂 - 《使用Cocos2d-x 开发3D游戏》系列 第二十五节: 3D项目优化方案的介绍到此结束,谢谢您的阅读,有关Cocos2d-x 3.2 大富翁游戏项目开发-第二十九部分 游戏配音、Cocos2d-x 3.2 大富翁游戏项目开发-第二十五部分 大富翁股市、Cocos2d-x 3.2 大富翁游戏项目开发-第二十八部分 游戏保存和载入存档游戏、Cocos2d-x 3.2 大富翁游戏项目开发-第二十部分 螃蟹挡路(code)等更多相关知识的信息可以在本站进行查询。
本文标签: