I'm creating a game that ends if you haven't reached a certain point by the time the timer reaches zero. It currently works and I can create multiple TimerTasks at one time, but I cannot cancel them. Currently, clicking the button resets the timer (on the display) but will still run in the background and end the program when it reaches zero (even though it shouldn't be running). Here's the code for the ActionListener that starts each timer.
public class Game implements Runnable {
private int currentScore, difficulty, level, highscore, x, y;
private boolean playMusic, playClicks, gameRunning;
private boolean stopLastTimer = false;
JFrame gameFrame;
Data data;
JButton target;
Thread t;
JLabel score;
Timer globalTimer = new Timer();
JLabel timer;
ActionListener clickedAction = new ActionListener(){
public void actionPerformed(ActionEvent ae) {
stopLastTimer = true;
t.interrupt();
currentScore++;
score.setText("Score: " + currentScore);
//playClickSound();
globalTimer.schedule(new TimerTask(){
double second = 2.0;
#Override
public void run() {
second = second - 0.1;
if(stopLastTimer) {
this.cancel(); stopLastTimer = false; } //should end old timer here
if(second == 0.0) {
this.cancel();
gameStop();
}
second = limitPrecision(Double.toString(second), 1);
timer.setText(second + "s");
}
},0, 100);
}
};
Don't use a TimerTask.
Instead you should be using a javax.swing.Timer for the animation. A Swing Timer has a stop() method.
The source of the ActionEvent will be the Timer itself.
Read the section from the Swing tutorial on How to Use Timer for more information and working examples.
Related
I'm actually trying to fix a problem with the component of JFrame that don't want to show up when I run my game loop (see the question after the code). I have reduced the code at the minimum possible for you to get what I mean fast:
Run.class
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
Game game = new Game();
game.loop();
}
});
}
Game.class
private Frame frame;
private HashMap<String,ActionListener> actions;
private HashMap<String,Image> ressources;
public Game() {
this.setActions();
this.setRessources();
frame = new Frame(actions,ressources);
}
public void loop() {
double FPS = 60;
double UPS = 60;
long initialTime = System.nanoTime();
final double timeU = 1000000000 / UPS;
final double timeF = 1000000000 / FPS;
double deltaU = 0, deltaF = 0;
int frames = 0, ticks = 0;
long timer = System.currentTimeMillis();
boolean running = true;
boolean RENDER_TIME = false;
while (running) {
...code for update, render, with a fps control
}
}
Frame.class
public Frame(HashMap<String,ActionListener> actions, HashMap<String,Image> ressources) {
this.setTitle(Constants.GAME_NAME);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setSize(Constants.GAME_SIZE_X, Constants.GAME_SIZE_Y);
this.setLayout(new FlowLayout());
JButton myButton = new JButton("My Button");
this.add(myButton);
this.revalidate();
this.repaint();
this.setVisible(true);
}
It's not the complete code because I don't want to give a useless thing. So here, my problem is:
If I run this code, the button not going to show up in the frame. But if I comment game.loop() in the Run.class, the windows show the button. And I don't understand WHY?
I have been trying for a few days to figure it out. I need some help for this one. Alone I'm afraid I will not find out.
To avid blocking the Event Dispatching Thread by running a long process you can use swing Timer which can handle the "looping" for you :
ActionListener animate = e -> {
game.oneFrame();
panel.repaint();
};
timer = new Timer(50, animate);
timer.start();
public void oneFrame(){
//update what is needed for one "frame"
}
For more help post mcve.
This is part of my code and it doesn't work because it keeps on saying it cannot find the symbol in my ActionListener. I don't know how to make it work.
So basically what I'm trying to do is make the images from 1-8.png move depending on where the slider lands and IDK how to:
private static JLabel value;
private static ImageIcon image;
private static Timer timer;
private static final int delay = 2000;
private static int newDelay;
private static int i = 1;
timer = new Timer(delay, new ActionListener() {
public void actionPerformed(ActionEvent e) {
// makes the image at i appear and then goes to 2 and so on until i i = 8 and will return a 1 after. Will keep on doing so
value.setIcon(new ImageIcon(i + ".png"));
i++;
if(i == 8) {
i = 1;
}
}
});
timer.start();
}
private static class SliderChange implements ChangeListener {
public void stateChanged(ChangeEvent event) {
JSlider source = (JSlider) event.getSource();
// while it is adjusting timer stops and gets the value of where the slider hits and the newDelay will be the new timer time. (So if they drag slider to 6, delay(which is 2000) will be divided by 6 to get new time
if (!source.getValueIsAdjusting()) {
timer.stop();
value.setIcon(new ImageIcon(i + ".png"));
newDelay = (delay/(int)source.getValue());
timer = new Timer(newDelay, new Actionlistener());
timer.start();
}
}
}
But this doesn't work. How can I fix it?
It points to this line saying there is an error:
timer = new Timer(newDelay, new Actionlistener());
I'm not sure it's really necessary to recreate the Timer each time. Instead, stop it, set it's delay property and restart it instead
private static class SliderChange implements ChangeListener {
public void stateChanged(ChangeEvent event) {
JSlider source = (JSlider) event.getSource();
// while it is adjusting timer stops and gets the value of where the slider hits and the newDelay will be the new timer time. (So if they drag slider to 6, delay(which is 2000) will be divided by 6 to get new time
if (!source.getValueIsAdjusting()) {
timer.stop();
value.setIcon(new ImageIcon(i + ".png"));
newDelay = (delay/(int)source.getValue());
timer.setDelay(newDelay);
timer.start();
}
}
}
The problem is timer = new Timer(newDelay, new Actionlistener()); is trying to create an instance of a interface without the implementing the requirements of the interface, which is confusing the compiler
I need to make a GUI where a worker enters a station (a spot on the panel) and stays there for a set amount of seconds, shown in a countdown about the workers head (so, once the workers moves to the spot, the station's label shows 3s -> 2s -> 1s and then the worker leaves, and the label reverts back to "OPEN"). I'm having trouble with making this happen, as I'm not too good with the Timer(s?) that Java has. I tried with something like this:
Timer timer = new Timer(1000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e)
{
//change label text/color, decrement countdown
panel.repaint();
Thread.sleep(1000);
}
});
But I can't reach the number of seconds to count down from from inside the timer, and I'm not sure how to pass that value to the timer. If someone can help me out, I'd really appreciate it.
Get rid of the Thread.sleep(). That's what the 1000 in Timer(1000, new ActionListener() does. It sets an interval for each timer event. Every time a timer event is fired, the actionPerformed is called. So you need to determine what needs to happen every "tick", and put that code in the actionPerformed. Maybe something like
Timer timer = new Timer(1000, new ActionListener() {
private int count = 5;
#Override
public void actionPerformed(ActionEvent e) {
if (count <= 0) {
label.setText("OPEN");
((Timer)e.getSource()).stop();
count = 5;
} else {
label.setText(Integer.toString(count);
count--;
}
}
});
You need to decide when to call timer.start().
For general information, see How to Use Swing Timers
Problem #1: You are calling Thread.sleep() from within the Swing GUI thread. That causes the thread to stop taking input and freeze. Delete that line. It does you no good! While you are at it, delete the repaint call as well.
Now that that's said and done, instead of creating an anonymous instance of ActionListener, you can create an actual class that implements ActionListener and provides a constructor. That constructor can have as an argument the number of seconds you want to start counting down. You can declare that class inside the method you are using, or you can declare it inside the class.
Here's a skeletal example:
public class OuterClass {
JLabel secondsLabel = ...;
Timer myTimer;
private void setupTimer(int numSecondsToCountDown) {
secondsLabel.setText(Integer.toString(numSecondsToCountDown));
myTimer = new Timer(1000, new CountdownListener(numSecondsToCountDown));
myTimer.start();
}
// ...
class CountdownListener implements ActionListener {
private int secondsCount;
public CountdownListener(int startingSeconds) { secondsCount = startingSeconds; }
public void actionPerformed(ActionEvent evt) {
secondsLabel.setText(Integer.toString(secondsCount);
secondsCount--;
if (secondsCount <= 0) { // stop the countdown
myTimer.stop();
}
}
}
}
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Stop timer with conditional only works first time?
I'm very confused as to how to make a timer using the swing and not util timer.
I am making a game where users have to answer questions in a 30 second time limit. I have a PlayFrame, where the time is shown, and a method inside PlayFrame called startTimer which contains all the timer stuff.
public static void startTimer() {
int elapsedSeconds = 0;
javax.swing.Timer myTimer = new javax.swing.Timer(1000, new MyTimerActionListener());
elapsedSeconds++;
if (elapsedSeconds == 30) {
myTimer.stop();
timerLabel.setText("0");
wrong();
} else {
String text = String.format("f", 30 - elapsedSeconds);
timerLabel.setText(text);
}
if (myTimer != null && myTimer.isRunning()) {
myTimer.stop();
myTimer = null;
timerLabel.setText("0");
} else {
elapsedSeconds = 0;
myTimer = new javax.swing.Timer(1000, new MyTimerActionListener());
myTimer.start();
String text = String.format("t", 30);
timerLabel.setText(text);
}
}
What I want this method to do is have a timer that counts down from 30 until the question is answered correctly. If the answer is answered incorrectly I want the timer to stop.
For an answer perhaps some psuedocode (or real code) to move me in the right direction. And this is for personal use, not homework or anything.
Please remember that this is a part of my whole code and it needs to work with other parts of it. I'll give more information upon request, thanks!
EDIT: New startTimer() method NOTE all System.out.print is for testing only:
public static void startTimer() {
class TimerListener implements ActionListener {
Timer timer = new Timer(1000, new TimerListener());
int elapsedSeconds = 30;
String seconds = Integer.toString(elapsedSeconds);
#Override
public void actionPerformed(ActionEvent evt) {
timer.start();
if (elapsedSeconds == 0) {
//System.out.print("here");
timer.stop();
PlayFrame.wrong();
}
else{
//System.out.print("hersfde");
elapsedSeconds--;
PlayFrame.timerLabel.setText(seconds);
}
//System.out.println(elapsedSeconds);
}
}
//System.out.print("l");
}
Doesn't do anything and not sure why.
This is how I would make a countdown timer:
Timer timer = new Timer(1000, new TimerListener());
class TimerListener implements ActionListener{
int elapsedSeconds = 30;
public void actionPerformed(ActionEvent evt){
elapsedSeconds--;
timerLabel.setText(elapsedSeconds)
if(elapsedSeconds <= 0){
timer.stop();
wrong()
// fill'er up here...
}
}
}
I am making a simple target shooting game.I have a countdownTimer inside the label and an object that blinks in a random position inside the panel. Every time I click on the object,. the object's timer stops which makes that object stop too, but the countdown timer doesn't and that is my problem. I want the countdown timer should stop also.
Could someone help me about this matter?
Here's the code :
private void starting()
{
new Timer(TIMER_PERIOD, new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
if (count++ < MAX_COUNT)
{
String text = "Time remaining: (" + (MAX_COUNT - count) + ") seconds left";
setCountDownLabelText(text);
Date date = new Date();
setCountDownPanelText(date);
}
else
{
((Timer) e.getSource()).stop();
randomTimer.stop();
JOptionPane.showMessageDialog(null, "Game Over");
System.exit(0);
}
}
}).start();
}
It strikes me that you don't understand the code at all, that you are unaware of the anonymous class created that is extending Timer, which (if you'd seen the documentation) has a function stop() which does what you ask.
You need to store a reference to the Timer.
private javax.swing.Timer timer;
private void starting() {
timer = new Timer(TIMER_PERIOD, new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
// do stuff
// stop the timer
timer.stop();
// do other stuff
}
}
}