Как я могу использовать Thread.sleep()?

#java #android #thread-sleep

#java #Android #поток-сон

Вопрос:

Я создаю памятную игру для школьного проекта, и у меня проблема с моим Thread.sleep.

Когда игрок возвращает две карты, программа проверяет, идентичны ли они. Если это не так, то они поворачиваются лицевой стороной вниз. Поскольку программа делает это почти мгновенно, я бы хотел сделать паузу, чтобы у игрока было время увидеть вторую карту. Проблема в том, что разрыв происходит до того, как карта поворачивается

 if (deck1.contains(carte)) {
    if (carte.getEtat() == 0) {
        carte.setEtat(1);
        cartesRetournees1.add(carte);
        majAffichage(carte);

        try {
            Thread.sleep(500);
        } catch (InterruptedException ie) {
            ie.printStackTrace();
        }
    }
    if (cartesRetournees1.size() == 2) {
        int nouveauEtat = 0;
        if (cartesRetournees1.get(0).getMotif() == cartesRetournees1.get(1).getMotif()) {
            nouveauEtat = -1;
            this.nbPairsTrouvees  ;
        }

        cartesRetournees1.get(0).setEtat(nouveauEtat);
        cartesRetournees1.get(1).setEtat(nouveauEtat);

        majAffichage(cartesRetournees1.get(0));
        majAffichage(cartesRetournees1.get(1));
        cartesRetournees1.remove(1);
        cartesRetournees1.remove(0);

        if (nbPairsTrouvees == this.plateau.size()) System.out.println("GAGNE !");
    }
}
  

В моей игре Thread.sleep работает перед majAffichage(carte), и я не понимаю, почему.
Я не знаю, как решить мою проблему, и если вы, ребята, можете мне помочь, я был бы очень благодарен 🙂

Ответ №1:

Это из-за того, как работает пользовательский интерфейс и рисование. Внутри платформы Android в основном потоке существует гигантский цикл обработки сообщений. Одним из таких сообщений является сообщение о выводе. Экран отображается только при обработке этого сообщения. Сообщения могут обрабатываться только в верхней части цикла. Итак, если поток спит, он никогда не обрабатывает новые сообщения во время этого сна, и экран не будет обновляться.

Если вы хотите что-то сделать с такой задержкой, есть два варианта:

1) Вместо того, чтобы переходить в режим ожидания, отправьте Runnable в основной цикл с помощью postDelayed, чтобы runnable запускался в указанное вами время в будущем.

2) Используйте второй поток и запускайте в нем всю свою игровую логику, передавая ему сообщения при возникновении событий пользовательского интерфейса и передавая события обратно в основной поток, когда ему нужно рисовать.

Ответ №2:

Во-первых, вы приостанавливаете не основной поток, а фоновый поток, потому что вы не хотите замораживать все приложение.

Во-вторых, используйте System.sleep() вместо Thread.sleep(), потому что первый не генерирует исключение.

Ответ №3:

Спасибо за ваш ответ! Я создал второй поток.

 package com.example.jeudumemo;

import android.graphics.Canvas;

public class GameLoopThread extends Thread
{
    private final static int FRAMES_PER_SECOND = 30;

    private final static int SKIP_TICKS = 1000 / FRAMES_PER_SECOND;

    private final Game view; 
    private boolean running = false; 

    public GameLoopThread(Game view) {
        this.view = view;
    }

    public void setRunning(boolean run) {
        running = run;
    }

    @Override
    public void run()
    {
        long startTime;
        long sleepTime;

        while (running)
        {
            startTime = System.currentTimeMillis();

            synchronized (view.getHolder()) {view.update();}

            Canvas c = null;
            try {
                c = view.getHolder().lockCanvas();
                synchronized (view.getHolder()) {view.draw(c);}
            }
            finally
            {
                try {
                    if (c != null) {
                        view.getHolder().unlockCanvasAndPost(c);
                    }
                } catch(IllegalArgumentException iae) { iae.printStackTrace(); }
            }
            sleepTime = SKIP_TICKS-(System.currentTimeMillis() - startTime);
            try {
                if (sleepTime >= 0) {sleep(sleepTime);}
            }
            catch (Exception e) {}
        } 
    } 

} 
  

и я вызываю это в своем основном классе :

 @Override
    public void surfaceCreated(SurfaceHolder holder) {
        if(gameLoopThread.getState()==Thread.State.TERMINATED) {
            gameLoopThread=new GameLoopThread(this);
        }
        gameLoopThread.setRunning(true);
        gameLoopThread.start();
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        boolean retry = true;
        gameLoopThread.setRunning(false);
        while (retry) {
            try {
                gameLoopThread.join();
                retry = false;
            }
            catch (InterruptedException e) {}
        }
    }

public void controleJeu(Carte carte) {
        if(deck1.contains(carte)) {
            if (carte.getEtat() == 0) {
                carte.setEtat(1);
                cartesRetournees1.add(carte);
                majAffichage(carte);

            }
            if (cartesRetournees1.size() == 2) {
                try {
                    gameLoopThread.sleep(500);
                }catch(InterruptedException ie) { ie.printStackTrace(); }
                int nouveauEtat = 0;
                if (cartesRetournees1.get(0).getMotif() == cartesRetournees1.get(1).getMotif()) {
                    nouveauEtat = -1;
                    this.nbPairsTrouvees  ;
                }

                cartesRetournees1.get(0).setEtat(nouveauEtat);
                cartesRetournees1.get(1).setEtat(nouveauEtat);

                majAffichage(cartesRetournees1.get(0));
                majAffichage(cartesRetournees1.get(1));
                cartesRetournees1.remove(1);
                cartesRetournees1.remove(0);
            }
        }
        else if(deck2.contains(carte)) {
            if (carte.getEtat() == 0) {
                carte.setEtat(1);
                cartesRetournees2.add(carte);
                majAffichage(carte);
            }
            if (cartesRetournees2.size() == 2) {
                try {
                    gameLoopThread.sleep(500);
                }catch(InterruptedException ie) { ie.printStackTrace(); }
                int nouveauEtat = 0;
                if (cartesRetournees2.get(0).getMotif() == cartesRetournees2.get(1).getMotif()) {
                    nouveauEtat = -1;
                    this.nbPairsTrouvees  ;
                }

                cartesRetournees2.get(0).setEtat(nouveauEtat);
                cartesRetournees2.get(1).setEtat(nouveauEtat);

                majAffichage(cartesRetournees2.get(0));
                majAffichage(cartesRetournees2.get(1));
                cartesRetournees2.remove(1);
                cartesRetournees2.remove(0);
            }
        }
        if (nbPairsTrouvees == nbDeck*6) { showPopupVictoire(this); this.victory = true; }
        System.out.println(nbDeck);
    }

  

Моя проблема все еще продолжается. Я думаю, что я не использовал свой GameLoopThread, поскольку он должен использоваться. Есть замечания?