-3

I was wondering if there was anyone that could look at my code, which is working so you can copy it and test it. what my problem is when the bottom bar counts down to the end it is supposed to end the game and then start it from the start again. But I think I am missing some code or my code just isn't written properly to do what i want it to do. Can anyone review it and see where I have gone wrong?

this is the game screen with all the GUI and the main():

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.Timer;

public class GameScreen {

    public static void main(String[] args) throws InterruptedException {
        final ProgressBar progressBar = new ProgressBar() {
            @Override
            public Dimension getPreferredSize() {
                return new Dimension(0, 30);
            }
        };
        final JFrame game = new JFrame();
        final JButton playButton, guessButton;
        final JPanel topPanel, gamePanel, rangePanel, guessPanel;
        final JTextArea gameStatus;
        final GuessingGame gameNumbers;
        final JLabel rangeLabel = new JLabel("Range: ");
        final JTextField playerName = new JTextField("", 20);
        final JTextField guessInput = new JTextField("", 20);

        gameStatus = new JTextArea(10, 20);
        JScrollPane scroll = new JScrollPane(gameStatus);
        gameNumbers = new GuessingGame();

        playButton = new JButton("Play");
        guessButton = new JButton("Guess");
topPanel = new JPanel();
        topPanel.setBackground(Color.yellow);
        topPanel.add(new JLabel("Player: "));
        topPanel.add(playerName);
        topPanel.add(playButton);

        rangePanel = new JPanel(new FlowLayout(FlowLayout.CENTER));
        rangePanel.add(rangeLabel, BorderLayout.CENTER);

        guessPanel = new JPanel();
        guessPanel.add(new JLabel("Guess: "));
        guessPanel.add(guessInput);
        guessPanel.add(guessButton);

        gamePanel = new JPanel(new BorderLayout());
        gamePanel.add(rangePanel, BorderLayout.NORTH);
        gamePanel.add(guessPanel);

        game.setTitle("Guessing Game");
        game.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        game.add(topPanel, BorderLayout.NORTH);
        game.add(scroll, BorderLayout.EAST);
        game.add(gamePanel, BorderLayout.CENTER);
        game.add(progressBar, BorderLayout.SOUTH);

        gameStatus.setFocusable(false);
        guessButton.setEnabled(false);
        guessInput.setEnabled(false);
        final Timer gameTimer = new Timer(1000, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent ae) {
                if (progressBar.getRunStatus() == false){
                    System.out.println("YAY");
                    guessButton.setEnabled(false);
                    guessInput.setEnabled(false);
                    playButton.setEnabled(true);
                    playerName.setEnabled(true);
                }
            }
        });
        playButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                if (playerName.getText().equals("")) {
                    JOptionPane.showMessageDialog(gamePanel, "Invalid Player Name");
                } else {
                    progressBar.repaint();
                    progressBar.StartTimer();
                    progressBar.setBackground(Color.gray);
                    gameNumbers.play();
                    gameStatus.append("Game Started!\n");
                    rangeLabel.setText(gameNumbers.toString());
                    guessButton.setEnabled(true);
                    guessInput.setEnabled(true);
                    playButton.setEnabled(false);
                    playerName.setEnabled(false);
                    gameTimer.start();
}
            }
        });
        guessButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                int playerGuess = Integer.parseInt(guessInput.getText());
                if (gameNumbers.isGuessCorrect(playerGuess)) {
                    gameStatus.append("Game Over!\n");
                    guessButton.setEnabled(false);
                    guessInput.setEnabled(false);
                    playButton.setEnabled(true);
                    playerName.setEnabled(true);
                    JOptionPane.showMessageDialog(gamePanel, "" + playerName.getText() + " wins!");
                }
                if (gameNumbers.isGuessAlmostCorrect(playerGuess)) {
                    gameStatus.append("very close!\n");
                    guessInput.requestFocus();
                }
                if (gameNumbers.isGuessLarger(playerGuess)) {
                    gameStatus.append("try something smaller...\n");
                    guessInput.requestFocus();
                }
                if (gameNumbers.isGuessSmaller(playerGuess)) {
                    gameStatus.append("try something larger...\n");
                    guessInput.requestFocus();
                }
            }
        });

        game.pack();
        game.setVisible(true); 
    }
