首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Java“突围”克隆:挂起和恢复线程

Java“突围”克隆:挂起和恢复线程
EN

Stack Overflow用户
提问于 2013-11-24 08:25:03
回答 1查看 647关注 0票数 2

在一个简介CS课程中,我试图复制Java中的“突围”。游戏已经完成了99%,所以我想我应该增加一些额外的。

我想添加的一件事是使用空格键暂停和恢复的能力。我添加了一个布尔"isPaused“变量,并在每次调用game.resume()和game.suspend()时更改它的值。然后,当用户点击空格键时,我使用KeyAdapter告诉程序根据"isPaused“值恢复和暂停。这似乎在大多数时间起作用,但偶尔需要两下空格键。我对代码进行了广泛的研究,对这个问题一窍不通。这似乎通常发生在一个新的水平开始。因此,我将发布"Board.java“文件中的代码,该文件包含游戏逻辑和当前的问题。谢谢!密码在下面。

这个“板”类处理所有游戏逻辑,并在屏幕上显示项目。

代码语言:javascript
复制
//imports
import java.awt.*;
import javax.swing.*;
import java.util.Random;
import java.lang.Thread;
import javax.sound.sampled.*;
import java.io.*;
import java.awt.event.*;
import java.util.ArrayList;

//class definition
public class Board extends JPanel implements Runnable, Constants {
//variables
Paddle paddle;
Ball ball;
Brick[][] brick = new Brick[10][5];
int score = 0, lives = 5, bricksLeft = 50, waitTime = 3, xSpeed, withSound, level = 1;
String playerName;
Thread game;
String songFile = "music/Start.wav";
Color brickColor = new Color(0,0,255);
ArrayList<Item> items = new ArrayList<Item>();
boolean isPaused = true;

//constructor
public Board(int width, int height) {
    super.setSize(width, height);
    addKeyListener(new BoardListener());
    setFocusable(true);

    makeBricks();
    paddle = new Paddle(width/2, height-(height/10), width/7, height/50, Color.BLACK);
    ball = new Ball(BALL_X_START, BALL_Y_START, BALL_WIDTH, BALL_HEIGHT, Color.BLACK);

    //Get the player's name
    playerName = JOptionPane.showInputDialog(null, "Enter your name:", "Name", JOptionPane.INFORMATION_MESSAGE);
    if (playerName == null) {
        System.exit(0);
    }

    //Start Screen that displays information and asks if the user wants music or not
    String[] options = {"Yes", "No"};
    withSound = JOptionPane.showOptionDialog(null, "Brick Breaker, Version 1.0\nBy Ty-Lucas Kelley, for CSC 171 Fall 2013\nAll credit for the music goes to the SEGA Corporation.\n\n\nControls: Press spacebar to start, and use the arrow keys to move.\n\n\nWould you like to play with the music on?", "Introduction", JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, options[1]);
    playMusic(songFile, withSound);

    game = new Thread(this);
    game.start();
    stop();
}

//fills the array of bricks
public void makeBricks() {
    for(int i = 0; i < 10; i++) {
        for(int j = 0; j < 5; j++) {
            Random rand = new Random();
            int itemType = rand.nextInt(3) + 1;
            int numLives = 3;
            brick[i][j] = new Brick(i * BRICK_WIDTH, (j * BRICK_HEIGHT) + (BRICK_HEIGHT / 2), BRICK_WIDTH - 5, BRICK_HEIGHT - 4, brickColor, numLives, itemType);
        }
    }
}

//starts the thread
public void start() {
    game.resume();
    isPaused = false;
}

//stops the thread
public void stop() {
    game.suspend();
    isPaused = true;
}

//ends the thread
public void destroy() {
    game.resume();
    isPaused = false;
    game.stop();
}

//runs the game
public void run() {
    xSpeed = 1;
    while(true) {
        int x1 = ball.getX();
        int y1 = ball.getY();

        //Makes sure speed doesnt get too fast/slow
        if (Math.abs(xSpeed) > 1) {
            if (xSpeed > 1) {
                xSpeed--;
            }
            if (xSpeed < 1) {
                xSpeed++;
            }
        }

        checkPaddle(x1, y1);
        checkWall(x1, y1);
        checkBricks(x1, y1);
        checkLives();
        checkIfOut(y1);
        ball.move();
        dropItems();
        checkItemList();
        repaint();

        try {
            game.sleep(waitTime);
        } catch (InterruptedException ie) {
            ie.printStackTrace();
        }
    }
}

public void addItem(Item i) {
    items.add(i);
}

public void dropItems() {
    for (int i = 0; i < items.size(); i++) {
        Item tempItem = items.get(i);
        tempItem.drop();
        items.set(i, tempItem);
    }
}

public void checkItemList() {
    for (int i = 0; i < items.size(); i++) {
        Item tempItem = items.get(i);
        if (paddle.caughtItem(tempItem)) {
            items.remove(i);
        }
        else if (tempItem.getY() > WINDOW_HEIGHT) {
            items.remove(i);
        }
    }
}

public void checkLives() {
    if (bricksLeft == 0) {
        ball.reset();
        bricksLeft = 50;
        makeBricks();
        lives++;
        level++;
        repaint();
        stop();
    }
    if (lives == 0) {
        repaint();
        stop();
    }
}

public void checkPaddle(int x1, int y1) {
    if (paddle.hitLeft(x1, y1)) {
        ball.setYDir(-1);
        xSpeed = -1;
        ball.setXDir(xSpeed);
    }
    else if (paddle.hitRight(x1, y1)) {
        ball.setYDir(-1);
        xSpeed = 1;
        ball.setXDir(xSpeed);
    }

    if (paddle.getX() <= 0) {
        paddle.setX(0);
    }
    if (paddle.getX() + paddle.getWidth() >= getWidth()) {
        paddle.setX(getWidth() - paddle.getWidth());
    }
}

public void checkWall(int x1, int y1) {
    if (x1 >= getWidth() - ball.getWidth()) {
        xSpeed = -Math.abs(xSpeed);
        ball.setXDir(xSpeed);
    }
    if (x1 <= 0) {
        xSpeed = Math.abs(xSpeed);
        ball.setXDir(xSpeed);
    }
    if (y1 <= 0) {
        ball.setYDir(1);
    }
    if (y1 >= getHeight()) {
        ball.setYDir(-1);
    }
}

public void checkBricks(int x1, int y1) {
    for (int i = 0; i < 10; i++) {
        for (int j = 0; j < 5; j++) {
            if (brick[i][j].hitBottom(x1, y1)) {
                ball.setYDir(1);
                if (brick[i][j].isDestroyed()) {
                    bricksLeft--;
                    score += 50;
                    addItem(brick[i][j].item);
                }
            }
            if (brick[i][j].hitLeft(x1, y1)) {
                xSpeed = -xSpeed;
                ball.setXDir(xSpeed);
                if (brick[i][j].isDestroyed()) {
                    bricksLeft--;
                    score += 50;
                    addItem(brick[i][j].item);
                }
            }
            if (brick[i][j].hitRight(x1, y1)) {
                xSpeed = -xSpeed;
                ball.setXDir(xSpeed);
                if (brick[i][j].isDestroyed()) {
                    bricksLeft--;
                    score += 50;
                    addItem(brick[i][j].item);
                }
            }
            if (brick[i][j].hitTop(x1, y1)) {
                ball.setYDir(-1);
                if (brick[i][j].isDestroyed()) {
                    bricksLeft--;
                    score += 50;
                    addItem(brick[i][j].item);
                }
            }
        }
    }
}

public void checkIfOut(int y1) {
    if (y1 > PADDLE_Y_START) {
        lives--;
        score -= 100;
        ball.reset();
        repaint();
        stop();
    }
}

//plays music throughout game if user wants to
public void playMusic(String song, int yesNo) {
    if (yesNo == 1) {
        return;
    }
    else if (yesNo == -1) {
        System.exit(0);
    }
    try {
        AudioInputStream audio = AudioSystem.getAudioInputStream(new File(song).getAbsoluteFile());
        Clip clip = AudioSystem.getClip();
        clip.open(audio);
        clip.loop(Clip.LOOP_CONTINUOUSLY); 
    } catch (Exception e) {
        e.printStackTrace();
    }
}

//fills the board
@Override
public void paintComponent(Graphics g) {
    super.paintComponent(g);
    paddle.draw(g);
    ball.draw(g);

    for (int i = 0; i < 10; i++) {
        for (int j = 0; j < 5; j++) {
            brick[i][j].draw(g);
        }
    }
    g.setColor(Color.BLACK);
    g.drawString("Lives: " + lives, 10, getHeight() - (getHeight()/10));
    g.drawString("Score: " + score, 10, getHeight() - (2*(getHeight()/10)) + 25);
    g.drawString("Level: " + level, 10, getHeight() - (3*(getHeight()/10)) + 50);
    g.drawString("Player: " + playerName, 10, getHeight() - (4*(getHeight()/10)) + 75);

    for (Item i: items) {
        i.draw(g);
    }

    if (lives == 0) {
        int heightBorder = getHeight()/10;
        int widthBorder = getWidth()/10;
        g.setColor(Color.BLACK);
        g.fillRect(widthBorder, heightBorder, getWidth() - (2 * widthBorder), getHeight() - (2 * heightBorder ));
        g.setColor(Color.WHITE);
        g.drawString("Game Over! Click the Spacebar twice to start over.", getWidth()/5, getHeight()/2);
    }
}

public String playerInfo() {
    return rank(score) + "." + " Name: " + playerName + ", Score: " + score;
}

public int rank(int score) {
    //check to see where this player falls on the list of saved games by reading from file
    return 0;
}

public void saveGame() {
    if (rank(score) >= 10) {
        return;
    }
    //save this game to HighScores.txt
}

public void printScores() {
    //print to paintComponent method. replace current 'game over' string
}

//Private class that handles gameplay and controls
private class BoardListener extends KeyAdapter {
    public void keyPressed(KeyEvent ke) {
        int key = ke.getKeyCode();
        if (key == KeyEvent.VK_SPACE) {
            if (lives > 0) {
                if (!isPaused) {
                    stop();
                }
                else {
                    start();
                }
            }
            else {
                paddle.setWidth(getWidth()/7);
                lives = 5;
                score = 0;
                bricksLeft = 50;
                level = 1;
                makeBricks();
                isPaused = true;
                for (int i = 0; i < 10; i++) {
                    for (int j = 0; j < 5; j++) {
                        brick[i][j].setDestroyed(false);
                    }
                }
            }
        }
        if (key == KeyEvent.VK_LEFT) {
            paddle.setX(paddle.getX() - 50);
        }
        if (key == KeyEvent.VK_RIGHT) {
            paddle.setX(paddle.getX() + 50);
        }
    }
    public void keyReleased(KeyEvent ke) {
        int key = ke.getKeyCode();
        if (key == KeyEvent.VK_LEFT) {
            paddle.setX(paddle.getX());
        }
        if (key == KeyEvent.VK_RIGHT) {
            paddle.setX(paddle.getX());
        }
    }
}

}

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2013-11-24 08:33:46

