I try to add time to my game that will increment every second.
How to fix that?
I add my code below
float timer;
timer += delta;
if(timer<=delta+1000)//every one sec
{
time = time+1;
timePoint.setSentence(""+time/100);
timer = 0f;
}
as your note, delta is Gdx.graphics.getDeltaTime().
'time' is string.
but looks like the time increment slowly. means that when time already run about 1,5 sec,
'time' still increase 1.
I divide by 100 because if not it will increase more faster/sec,
i also use TimeUtils class from libgdx but it produced similar result.
Thanks before.
This should work. Note that time/100 results in 0 for 0-99 and 1 for 100-199. That's probably not the effect you wanted.
float timer;
timer += delta;
if (timer >= 1) {
time++;
timePoint.setSentence(""+time);
timer -= 1;
}
The problem was that you set the timer back to 0. If it was 1.1f for example (because the last delta was 0.1f), then you basically lose 100ms. Don't reset the timer to 0f, but decrease it by 1f instead.
I would do it like this:
float time = 0f;
In render:
time += delta;
timePoint.setSentence(Integer.toString((int)time));
delta is giving the ellapsed time in seconds, so for 30FPS it is 1/30 seconds. So you only need to add it to your time. To print the difference (i guess the setSentence is printing the text) you only need to cast it to int, so that it cuts the fraction digits.
Hope it helps.
EDIT: If you need the timer and the time variable somewhere you need to store them in 2 different variables.
For that i would do it like this:
float timer = 0f;
int time = 0;
And in render:
timer+=delta;
if (timer >= 1f) {
time++;
timePoint.setSentence(Integer.toString(time));
timer-=1f;
}
By doing this you are not loosing the few milli seconds you would loose if you reset the timer.
This means, that if timer goes from 0.99f to 1.05f in one renderloop and you reset the timer to 0f, you loose 0.05 seconds. If this happens every second you loose 1 second every 20 seconds (if i am not wrong^^)
Like in pure java:
Timer timer = new Timer();
timer.schedule(new incrementYourValue(), 0, 1000); //1000 is time in mili sec
//0 is the time waited before the beginning.
Had similar problem but for me using delta time was kinda overkill. Instead I used Libgdx Timer that "Executes tasks in the future on the main loop thread". Using Timer from java.util may cause Concurrency problems in libgdx.
import com.badlogic.gdx.utils.Timer;
public class Scheduler {
public Scheduler(Runnable runnable, float periodInSeconds) {
Timer timer = new Timer();
timer.scheduleTask(new Timer.Task() {
#Override
public void run() {
runnable.run();
}
}, 0, periodInSeconds);
}}
And usage:
new Scheduler(() -> updateSth(), 1f);
Related
if I don't control the number of times per second my code executes, when I add a line, the program varies and I have to adjust the constants again. (translated by Google)
My code running out of control:
public builder(){
while(true)
stepEvent();
}
private void stepEvent() {
setOfActions();
repaint();
}
This is just one way to do it(it's very long but VERY precise - I recommend it for game development). In this case I'm using the run() method from the Runnable interface to execute the code.
public void run(){
long lastTime = System.nanoTime();
final double ns = 1000000000.0 / 60.0;
double delta = 0;
while(true){
long now = System.nanoTime();
delta += (now - lastTime) / ns;
lastTime = now;
while(delta >= 1){
the code you want to be executed
delta--;
}
}
}
Explanation Line by Line:
Basically, I store the current time in nanoseconds in lastTime. Then in ns I store 1/60th of a second in nanoseconds and create a variable delta.
After this, I go inside the infinite while loop(it doesn't have to be infinite) and store the current time in nanoseconds once again in now. This is to take into account the amount of time that took the computer to go from the lastTime declaration line to the while loop line.
After doing all this, I add to delta the difference of now and lastTime divided by the 1/60th of a second(ns) I mentioned. This means that every time delta is equal to 1, 1/60th of a second will have passed.
Right after this, I make lastTime be the same as now. In the while loop that comes afterwards I check if delta is equal or greater than 1 and then in there you should put all the code you want to be executed 60 times per second. Don't forget to substract 1 from delta so it doesn't loop endlessly.
Analyze the code thoroughly and see if you can understand it. If you can't, I'll clarify further. I insist that this is just one possible way to do it, but there are many more ways.
Note: In some cases, you will never even need delta, but it is very helpful for some purposes.
Credit for the code: Most of this code(at least where I got it & learned it) is extracted from TheCherno's Game Programming Series
Have a great day!
import java.util.Timer;
import java.util.TimerTask;
public class HelloWorld {
public static void main(String []args) {
// number of ms in 1/60 of a second
// there will be some rounding error here,
// not sure if that's acceptable for your use case
int ms = 1000 / 60;
Timer timer = new Timer();
timer.schedule(new SayHello(), 0, ms);
}
}
class SayHello extends TimerTask {
public void run() {
System.out.println("Hello World!");
}
}
Basically, you have to execute your stepEvent every 17 ms.
With the assumption you want to run sequentially, you could stop the execution during a defined period by using Thread.sleep(millis , nanos). In this case, we will stop the thread 17ms minus the stepEvent execution time (think to add condition to avoid negative value in sleep function)
long startedTime;
for(;;){
startedTime = System.currentTimeMillis();
stepEvent();
Thread.sleep(17 - System.currentTimeMillis() + startedTime);
}
Otherwise you can use the ScheduledExecutorService which allows you to schedule code to run periodically at fixed time intervals (or after a specified delay). In this case, you can execute your step at a fixed rate every 17ms.
ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
scheduledExecutorService.scheduleAtFixedRate(YourClass::stepEvent, 0, 17, TimeUnit.MILLISECONDS);
You can also configure to use severals thread with Executors.newScheduledThreadPool
I'm trying to make a timer that goes from 15 minutes to 0 but my code doesn't work. Sorry if this is easy, I recently started learning.
package timer;
import java.util.Timer;
import java.util.TimerTask;
public class Timer {
int secondsLeft = 900;
int minutesLeft = secondsLeft/60;
int seconds2 = secondsLeft - minutesLeft * 60;
Timer timer = new Timer();
TimerTask task = new TimerTask() {
public void run() {
secondsLeft--;
System.out.println("Time left : " + minutesLeft + ":" + seconds2 );
}
};
public void start() {
timer.scheduleAtFixedRate(task, 1000, 1000);
}
public static void main(String[] args) {
Timer timer = new Timer();
timer.start();
}
}
Your program is mostly written correctly, but you are not printing any changes. When the seconds count down, you need to convert existing total seconds to minutes and seconds.
You can do it several ways.
Method 1: Like you are doing it now, by
maintaining a total number of seconds. It requires two operators.
The division operator /
The remainder operator %
To get the minutes remaining, simply divide total seconds by 60. (totalSeconds / 60)
To get the seconds remaining in the current minute take the remainder (totalSeconds % 60)
Method 2: By maintaining separate values for minutes and seconds, where seconds is the number of seconds within the current minute.
define a int minutes field initialized to 15
define a int seconds field initialized to 0
When the timer task runs, you need to update those fields correctly. When the seconds reach 0
decrement the minutes and set the seconds to 59. Otherwise, just decrement the seconds.
When they both reach 0, you're done. So this requires some if clauses on your part.
Additional Recommendations
To retain the leading zeroes of minutes and seconds, you can use the following formatted print statement.
System.out.printf("Time left : %02d:%02d%n",minutesLeft, secondsLeft);
The %02d is the field width and the 0 means keep leading zeroes to fill out that field. To learn more about formatted printing, check out the Formatter class in the Java API.
And finally, please call you class something other than Timer. You are using a Timer class by that name already and even though it is in the same package it can be confusing.
How can I get the time left in a util.Timer?
What I want to do is to add a progressbar that displays time left until the timer starts over.
This is what I've got this far:
int seconds = 8;
java.util.Timer timer = new Timer();
timer.schedule( new TimerTask(){
public void run(){
// Do something
// Add a progressbar that displays time left until the timer "starts over".
},0,(long) (seconds*1000));
You would need a second timer to refresh the gui in a specific interval.
Another way to achieve this, would be to activate a single timer every second and update the counting in the ui. If the time is up, call your specific action.
A simple expample with console output only:
TimerTask task = new TimerTask()
{
int seconds = 8;
int i = 0;
#Override
public void run()
{
i++;
if(i % seconds == 0)
System.out.println("Timer action!");
else
System.out.println("Time left:" + (seconds - (i %seconds)) );
}
};
Timer timer = new Timer();
timer.schedule(task, 0, 1000);
It's output would be:
Time left:7
Time left:6
Time left:5
Time left:4
Time left:3
Time left:2
Time left:1
Timer action!
Time left:7
Time left:6
Time left:5
Time left:4
Time left:3
Time left:2
Time left:1
Timer action!
Time left:7
Time left:6
...
Then simply change the System.out's with your code to update the progress bar. Remember: java.util.Timer starts its own Thread. Swing is not thread safe, so you need to put every gui changing code into SwingUtilities.invokeLater()!
If you're not doing any long running tasks, every time your timer reachs the 8 seconds mark, you may want to use javax.swing.Timer directly. It uses the EDT and not its own Thread, so you don't need to synchronize your calls to Swing components with SwingUtilities.invokeLater().
Also see:
javax.swing.Timer vs java.util.Timer inside of a Swing application
All you need to do is declare a long variable timeleft in your MainActivity.
long timeleft;
Then, when you create a new Timer, set the "onTick" override to update the timeleft variable each "onTick" (which in the following example is 1000 milliseconds )
timer = new CountDownTimer(time, 1000) {
#Override
public void onTick(long millisecondsUntilFinished) {
timeleft = millisecondsUntilFinished;
}
}
Your app can access then the variable timeleft every time you need to check how much time is left.
I'm making fast forward button in my Mp3 player. I wrote already code for this, but have problem how to implement timer to jump 5% forward? I mean when I press button timer should jump 5% forward of total long song. This is my fastForward method.
public void FastForward(){
try {
//songTotalLength = fis.available();
fis.skip((long) ((songTotalLength * 0.05)));
} catch (IOException e) {
e.printStackTrace();
}
}
And here is the button method:
private void jButton3ActionPerformed(ActionEvent e) {
mp3.FastForward();
if(mp3.player.isComplete()){
bar = 100;
}
jProgressBar1.setValue((int)bar);
bar+=5;
}
And this one is for timer:
private void setTime(float t) {
int mili = (int) (t / 1000);
int sec = (mili / 1000) % 60;
int min = (mili / 1000) / 60;
start.set(Calendar.MINUTE, 0);
start.set(Calendar.SECOND, 0);
end.set(Calendar.MINUTE, 0 + min);
end.set(Calendar.SECOND, 0 + sec);
timer = new javax.swing.Timer(1000, new TimerListener());
percent = (float)100/(min*60+sec);
}
You're already redundantly tracking progress in two variables fis and bar. For the sake of good design, use one of those to determine elapsed time rather than using yet another variable for the same purpose.
but have problem how to implement timer to jump 5% forward?
You seem to have mistaken the purpose of a Timer. According to the Timer class documentation, it:
Fires one or more ActionEvents at specified intervals.
So the timer is not meant to keep track of how much time has elapsed. It will simply invoke the actionPerformed(ActionEvent) method of your TimerListener once per second (every 1000 milliseconds) as you have it configured.
For a more complete answer, please post the code for your TimerListener class.
Notes
It seems that your setTime(float) method is meant to be called repeatedly, so this method should not be initializing the timer variable. Rather initialize the timer once and leave it alone to do its job.
I'm assuming you intended the supplied float parameter t to represent microseconds.
The float data type has only 7 digits of precision. This could be fine since you're interested only in minutes and seconds, otherwise float is only good for up to about four months of seconds before losing accuracy.
It seems like you wanted your button click handler to do this (increment bar sooner):
private void jButton3ActionPerformed(ActionEvent e) {
mp3.FastForward();
bar+=5; // increment bar before checking complete, and before setting progress
if(mp3.player.isComplete()){
bar = 100;
}
jProgressBar1.setValue((int)bar);
}
I am using a while loop with a timer.
The thing is that the timer is not used in every loop.
It is used only the first time. After the first time the statements included inside the loop are executed without the delay that i have set.
How is this even possible since the timer is included inside the while loop.
Any solutions ?
int count = 1;
while (count <= 10) {
final Handler handler = new Handler();
Timer t = new Timer();
t.schedule(new TimerTask() {
public void run() {
handler.post(new Runnable() {
public void run() {
// Stuff the while loop executes
}
});
}
}, 20000);
count++;
}
The TimerTask kicks off a new Thread and then the loop proceeds as normal.
The execution of the thread does not cause a delay to the execution of the code in your loop.
It's because you're queueing up 10 toasts all to execute in one hour. Each iteration of your loop takes only a fraction of a millisecond or maybe a tad bit more than that. To enqueue them properly, you could do 3600000 * count instead of 3600000 each time.
This is a terrible way to do it though. You should use AlarmManager for stuff like this.
You're scheduling 10 TimerTasks to execute after an hour, at the same time. So all 10 tasks are being executed after 1 hour, which makes it seem like 1 execute since all the Toast messages display at the same time. To schedule tasks at a fixed delay, with the first task starting in 1 hour, use this method:
Timer t = new Timer();
t.schedule(task, 3600000, 3600000);
This will execute until you call t.cancel().