Java - 如何在

时间:2018-03-20 14:28:32

标签: java android while-loop

我是Java的新手,我在Android Studio上制作了俄罗斯方块游戏。我试图做一个"暂停/开始"按钮,它不起作用。当我按下按钮PAUSE时,音乐和游戏停止(它按预期工作)。但是当我再次按下“开始”时,音乐会继续,但游戏不会恢复。

我做了一个功能"暂停" sleep()内有while,函数"重启"使用一个变为false的布尔值(这设置了while的条件) 这是我的代码:

private void pause() {
    ps=true;
    while(ps) {
        try {
            sleep(4000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

private void restart() {
    ps=false;
}

以下是我MainActivity的一部分:

public void pauseButton (View view) {

    if (ps == false) {
        ps=true;
        GameState.getInstance().setUserAction(UserAction.PAUSE);
        mediaPlayer.pause();
    } else {
        ps=false;
        GameState.getInstance().setUserAction(UserAction.START);
        mediaPlayer.start();
    }
}

这就是" Useraction.Pause / Start"正在做

case PAUSE:
    pause();
    break;
case START:
    restart();
    break;

如何让重启功能起作用?我需要制作"而#34;停止或者可能在此功能中停止睡眠,我不能...感谢您的帮助!

 public class GameThread extends Thread{


private Shape shape;

private Set<Block> remainingBlockSet = new HashSet<>();

private boolean isRunning = true;

private long time;

private char[] shapeTypes={'O', 'I', 'J', 'L', 'Z', 'S','T'};

private boolean ps = true;




 GameThread(){
    //La première pièce du jeu apparait
    spawnNewShape();
    //Initialisation du temps
    this.time = System.currentTimeMillis();

}


//----------------------------------------------------------------------------------------------
// METHODES DE GESTION DE LA THREAD
//----------------------------------------------------------------------------------------------


/**
 *Boucle événementielle
 */
@Override
public void run() {
    while (isRunning) {
        //On bouge la pièce en fonction des demande utilisateur (bouton préssé)
        processUserAction();

        //La pièce tombe
        processMoveDown();

        //On enlève les lignes remplie
        removeCompletedRows();

        //On effectue le rendu graphique
        RenderManager.getInstance().render(shape, remainingBlockSet);
    }
}







/**
 * Arret de la boucle événementielle
 */
 void stopRunning(){
    isRunning = false;
}


//----------------------------------------------------------------------------------------------
// METHODES DE GESTION DU JEU
//----------------------------------------------------------------------------------------------

/**
 * Traitement des actions utilisateur
 */
private void processUserAction()  {
    //On recupère la dernière action
    UserAction action = GameState.getInstance().getUserAction();
    switch (action) {
        case LEFT:
            moveLeft();
            break;
        case RIGHT:
            moveRight();
            break;
        case ROTATE:
            rotate();
            break;
        case FALL:
            fall();
            break;
        case PAUSE:
            pause();
            break;
        case RESUME:
            restart();
            break;


    }
    //On définit la dernière action à nulle
    GameState.getInstance().setUserAction(UserAction.NONE);

}




 // met en pause le jeu
  public void pause() {
   ps = true;
  while(ps) {
    try {
       sleep(5000);
   } catch (InterruptedException e) {
       e.printStackTrace();
   }
 }
 }

 // permet de relancer le jeu
 public void restart() {
    ps=false;

}







private void fall(){
    while(shape.canMoveDown(remainingBlockSet)){
        shape.moveDown();
    }
}

private void rotate(){
    shape.rotate(remainingBlockSet);
}

/**
 * Décale la pièce d'une case vers la gauche
 */
private void moveLeft(){
    shape.moveLeft(remainingBlockSet);
}

/**
 * Décale la pièce d'une case vers la droite
 */
private void moveRight(){
    shape.moveRight(remainingBlockSet);
}



/**
 * Décale la pièce d'une case vers le bas
 */
private void processMoveDown(){
    //Si le laps de temps n'est pas écoulé on ne fait rien
    long now = System.currentTimeMillis();
    if(now-time < GameConstants.TIME_LAPS){
        return;
    }
    //Sinon la pièce descend

    if(shape.canMoveDown(remainingBlockSet)){
        shape.moveDown();
    }
    else{
        processShapeCollision();
    }

    //On redéfinit le temps comme le temps actuel
    time = System.currentTimeMillis();
}

private void processShapeCollision(){
    remainingBlockSet.addAll(shape.getBlockList());
    spawnNewShape();
}

   /**
    * A partir d'un caractère choisis aléatoirement, cette methode 
  permet 
 de générer la pièce qui
   * lui est associé.
    */
  private void spawnNewShape(){
    int x = (GameConstants.COLUMNS/2)-2;
    int y = 0;
    char shapeType = chooseRandomShape();
    switch (shapeType){
        case 'O':
            this.shape = new OShape(x,y);
            break;
        case 'T':
            this.shape = new TShape(x,y);
            break;
        case 'S':
            this.shape = new SShape(x,y);
            break;
        case 'I':
            this.shape = new IShape(x,y);
            break;
        case 'L':
            this.shape = new LShape(x,y);
            break;
        case 'Z':
            this.shape = new ZShape(x,y);
            break;
        case 'J':
            this.shape = new JShape(x,y);
            break;
        default:
            //imposible
            break;

    }
}


/**
 * Cette methode génère aléatoirement un entier entre 0 et 7. Ce dernier permet ensuite de
 * séléctioner le caractère de la pièce à faire appraitre.
 * @return un caractère correspondant à la prochaine pièce à faire apparaitre.
 */
private char chooseRandomShape(){
    int x = (int) (Math.random() * shapeTypes.length);
    return shapeTypes[x];
}






private void removeCompletedRows() {
    for(int y = GameConstants.ROWS-1; y>0; y--){
        List<Block> line = getBlockLine(y);
        if (isLineCompleted(line)){
            //Log.i(TAG,"la ligne"+y+"est pleine :"+line);
            removeLine(line);
            moveDownAboveBlocks(y);
        }
    }

}

private List<Block> getBlockLine(int y) {
    List<Block> line = new ArrayList<>();
    for(Block block : remainingBlockSet){
        if(y == block.getY()){
            line.add(block);
        }
    }
    return line;
}


private boolean isLineCompleted(List<Block> line) {
    for(int x = 0; x< GameConstants.COLUMNS; x++){
        boolean found = false;
        for(Block block : line){
            if (block.getX() == x){
                found = true;
                break;
            }
        }
        if(!found) {
            return false;
        }
    }
    return true;
}


private void removeLine(List<Block> line){
    remainingBlockSet.removeAll(line);
}


private void moveDownAboveBlocks(int y){
    for(Block block : remainingBlockSet){
        if (block.getY()<y){
            block.moveDown();
        }
    }
}

}

2 个答案:

答案 0 :(得分:1)

你没有明确说过,但我认为UI在不同的线程中工作,所以你可以按暂停/重启按钮而不被正在运行的'while'循环阻止

您的代码未显示您如何定义ps变量 - 它是否不稳定? 我们可以看到这些代码是不同步的,因此不会放置任何内存障碍,在这种情况下(当ps不易变时)这个变量可能被运行while循环的线程“缓存”并且再也不会从内存重新读取

请确保它是易失性的 - 或者是AtomicBoolean,或者进行一些同步(除非暂停/启动中的所有操作都是幂等的,否则无论如何都不错)

请参阅此处了解更多详情: https://www.concretepage.com/java/thread-communication-using-volatile-in-java https://jorosjavajams.wordpress.com/volatile-vs-synchronized/

答案 1 :(得分:0)

你的问题可能是你“消耗”你暂停的线程几乎可以肯定是GUI线程(是的我说“gui”线程,因为只有一个,只要你拥有它,没有别的可以发生在GUI上)。永远不会推送第二个按钮,因为第一个按钮仍在使用线程。

每当您从系统收到任何通知时,只需采取非常快速的操作并立即将线程返回系统。 (例外情况是传递给“main”的线程,你可以永久保存)

除非你在gui线程上做整个游戏,否则循环也不会做任何事情来暂停你的游戏。换句话说,如果游戏在你的主线程上,锁定gui线程将不会阻止它。

当他们按下暂停按钮时,没有按钮调用pause(),而是设置ps = true并返回。让你的游戏循环(实际运行游戏的线程)在每次迭代时检查ps标志,并且只要ps为真就阻塞(你正在做它的方式很好,它只需要在其他代码中)。

ps也应该绝对不稳定,但这绝不是问题......