Java Thread.sleep заставляет мой ранее вызванный метод отменить

Название может быть неправильным, но я не мог придумать ничего другого, чтобы назвать этот вопрос.

Моя проблема связана с некоторым кодом Java, который я пишу, который сводит меня с ума. По сути, я пытаюсь сделать игру «карточная память», в которой у меня есть сетка карт 4X4; когда вы нажимаете на одну, она переворачивается, затем вы нажимаете на вторую, она переворачивается, и если это одна и та же карта, она исчезает, а если это разные карты, она переворачивает их обратно.

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

try{Thread.sleep(2000);}catch(InterruptedException ex) {}

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

Я собираюсь добавить весь код, который у меня есть ниже. Извините, что много, но я не знаю, какая часть актуальна.

Карта.java

import objectdraw.*;
import java.awt.Image;
import java.awt.image.*;
import java.io.*;
import javax.imageio.*;

public class Card {

  private int value;
  private VisibleImage imageFront, imageBack;

  public Card(int val, Location p, double w, double h, DrawingCanvas c) {

    value = val;
    String urlStr = "images/" + val + ".png";
    BufferedImage img = null, imgb = null;
    try {
      img = ImageIO.read(new File(urlStr));
      imgb = ImageIO.read(new File("images/card-back.png"));
    } catch(IOException ex) {}
    imageFront = new VisibleImage(img,p,w,h,c);
    imageFront.hide();
    imageBack = new VisibleImage(imgb,p,w,h,c);

  }

  public void flip() {
    if(imageFront.isHidden()) {
      imageFront.show();
      imageBack.hide();
    } else {
      imageBack.show();
      imageFront.hide();
    }
  }

  public Boolean contains(Location p) {
    if(imageFront.isHidden()) {
      return imageBack.contains(p);
    } else {
      return imageFront.contains(p);
    }
  }

  public void moveTo(double x, double y) {
    imageFront.moveTo(x,y);
    imageBack.moveTo(x,y);
  }

  public int getValue() {
    return value;
  }

  public void hide() {
    imageFront.hide();
    imageBack.hide();
  }

}

Сетка.java

import objectdraw.*;

public class Grid {

  private static final int ROWS = 4;
  private static final int COLS = 4;

  private Card[] cards = new Card[COLS * ROWS];

  public Grid(double cardW, double cardH, DrawingCanvas c) {

    int cnt = 0;
    Location p1 = new Location(0,0);
    Location p2 = new Location(0,(ROWS/2)*cardH);
    for(int i = 0; i < ROWS; i++) {

      for(int j = 0; j < COLS; j++) {

        // Set up 2 of the same card, one at cnt and one at cnt + cards.length/2
        if(cnt < cards.length/2) {

          cards[cnt] = new Card(cnt+1,p1,cardW,cardH,c);
          p1.translate(cardW,0);
          cards[cnt + cards.length/2] = new Card(cnt+1,p2,cardW,cardH,c);
          p2.translate(cardW,0);
          cnt++;

        }

      }

        p1.translate(-(cardW * COLS),cardH);
        p2.translate(-(cardW * COLS),cardH);

    }

  }

  private static int sel = -1;

  public void select(Location p) {

    for(int i = 0; i < cards.length; i++) {

      // Find the correct card
      if(cards[i].contains(p)) {

        if(sel == -1) {

          // This is the first card selected
          System.out.printf("\nThis is the first card selected");
          cards[i].flip();
          sel = i;
          break;

        } else {
          System.out.printf("\nThis is the second card");

          // They selected the same card
          if(i == sel) {
            break;
          } else {

            // This is the second card selected and it's unique
            // Flip it and check if they match. If they do, then hide both,
            // if they don't then flip both back
            cards[i].flip();

            if(cards[i].getValue() == cards[sel].getValue()) {
              try {
                remove(cards[i], cards[sel]);
              } catch(InterruptedException ex) {}
              sel = -1;
              break;
            } else {
              cards[i].flip();
              cards[sel].flip();
              sel = -1;
              break;
            }

          }

        }

      }

    } // for loop

  }

  public void remove(final Card card1, final Card card2) throws InterruptedException {
    new Thread() {
      public void run() {
        sleep(2000);
        card1.hide();
        card2.hide();
      }
    }.start();
  }

}

Клиент.java

import objectdraw.*;

public class Client extends WindowController {

  public static void main(String[]args) {
    new Client().startController(310,460);
  }

  Grid board;
  public void begin() { 
    board = new Grid(75,102,canvas);
  }

  public void onMouseClick(Location p) {
    board.select(p);
  }

}

Для справки: все это взято из библиотеки objectdraw.


person CaldwellYSR    schedule 14.06.2013    source источник


Ответы (1)


Я бы разделил логику select() и remove(). Именно здесь:

if(cards[i].getValue() == cards[sel].getValue()) {
    remove(cards[i], cards[sel]); //call the remove

И remove() запустит поток и удалит нужные значения:

public void remove(final Card card1, final Card card2) {
    new Thread() {
        @Override
        public void run() {
            try {
                sleep(2000);
            } catch (InterruptedException e) {
            }
            card1.hide();
            card2.hide();
        }
    }.start();
}

Таким образом, вы не блокируете поток пользовательского интерфейса (пользователь может видеть флип), и новый поток скроет карты через две секунды.

person darijan    schedule 14.06.2013
comment
Этот сон (2000) дает мне ошибку компиляции, в которой говорится, что он не объявлен брошенным. Я вижу, что он выбрасывается в заголовок метода удаления, но я все еще получаю ошибку компилятора. - person CaldwellYSR; 15.06.2013
comment
Вы должны поймать его где-нибудь. Вы можете написать блок try-catch внутри метода remove() или блок try-catch вокруг вызова метода remove. - person darijan; 15.06.2013
comment
Также сделано, сначала он сказал мне, что я выбрасываю исключение, но не ловлю его. Поэтому я поставил try-catch вокруг вызова remove() и попытался снова, но он говорит: ./Grid.java:95: error: unreported exception InterruptedException; must be caught or declared to be thrown sleep(2000); - person CaldwellYSR; 15.06.2013
comment
Не могли бы вы обновить код, чтобы увидеть, где мы сейчас находимся? - person darijan; 15.06.2013
comment
хорошо, я отредактировал свой код. Как оказалось, try-catch должен проходить sleep(). Извините, моя ошибка, я немного устал. И еще одно замечание, это сработает только при выпадении двух одинаковых карт. Для другого сценария (когда вы выбираете две разные карты) вам нужно будет сделать что-то подобное, только вместо .hide() для обеих карт вам нужно будет flip() - person darijan; 15.06.2013
comment
Эй, не извиняйся передо мной, я просто рад, что ты помогаешь! Не беспокойтесь о том, что я сказал в комментарии ранее, оказывается, у меня был лишний } каким-то образом, который я не уловил. - person CaldwellYSR; 15.06.2013
comment
Большое спасибо за всю помощь, это сработало чудесно. Вы должны указать ответ, что вам нужен метод удаления, а также новый метод переворачивания для случая, когда они выбрали две разные карты, так что это совершенно правильно, и я не чувствую себя плохо из-за того, что выбрал не полный ответ :) - person CaldwellYSR; 15.06.2013