您的问题很可能是某种并发问题。您可能希望将变量从boolean转换为AtomicBoolean,并在suspendresume方法中使用synchronized (game)

此外,您不应该使用Thread.suspendThread.resume方法。阅读他们的JavaDoc以获得更多信息。

如下所示:

代码语言:javascript
复制
...
AtomicBoolean isPaused = new AtomicBoolean(false);
...

private void gamePause() {
   synchronized(game) {
      game.isPaused.set(true);
      game.notify();
   }
}

private void gameContinue() {
   synchronized(game) {
      game.isPaused.set(false);
      game.notify();
   }
}
...

然后在您处理循环的地方:

代码语言:javascript
复制
...
public void run() {
  xSpeed = 1;
  while(true) {
    synchronized(game) {
      while(game.isPaused().get()) {
         try {
            Thread.sleep(1000);
         } catch (InterruptedException iex) {
            // This most likely means your JVM stops. Maybe log the Exception.
            game.destroy();
            return;
         }
      }
      int x1 = ball.getX();
      int y1 = ball.getY();
      ...
      }
    }
  }
}

也在checkLives方法中。(据我所知,checkLives只在运行时被调用,如果是这样的话,这已经在synchronized(game)块中了。如果不是,您还必须在synchronized的周围添加stop()

代码语言:javascript
复制
public void checkLives() {
    if (bricksLeft == 0) {
        ...
        if(!game.isPaused().get())
           stop();
    }
    if (lives == 0) {
        repaint();
        if(!game.isPaused().get())
           stop();
    }
}

问题是checkLives()调用了stop(),这会触发isPaused被翻转。如果在激活KeyListener的同时,它探测isPaused,认为游戏暂停并继续运行,那么您必须再次点击空间才能继续。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/20172562

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档