gpt4 book ai didi

Java "Breakout"克隆 : Suspending and resuming thread

转载 作者:行者123 更新时间:2023-11-30 11:25:45 24 4
gpt4 key购买 nike

对于 CS 入门类(class),我正在尝试用 Java 克隆“Breakout”。游戏已经完成 99%,所以我想我应该添加一些额外内容。

我想添加的一件事是使用空格键暂停和恢复的功能。我添加了一个 boolean “isPaused”变量并在每次调用 game.resume() 和 game.suspend() 时更改它的值。然后,我使用 KeyAdapter 告诉程序在用户按下空格键时根据“isPaused”值恢复和暂停。这似乎大部分时间都有效,但偶尔需要单击两次空格键。我已经广泛查看了代码,但无法解决问题。它似乎通常在新级别开始时发生。因此,我将发布“Board.java”文件中的代码,其中包含游戏逻辑和手头的问题。谢谢!代码如下。

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

//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());
}
}
}

最佳答案

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

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

像这样:

...
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();
}
}
...

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

...
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) block 中。如果不是,则必须添加 synchronized 也围绕 stop() 进行。

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,认为游戏已暂停并继续,因此您必须再次按空格键才能继续。

关于Java "Breakout"克隆 : Suspending and resuming thread,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20172562/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com