- - 想做特效。 我写的合并方法是调用 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。不然没法判断触摸。
还有就是不能让检测游戏结束的 执行在 Build之前,(Build延时了。)
所以 检测游戏结束的 函数也要延时。
scheduleOnce(schedule_selector(My2048Scene::gameover),0.2f);
void My2048Scene::gameover(float dt)
{
bool gameflag=false;
gameflag=My2048Cheack();
if(MyWin)
My2048win();
else if(!gameflag)
My2048over();
}
完整的 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 gameover(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::gameover(float dt)
{
bool gameflag=false;
gameflag=My2048Cheack();
if(MyWin)
{
//system("pause");
//CCLOG("Win\n");
My2048win();
}
else if(!gameflag)
{
//system("pause");
//CCLOG("over\n");
My2048over();
}
}
void My2048Scene::My2048Move()
{
// 开始主动作
bool flag=false;
if(Myreverse==0)
return ;
else
flag=My2048union(Myreverse);
if(!flag)
return;
//等待move_to 完成后再执行
scheduleOnce(schedule_selector(My2048Scene::Myrebui),0.2f);
scheduleOnce(schedule_selector(My2048Scene::Mytouchflag),0.3f);
scheduleOnce(schedule_selector(My2048Scene::gameover),0.2f);
}
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]==0||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