Michael A
Michael A

Reputation: 43

Speeding up a timer?

I am trying to make my current counter/timer speed up when integers get smaller. For example it would be like 10......... 9........, 8........, 7....... 6...... 5..... 4.... 3... 2.. 1.

Current code:

    private int interval;
private Timer timer;

public void startTimer(final Player p, String seconds) {
    String secs = seconds;
    int delay = 1000;
    int period = 1000;
    timer = new Timer();
    interval = Integer.parseInt(secs);
    timer.scheduleAtFixedRate(new TimerTask() {

        @Override
        public void run() {
            p.sendMessage("" + setInterval(p));
        }

    }, delay, period);
}

private final int setInterval(Player p) {
    if (interval == 1){ 
        timer.cancel(); 
        p.sendMessage(ChatColor.RED + "" + ChatColor.BOLD + "Countdown Finished!");
    }
    return --interval;
}

Upvotes: 1

Views: 1664

Answers (2)

FaNaJ
FaNaJ

Reputation: 1359

One option is to use javafx.animation.Timeline.

for example :

import javafx.animation.Interpolator;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.stage.Stage;
import javafx.util.Duration;

public class CountDown extends Application {

    private static final double SPEED_UP_FACTOR = 0.15; // + 15%

    @Override
    public void start(Stage primaryStage) throws Exception {
        IntegerProperty counter = new SimpleIntegerProperty(10);
        Timeline timeline = new Timeline(
                new KeyFrame(Duration.seconds(counter.get()), new KeyValue(counter, 0))
        );
        counter.addListener((observable, oldValue, newValue) -> {
            double currentRate = timeline.getRate();
            timeline.setRate(currentRate + currentRate * SPEED_UP_FACTOR); // speed up count down
            System.out.println(newValue);
        });
        timeline.setOnFinished(event -> {
            System.out.println("CountDown Finished!");
            Platform.exit();
        });
        timeline.play();
    }

    public static void main(String[] args) {
        launch(args);
    }

}

EDIT :

or simply use Thread.sleep() :

public class CountDown {

    private static final double SPEED_UP_FACTOR = 0.15; // + 15%

    public static void main(String[] args) {
        CountDownTimer timer = new CountDownTimer(10, 1000);
        new Thread(timer).start();
    }

    static final class CountDownTimer implements Runnable {

        final int initialValue;
        final long intervalMillis;

        CountDownTimer(int initialValue, long intervalMillis) {
            this.initialValue = initialValue;
            this.intervalMillis = intervalMillis;
        }

        @Override
        public void run() {
            int counter = initialValue;
            double rate = 1;
            while (counter > 0) {
                sleep(Math.round(intervalMillis / rate));
                rate += rate * SPEED_UP_FACTOR;
                System.out.println(--counter);
            }
        }

    }

    private static void sleep(long timeout) {
        try {
            Thread.sleep(timeout);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}

Upvotes: 1

Samuel LOL Hackson
Samuel LOL Hackson

Reputation: 1221

From the Java docs:

public void scheduleAtFixedRate(TimerTask task,
                   Date firstTime,
                   long period)

Schedules the specified task for repeated fixed-rate execution, beginning at the specified time. Subsequent executions take place at approximately regular intervals, separated by the specified period.

Using this method, there is no way you can alter the period, because this method isn't designed for this. If you tried to access period inside the task, the compiler would fail because period isn't visible within the task.

If you don't want to wrap your head around threads, runnables and the wait() method and want to stick to using a method from the Timer class (which I assume you used - but for the record, please add imports to your posted source code if you use methods from another package that possibly has documentation!), consider using public void schedule(TimerTask task, long delay) instead, wrapped inside a while loop. Then you can alter the delay parameter within the loop and schedule executes the task within a different time span.

Of course you'd have to figure out how to get out of the while loop when the countdown is finished (one "quick & dirty" way would be using a boolean). But because you basically "reset" the timer in every iteration of the while loop, timer.cancel() won't do anything for you. It'd cancel once, but the next iteration timer will simply restart the task.

Upvotes: 1

Related Questions