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。不然没法判断触摸。


还有就是不能让检测游戏结束的 执行在 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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值