;
}

This is my progressBar class:

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import javax.swing.JPanel;
import javax.swing.Timer;

class ProgressBar extends JPanel {

    public int minValue, maxValue;
    private int currentValue;
    public boolean running;
    private ArrayList<Rectangle> rects = new ArrayList<>();
    private int removeValue = 0;

    public ProgressBar() {
        setMaxValue();
        minValue = 0;
        this.running = true;
        currentValue = maxValue;
        this.setBackground(Color.green);
    }

    public void StartTimer() {
        setMaxValue();
        Timer progressBarCountDownTimer = new Timer(1000, new ActionListener() {
            int count = getMaxValue();
            @Override
            public void actionPerformed(ActionEvent ae) {

                if (getValue() == 0) {
                    setRunStatus(false);
                    ((Timer) ae.getSource()).stop();
                    System.out.println("YAY");
                    ;

                } else {
                    count--;
                    System.out.println(getValue());
                    setValue(count);
                }
                setValue(count);
            }
        });
        progressBarCountDownTimer.start();
    }
@Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g;

        rects.clear();
        int rectWidths = getWidth() / getMaxValue();
        int startingX = 0;

        for (int i = 0; i < (getMaxValue() - removeValue); i++) {
            rects.add(new Rectangle(startingX, 0, rectWidths, getHeight()));
            startingX += rectWidths;
        }

        for (Rectangle r : rects) {
            g2d.setColor(Color.green);
            g2d.fillRect(r.x, r.y, r.width, r.height);
        }
    }

    public int getValue() {
        return currentValue;
    }

    public void setRunStatus(boolean running) {
        this.running = running;
    }

    public boolean getRunStatus() {
        if (this.running == true) {
            return true;
        } else {
            return false;
        }
    }

    public void setValue(int value) {
        int rem = value - currentValue;
        removeValue -= rem;
        currentValue = value;
        repaint();
    }

    public int getMaxValue() {
        return maxValue;
    }

    public void setMaxValue() {
        maxValue = RandomValues.integer(5, 20);
    }
}

This is my Guessing Game class():

public class GuessingGame {

    int minRange, maxRange, secretNumber;
    RandomValues randomValue;

    public GuessingGame() {
        randomValue = new RandomValues();
    }

    public int getMinRange() {
        return minRange;
    }

    public int getMaxRange() {
        return maxRange;
    }

    public void setMinRange() {
        this.minRange = randomValue.integer(1, 10);
    }

    public void setMaxRange() {
        this.maxRange = randomValue.integer(80, 100);
    }

    public int getSecretNumber() {
        return secretNumber;
    }

    public void setSecretNumber() {
         this.secretNumber = randomValue.integer(minRange, maxRange);
    }   

    public void play() {
        setMinRange();
        setMaxRange();
        setSecretNumber();
    }

    public boolean isGuessCorrect(int guess) {
        if (guess == this.secretNumber) {
            return true;
        } else {
            return false;
        }
    }

    public boolean isGuessAlmostCorrect(int guess) {
        if (guess >= this.secretNumber - 5 & guess <= this.secretNumber + 5 & guess != this.secretNumber) {
            return true;
        } else {
            return false;
        }
    }

    public boolean isGuessSmaller(int guess) {
        if (guess < this.secretNumber) {
            return true;
        } else {
            return false;
        }
    }

    public boolean isGuessLarger(int guess) {
        if (guess > this.secretNumber) {
            return true;
        } else {
            return false;
        }
    }

    @Override
    public String toString() {
        return String.format("Range: %d to %d answer: %d", getMinRange(), getMaxRange(), getSecretNumber());
    }
}

And finally, this is just my simple RandomValues class to get random Numbers:

import java.util.Random;


public class RandomValues {

    public static int integer(int min, int max) {
        Random randomNum = new Random();
        int randomValue = randomNum.nextInt(max - min + 1) + min;
        return randomValue;
    }
}

I am sorry if this is a little bit too long, but if you do copy and paste it, it does work and load it's just the count down timer part just doesn't seem to want to work the way i want it to... if there is anyone that could help me out, i would love them forever :)

