首页 > 代码库 > Cocos2d-x 个人笔记 《2048》(5)
Cocos2d-x 个人笔记 《2048》(5)
- - 想做特效。 我写的合并方法是调用 display 重绘精灵的图片,使用CCActionInterval 后,我打算把重构精灵延时。
然后就乱了。。。动作线程还没执行玩,精灵就销毁了什么的。还有定时器还没执行就又调用定时器什么。
CCScheduler#scheduleSelector. Selector already scheduled...这之类的错误。
果断重写,把每个要移动的矩阵元素 的移动目标保存下来,然后一次执行所有的动作,再延时重载精灵图片。
用了一个 b[][] 存移动到的 坐标。-1 表明没有移动。
My2048[][] 是存2 ^ ?的。
const int PP[]= {0,2,4,8,16,32,64,128,256,512,1024,2048};
举个左移的例子。
memset(b,-1,sizeof(b)); if(m==1)// left { FOR(i,0,4) { FOR(j,0,4) { if(My2048[i][j]==0) for(int k=j+1; k<4; k++) { if(My2048[i][k]==0)continue; int tmp=My2048[i][j]; My2048[i][j]=My2048[i][k]; My2048[i][k]=tmp; b[i][k]=i*4+j; flag=true; break; } for(int k=j+1; k<4; k++) { if(My2048[i][k]==0)continue; else if(My2048[i][k]==My2048[i][j]) { My2048[i][j]++; My2048[i][k]=0; My2048Point+=PP[My2048[i][j]]; b[i][k]=i*4+j; flag=true; pointadd=true; break; } else break; } } } }
这下顺便可以实现Undo 功能。只需要一个双向队列,队列只保存最近的一些就够了。
在 四个方向判断完了之后就 检查一下是否有成功移动的。有的话就调用动作和延时。
void My2048Scene::Mydisplay() { FOR(i,0,4) FOR(j,0,4) { if(b[i][j]==-1)continue; int x=b[i][j]/4,y=b[i][j]%4; CCActionInterval *move_to=CCMoveTo::create(0.2f,ccp(Mysize.width+100*y,Mysize.height-100*x)); g[i*4+j]->runAction(move_to); } scheduleOnce(schedule_selector(My2048Scene::Myredis),0.2f); }
开始有个CCSprite *g[16]; 都执行 Move_to 动作0.2秒。
Move_to 线程是跟下面的并发执行的,所以 Myredis用定时器延迟0.2秒执行。
而 Myredis 则是重载精灵图片。
void My2048Scene::Myredis(float dt) { FOR(i,0,4) FOR(j,0,4) { CCString *str=CCString::createWithFormat("%d.png",My2048[i][j]); g[i*4+j]->cleanup(); g[i*4+j]->initWithFile(str->getCString()); g[i*4+j]->setPosition(ccp(Mysize.width+100*j,Mysize.height-100*i)); } }
这样就完成了移动特效。
随机生成2or4的时候,使用一个先放大,再缩回原样。
CCString *str=CCString::createWithFormat("%d.png",My2048[i][j]); g[i*4+j]->cleanup(); g[i*4+j]->initWithFile(str->getCString()); g[i*4+j]->setPosition(ccp(Mysize.width+100*j,Mysize.height-100*i)); CCActionInterval *build_1=CCScaleTo::create(0.2f,1.5f); CCActionInterval *build_2=CCScaleTo::create(0.2f,1.0f); CCActionInterval *build_action=CCSequence::create(build_1,build_2,NULL); g[i*4+j]->runAction(build_action);
不过这样写后,我在调试的时候,发现触摸很快的话,定时器一样会出现问题。
我就 bool Go_touch; 让我的 随机生成2or4 这个没有完成的话,触摸是无效的。
scheduleOnce(schedule_selector(My2048Scene::Myrebui),0.2f); scheduleOnce(schedule_selector(My2048Scene::Mytouchflag),0.3f);
rebuil 是Build函数的 延时调用,
touchflag 则是让触摸能被承认。
void My2048Scene::Myrebui(float dt) { build(); } void My2048Scene::Mytouchflag(float dt) { Go_touch=true; }
只需要把Go_touch 放在 ccTouchBegan里面就可以了。
bool My2048Scene::ccTouchBegan(CCTouch *pTouch,CCEvent *pEvent) { //开始触摸 if(Go_touch==false)return false; MoveFlag=0; startP=pTouch->getLocation(); return true; }
不过得记得在 Scene的init 的时候需要 初始化 Go_touch 为 true。不然没法判断触摸。
完整的 2048Scene.h
#pragma once #include "cocos2d.h" #include <queue> using namespace std; using namespace cocos2d; class My2048Scene:public CCLayer { public: My2048Scene(); ~My2048Scene(); static CCScene * scene(); void menuCall_restart(CCObject *pSender); void menuCall_return(CCObject *pSender); virtual void build(); virtual bool init(); virtual void My2048Move(); virtual bool My2048Cheack(); virtual bool My2048union(int m); void Myredis(float dt); void Myrebui(float dt); void Mytouchflag(float dt); void Mydisplay(); void Mypointadd(); void My2048over(); void My2048win(); long long My2048Point; int My2048[5][5]; CCLabelTTF *Mypoint; CCSize Mysize; CCSize size; CCSprite *Overboard; void onEnter(); void onExit(); virtual bool ccTouchBegan(CCTouch *pTouch,CCEvent *pEvent); virtual void ccTouchMoved(CCTouch *pTouch,CCEvent *pEvent); virtual void ccTouchEnded(CCTouch *pTouch,CCEvent *pEvent); CREATE_FUNC(My2048Scene); private: bool MoveFlag; CCPoint startP,thendP; float move_dis; void get_ture_callback(); int Myreverse; bool MyWin; queue<int>Myque; int b[4][4]; bool Go_touch; };
完整的2048Scene.cpp
# include "2048Scene.h" # include "MyScene.h" # include <cstring> # include <ctime> # include <queue> using namespace std; #define FOR(i,a,b) for(int i=a;i<b;i++) const int xx[]= {0,0,-1,1}; const int yy[]= {-1,1,0,0}; CCSprite *g[16]; const int PP[]= {0,2,4,8,16,32,64,128,256,512,1024,2048}; My2048Scene::My2048Scene() { } My2048Scene::~My2048Scene() { } CCScene* My2048Scene::scene() { // 'scene' is an autorelease object CCScene *scene = CCScene::create(); // 'layer' is an autorelease object My2048Scene *layer = My2048Scene::create(); // add layer as a child to scene scene->addChild(layer); // return the scene return scene; } bool My2048Scene::init() { size.width=480,size.height=854; move_dis=100; CCSprite *background_2048=CCSprite::create("homepage.png"); background_2048->setPosition(ccp(size.width/2,size.height*0.5)); this->addChild(background_2048); CCSprite *coord_2048=CCSprite::create("2048-coord.png"); coord_2048->setPosition(ccp(size.width/2,size.height*0.5)); this->addChild(coord_2048); //CCLOG("%f %f\n",size.width,size.height); Mysize=coord_2048->getPosition(); Mysize.width-=150,Mysize.height-=10; //CCLOG("%f %f\n",Mysize.width,Mysize.height); /*int i=0,j=1; CCSprite *sp1=CCSprite::create("5.png"); sp1->setPosition(ccp(Mysize.width+100*j,Mysize.height-100*i)); this->addChild(sp1);*/ CCLabelTTF *My_restart_tmp =CCLabelTTF :: create("restart" ,"FZNHT.ttf",40); CCMenuItemLabel *My_restart =CCMenuItemLabel::create(My_restart_tmp,this,menu_selector(My2048Scene::menuCall_restart)); My_restart->setPosition(ccp(size.width/3*2,size.height*0.6)); CCLabelTTF *My_return_tmp =CCLabelTTF :: create("return" ,"FZNHT.ttf",40); CCMenuItemLabel *My_return =CCMenuItemLabel::create(My_return_tmp,this,menu_selector(My2048Scene::menuCall_return)); My_return->setPosition(ccp(size.width/3,size.height*0.6)); CCMenu *menu =CCMenu::create(My_restart,My_return,NULL); menu->setPosition(CCPointZero); this->addChild(menu); CCLabelTTF *Mypoint_borad=CCLabelTTF::create("Point :","FZNHT.ttf",40); Mypoint_borad->setColor(ccc3(255,255,0)); Mypoint_borad->setPosition(ccp(size.width/5,size.height*0.675)); this->addChild(Mypoint_borad); Mypoint=CCLabelTTF::create("0","FZNHT.ttf",40); Mypoint->setColor(ccc3(0,255,255)); //Mypoint->setAnchorPoint(ccp(size.width/5*4,size.height*0.675)); Mypoint->setPosition(ccp(size.width/5*4,size.height*0.675)); this->addChild(Mypoint); FOR(m,0,16) { int i=m/4,j=m%4; My2048[i][j]=0; CCString *str=CCString::createWithFormat("%d.png",My2048[i][j]); g[i*4+j]=CCSprite::create(str->getCString()); g[i*4+j]->setPosition(ccp(Mysize.width+100*j,Mysize.height-100*i)); this->addChild(g[i*4+j]); //初始化全部覆盖透明图片 } My2048Point=0; MyWin=false; Go_touch=true; time_t t; time(&t); t%=1000; t*=t; srand(t); build(); build(); //setTouchEnabled(false); setTouchEnabled(true); //设置触摸 Myreverse=0; //My2048win(); Overboard=NULL; return true; } void My2048Scene:: build() { FOR(k,0,16) { int i=k/4,j=k%4; if(My2048[i][j]==0) Myque.push(k); } int m=CCRANDOM_0_1()*(Myque.size()-1)+1; //CCLOG("%d ",m); int tmp; while (m--&&!Myque.empty()) { tmp=Myque.front(); Myque.pop(); } while(!Myque.empty())Myque.pop(); m=tmp; int i=m/4,j=m%4; int or_2_4=CCRANDOM_0_1()*10; if(or_2_4>=8) My2048[i][j]=2; else My2048[i][j]=1; //随机生成2或者4 CCString *str=CCString::createWithFormat("%d.png",My2048[i][j]); g[i*4+j]->cleanup(); g[i*4+j]->initWithFile(str->getCString()); g[i*4+j]->setPosition(ccp(Mysize.width+100*j,Mysize.height-100*i)); CCActionInterval *build_1=CCScaleTo::create(0.2f,1.5f); CCActionInterval *build_2=CCScaleTo::create(0.2f,1.0f); CCActionInterval *build_action=CCSequence::create(build_1,build_2,NULL); g[i*4+j]->runAction(build_action); } void My2048Scene::Myredis(float dt) { FOR(i,0,4) FOR(j,0,4) { CCString *str=CCString::createWithFormat("%d.png",My2048[i][j]); g[i*4+j]->cleanup(); g[i*4+j]->initWithFile(str->getCString()); g[i*4+j]->setPosition(ccp(Mysize.width+100*j,Mysize.height-100*i)); } } void My2048Scene::Mydisplay() { FOR(i,0,4) FOR(j,0,4) { if(b[i][j]==-1)continue; int x=b[i][j]/4,y=b[i][j]%4; CCActionInterval *move_to=CCMoveTo::create(0.2f,ccp(Mysize.width+100*y,Mysize.height-100*x)); g[i*4+j]->runAction(move_to); } scheduleOnce(schedule_selector(My2048Scene::Myredis),0.2f); } bool My2048Scene::My2048union(int m) { //合并 bool flag=false; bool pointadd=false; memset(b,-1,sizeof(b)); if(m==1)//l { FOR(i,0,4) { FOR(j,0,4) { if(My2048[i][j]==0) for(int k=j+1; k<4; k++) { if(My2048[i][k]==0)continue; int tmp=My2048[i][j]; My2048[i][j]=My2048[i][k]; My2048[i][k]=tmp; //Mydisplay(i,j,i,k); b[i][k]=i*4+j; flag=true; break; } for(int k=j+1; k<4; k++) { if(My2048[i][k]==0)continue; else if(My2048[i][k]==My2048[i][j]) { My2048[i][j]++; My2048[i][k]=0; My2048Point+=PP[My2048[i][j]]; //Mydisplay(i,j,i,k); b[i][k]=i*4+j; flag=true; pointadd=true; break; } else break; } } } } else if(m==2)//r { FOR(i,0,4) { for(int j=3; j>=0; j--) { if(My2048[i][j]==0) for(int k=j-1; k>=0; k--) { if(My2048[i][k]==0)continue; int tmp=My2048[i][j]; My2048[i][j]=My2048[i][k]; My2048[i][k]=tmp; //Mydisplay(i,j,i,k); b[i][k]=i*4+j; flag=true; break; } for(int k=j-1; k>=0; k--) { if(My2048[i][k]==0)continue; else if(My2048[i][k]==My2048[i][j]) { My2048[i][j]++; My2048[i][k]=0; My2048Point+=PP[My2048[i][j]]; //Mydisplay(i,j,i,k); b[i][k]=i*4+j; flag=true; pointadd=true; break; } else break; } } } } else if(m==3)//d { FOR(i,0,4) { for(int j=3; j>=0; j--) { if(My2048[j][i]==0) for(int k=j-1; k>=0; k--) { if(My2048[k][i]==0)continue; int tmp=My2048[j][i]; My2048[j][i]=My2048[k][i]; My2048[k][i]=tmp; //Mydisplay(j,i,k,i); b[k][i]=j*4+i; flag=true; break; } for(int k=j-1; k>=0; k--) { if(My2048[k][i]==0)continue; else if(My2048[k][i]==My2048[j][i]) { My2048[j][i]++; My2048[k][i]=0; My2048Point+=PP[My2048[j][i]]; //Mydisplay(j,i,k,i); b[k][i]=j*4+i; pointadd=true; flag=true; break; } else break; } } } } else if(m==4)//u { FOR(i,0,4) { FOR(j,0,4) { if(My2048[j][i]==0) for(int k=j+1; k<4; k++) { if(My2048[k][i]==0)continue; int tmp=My2048[j][i]; My2048[j][i]=My2048[k][i]; My2048[k][i]=tmp; //Mydisplay(j,i,k,i); b[k][i]=j*4+i; flag=true; break; } for(int k=j+1; k<4; k++) { if(My2048[k][i]==0)continue; else if(My2048[k][i]==My2048[j][i]) { My2048[j][i]++; My2048[k][i]=0; My2048Point+=PP[My2048[j][i]]; //Mydisplay(j,i,k,i); b[k][i]=j*4+i; pointadd=true; flag=true; break; } else break; } } } } if(flag) { Go_touch=false; Mydisplay(); } if(pointadd) { Mypointadd(); } return flag; } void My2048Scene::Mypointadd() { //加分 Mypoint->setString(CCString::createWithFormat("%lld",My2048Point)->getCString()); } void My2048Scene::Myrebui(float dt) { //build延时触发 build(); } void My2048Scene::Mytouchflag(float dt) { //能够触摸 Go_touch=true; } void My2048Scene::My2048Move() { // 开始主动作 bool flag=false; if(Myreverse==0) return ; else flag=My2048union(Myreverse); if(flag) { //等待move_to 完成后再执行 scheduleOnce(schedule_selector(My2048Scene::Myrebui),0.2f); scheduleOnce(schedule_selector(My2048Scene::Mytouchflag),0.3f); } else return; bool gameflag=false; gameflag=My2048Cheack(); if(MyWin) { //system("pause"); CCLOG("Win\n"); My2048win(); } else if(!gameflag) { //system("pause"); CCLOG("over\n"); My2048over(); } } void My2048Scene::My2048win() { //游戏胜利画面 Overboard=CCSprite::create("overboard.png"); Overboard->setPosition(ccp(Mysize.width+150,Mysize.height-150)); this->addChild(Overboard,100); CCLabelTTF *Win_flag=CCLabelTTF::create("YOU WIN","FZNHT.ttf",40); Win_flag->setColor(ccc3(255,0,0)); CCSize tmp=Overboard->getPosition(); Win_flag->setPosition(ccp(tmp.width-125,tmp.height-125)); Overboard->addChild(Win_flag); CCLabelTTF *board_point=CCLabelTTF::create("0","FZNHT.ttf",30); board_point->setString(CCString::createWithFormat("%lld",My2048Point)->getCString()); board_point->setColor(ccc3(0,0,0)); board_point->setPosition(ccp(tmp.width/2,tmp.height/6)); Overboard->addChild(board_point); this->setTouchEnabled(false); } void My2048Scene::My2048over() { //游戏结束画面 Overboard=CCSprite::create("overboard.png"); Overboard->setPosition(ccp(Mysize.width+150,Mysize.height-150)); this->addChild(Overboard,100); CCLabelTTF *Lost_flag=CCLabelTTF::create("YOU LOST","FZNHT.ttf",40); Lost_flag->setColor(ccc3(0,255,255)); CCSize tmp=Overboard->getPosition(); Lost_flag->setPosition(ccp(tmp.width-125,tmp.height-125)); Overboard->addChild(Lost_flag); CCLabelTTF *board_point=CCLabelTTF::create("0","FZNHT.ttf",30); board_point->setString(CCString::createWithFormat("%lld",My2048Point)->getCString()); board_point->setColor(ccc3(0,0,0)); board_point->setPosition(ccp(tmp.width/2,tmp.height/6)); Overboard->addChild(board_point); this->setTouchEnabled(false); } bool My2048Scene::My2048Cheack() { //检查胜利或者失败 bool flag=false; FOR(i,0,4) FOR(j,0,4) { if(My2048[i][j]==11)MyWin=true; } FOR(i,0,4) FOR(j,0,4) { FOR(k,0,4) { int x=i+xx[k]; int y=j+yy[k]; if(x<0||y<0||x>=4||y>=4)continue; if(!My2048[i][j]||My2048[i][j]==My2048[x][y]) return true; } } return false; } void My2048Scene::get_ture_callback() { //判断触摸方向 Myreverse=0; CCPoint ans=ccpSub(startP,thendP); if(ans.x*ans.x+ans.y*ans.y<move_dis*move_dis)return; if (fabs(ans.x)>fabs(ans.y)) { if (ans.x>move_dis) { //CCLOG("l"); Myreverse=1; } else if(ans.x<-move_dis) { //CCLOG("r"); Myreverse=2; } else { return; } } else { if (ans.y>move_dis) { //CCLOG("d"); Myreverse=3; } else if(ans.y<-move_dis) { //CCLOG("u"); Myreverse=4; } else return; } if(Myreverse==0)return; MoveFlag=1; My2048Move(); } void My2048Scene::onEnter() { CCLayer::onEnter(); CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(this,0,false); } void My2048Scene::onExit() { CCLayer::onExit(); CCDirector::sharedDirector()->getTouchDispatcher()->removeDelegate(this); } bool My2048Scene::ccTouchBegan(CCTouch *pTouch,CCEvent *pEvent) { //开始触摸 if(Go_touch==false)return false; MoveFlag=0; startP=pTouch->getLocation(); return true; } void My2048Scene::ccTouchMoved(CCTouch *pTouch,CCEvent *pEvent) { //触摸点移动中 if(MoveFlag)return; thendP=pTouch->getLocation(); Myreverse=0; get_ture_callback(); } void My2048Scene::ccTouchEnded(CCTouch *pTouch,CCEvent *pEvent) { //触摸结束 if(MoveFlag)return; thendP=pTouch->getLocation(); Myreverse=0; get_ture_callback(); } void My2048Scene::menuCall_restart(CCObject *pSender) { //restart 菜单 if(Overboard!=NULL) Overboard->removeFromParentAndCleanup(true); FOR(i,0,16) g[i]->removeFromParentAndCleanup(true); CCScene *temps=My2048Scene::scene(); CCDirector::sharedDirector()->replaceScene(temps); } void My2048Scene::menuCall_return(CCObject *pSender) { //return 菜单 CCScene *temps=MyScene::scene(); CCDirector::sharedDirector()->replaceScene(temps); }
以及 :My2048_beta_test.apk(论程序员的美术水平……醉了,被评UI丑到爆。)
PS:基友说给我画的图……我觉得我要等很久了……
http://yun.baidu.com/share/link?shareid=1360105856&uk=2065698893
Cocos2d-x 个人笔记 《2048》(5)