Search code examples
javaandroidcocos2d-android

How to execute function ONLY after all actions are finished in Cocos2d


Can you guys tell me how can I execute function updateTiles() ONLY after all nodes' actions in function slideTiles(String s) are finished? I tried adding some while loop but it freezes whole program. After running functions one after another the animations just don't show up.

public boolean ccTouchesEnded(MotionEvent event)
{
CGPoint location = CCDirector.sharedDirector().convertToGL(CGPoint.ccp(event.getX(), event.getY()));
x2=location.x; y2=location.y;

 float diffY = y1-y2;
 float diffX = x1-x2;

 if (Math.abs(diffX)>Math.abs(diffY)&&diffX<0)
     move="right";
 else if (Math.abs(diffX)>Math.abs(diffY)&&diffX>=0)
     move="left";
 else if (Math.abs(diffX)<=Math.abs(diffY)&&diffY<0)
     move="up";
 else if (Math.abs(diffX)<=Math.abs(diffY)&&diffY>=0)
     move="down";

 int row=(int)(y1/TILE_SQUARE_SIZE);
 int column=(int)(x1/TILE_SQUARE_SIZE);

 slideTiles(move);

 //wait for animations to finish
 int sum=0;
 boolean actionDone=false;
 while (!actionDone)
 {
     for (CCNode c : tilesNode.getChildren())
     {
         sum+=c.numberOfRunningActions();
     }

     //String s=sum+"";
     //statusLabel.setString(s);

     if (sum==0){
         actionDone=true;
         break;
     }

     sum=0;
 }

 updateTiles();




 return true;
 }

//////

public void slideTiles(String move)
{
//  Increment the moves label and animate the tile
CCBitmapFontAtlas moveslabel = (CCBitmapFontAtlas) getChildByTag(MOVES_LABEL_TAG);
moves++;

    moveslabel.runAction(CCSequence.actions(
            //CCDelayTime.action(0.25f),
            CCScaleTo.action(0.2f, 6/5f),
            //CCDelayTime.action(0.25f),
            CCScaleTo.action(0.2f, 5/6f)
            ));
    moveslabel.setString("Moves:\n  " + CCFormatter.format("%03d", moves ));

    if (move.equals("up"))
    {   
        for (int start=NUM_COLUMNS; start<2*NUM_COLUMNS; start++)
        for (int y=start; y<NUM_COLUMNS*NUM_ROWS; y+=NUM_COLUMNS)
        {
            if (tileNumbers[y]!=EMPTY)
            {
                for (int f=start-NUM_COLUMNS; f<y; f+=NUM_COLUMNS)
                {
                    if (tileNumbers[f]==EMPTY)
                    {   
                        //y->f
                        CGPoint moveTo = tilesNode.getChildByTag(f).getPosition();
                        CCMoveTo movetile = CCMoveTo.action(0.25f, moveTo);
                        CCSequence movetileSeq = CCSequence.actions(movetile);//CCCallFunc.action(this,"stopAction"));
                        tilesNode.getChildByTag(y).runAction(movetileSeq);

                        tileNumbers[f]=tileNumbers[y];
                        tileNumbers[y]=EMPTY;

                        break;
                    }
                }
            }
        }
    }

Edit: Is this kind of solution correct? It works surprisingly well.

 public boolean ccTouchesEnded(MotionEvent event)
 {   

 ...
 ...

 slideTiles(move);

 float time = 0.25f+0.05f; //0.25f is time of moveTo action for each tile
 CCDelayTime delay = CCDelayTime.action(time);
 CCCallFunc cA = CCCallFunc.action(this, "updateTiles");
 CCSequence se = CCSequence.actions(delay, cA);
 runAction(se);

 return true;

 }

Solution

  • Generally, you shouldn't use while loop to wait in UI thread , it will cause big problem you have saw it.

    You should use Thread to do this waiting job.

    new Thread(new Runnable() {
            @Override
            public void run() {
                 while(true){
                     //here you wait forever doesn't matter the UI thread.
                     if(everythingDone) {//here to add your condition
                          new Handler().post(new Runable() {
                              @Override
                              public void run() {
                                   //Here you can do what you want and will be done in UI Thread
                              }
                          });
                     }
                 }
            }
    }).start();