KrazyKat89
  • 81
  • 1
  • 5
  • *"but if you do copy and paste it,.."* 4 times, for the 4 public classes. If 3 of them were default access, they could be moved into the end of the source with the `main(String[])`. Thereby reducing it to **1** copy/paste. – Andrew Thompson Dec 29 '12 at 03:51
  • The description is a little vague- "it's not doing what I want" - After reading through the code and playing around with it, I think I know what it's "suppose" to do, but that would be a guess at best – MadProgrammer Dec 29 '12 at 03:58
  • KrazyKat89, to be honest, you really don't seem to have put any effort into formulating this question. Sure, there are people who will answer anything, but you're really supposed to narrow down your question to ask something specific - don't just throw a bunch of code at people and ask "what's wrong?" If you do that, it tends not to be too well received on these sites. – David Z Dec 29 '12 at 04:13

2 Answers2

2

In your gameTimer when the progressBar.getRunStatus() == false, you need to stop the timer...((Timer)ae.getSource()).stop();

Now...to be honest, I wouldn't bother.

I'd use something like a ChangeListener or PropetyListener to provide a callback mechanism from the ProgressBar which other classes can register with. This means that the feedback becomes more passive, rather then this active "pinging" process you're currently going through.

Basically, this means that you would provide a means for other objects to register interest in being notified when the state of the progress bar changes and they would react to that can as required.

You ProgressBar#paintComponent is ... to be frank ... weird ...

Try instead painting a rectangle that represents the percentage of the available width instead...

protected void paintComponent(Graphics g) {
    super.paintComponent(g);
    Graphics2D g2d = (Graphics2D) g;

    int x = 0;
    int y = 0;
    int width = Math.round(getWidth() * (((float)getValue() / (float)getMaxValue())));
    g2d.setColor(Color.GREEN);
    g2d.fillRect(x, y, width, getHeight());

//            rects.clear();
//            int rectWidths = getWidth() / getMaxValue();
//            int startingX = 0;
//
//            for (int i = 0; i < (getMaxValue() - removeValue); i++) {
//                rects.add(new Rectangle(startingX, 0, rectWidths, getHeight()));
//                startingX += rectWidths;
//            }
//
//            for (Rectangle r : rects) {
//                g2d.setColor(Color.green);
//                g2d.fillRect(r.x, r.y, r.width, r.height);
//            }
}
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
1

I think one of the problems is that you do not properly stop your Timers but keep then running unintentionally.

For example, in ProgressBar you always create a new timer in each call of StartTimer. You try to stop it by calling ((Timer) ae.getSource()).stop(); if getValue() returned 0. I think it doesn't work because you have a race condition and the value can actually become negative. So stop is never triggered.

I would recommend to store the progressBarCountDownTimer as an attribute of the class, and assure that it is stopped properly before you start a new timer. IMHO this is more robust.

Philipp Claßen
  • 41,306
  • 31
  • 146
  • 239
  • I'm not sure how you would get a race condition with a `javax.swing.Timer`, as each "tick" is executed in the EDT (single thread), the observer and producer are actually the same method, depending on the condition a different branch is taken - But I've being painting walls all day so my brain may simple be mush - I do agree with the timer as an attribute of the class none-the-less – MadProgrammer Dec 29 '12 at 06:58
  • @Philipp How would I go about doing what you suggest? – KrazyKat89 Dec 29 '12 at 07:28
  • ok so it seems to work really well now for the first run through, when the count down bar get to 0, the timer stops and the play button works again and the guess button doesnt. that what i want :) but then go and press the play button a second time and it doesnt work again :( any ideas???? – KrazyKat89 Dec 29 '12 at 07:45
  • hi again, I'm just wondering now, I have placed the progressbar into the guessing game class as a subclass of it. I have created an interface that has a single abstract method in it called stopped(). This is hopefully supposed to allow me to be able to tell my main() where all the game code is located, that the count down has just stopped and now to restart the game again. But I have no idea what code to put into the overridden stopped() method in the subclass (progressbar) for it to work that way. – KrazyKat89 Dec 29 '12 at 11:09