Using multiple timers in a Java application with animation - java

I'm writing a Java Application that will side scroll sheet music across the screen and then when it crosses a middle line, it will play the note(s).
It will have a variable speed based on the beats per minute.
Every quarter of a beat I need to have a "tick" function that will get the next note (if any) and start its animation. To calculate this tick I have a function 60000ms/bpm/4. This will be separate from the animation timer, because the repaint should probably be called at some constant rate.
So I'm thinking I need Util Timer for the "ticks" and a swing timer for the JPanel and drawing in the paintComponent() method.
My question is: What would be the best practice for accomplishing this? I've done a fair amount of Java programming, but no Swing or animations so I would like to learn the best way to do this.
Thanks
Nate

There is no reason to use Timer or TimerTask to solve this problem.
In this case, you have a series of notes, and when you start playing, you can calculate ahead of time, the exact time that each and every note should play. I am assuming that you already have some sort of loop that is updating the display at a steady rate. (e.g. 30 refreshes per second, or something like that). Given such a loop, all you need is an event oriented class that can tell you whether it is time to play a note.
long noteTime[] = new long[numberOfNotes];
long startTime = System.currentTimeMillis();
Declare the above array. Then walk through all the notes in the song, and calculate the time that each note is expected to play. Say you have qurter notes, the first note will play at startTime, the second one beat after startTime, the third two beats after start time, etc. This is where you calculate the time for a beat and use it. Just calculate the actual time values for each note to play.
Then, in the middle of your event loop that is refreshing the display, include the following code:
int nextNote = 0;
while (event_loop_condition) {
.
.
.
if (System.currentTimeMillis()>noteTime[nextNote]) {
playNote(nextNote++);
}
.
.
.
}
The point is that you already have an event loop, all you need to know is whether it it time yet to play the note, and this will do that for you.
On the other hand, if you are not handling the refresh, and you really do want to do this on a thread, the follow method can be called on a thread, and it will play all the notes at the correct times:
playAllNotes() {
for (int i=0; i<numberOfNotes; i++) {
Thread.sleep(noteTime[i]-System.currentTimeMillis());
playNote(i);
}
}
The sleep statement will delay until the time that the note should be played, and will play it at that time. Then it will sleep until the time for the next note to be played.
The important thing to notice about both methods, is that any delay in playing a note is NOT compounded for the next note. Say some system utility kicks in and delays one note by 50ms. The next note will not be delayed by this, because you calculated all the times for all the notes to be played up front. Given that threads are competing for CPU time, you will have thread/process contention, and there will be small variances in the time that notes are played, but they will never compound!
A lot of programmers inappropriately use timers (See discussion of Timers) on my website if you want to know more.

Related

Making Java game, found easy way to cheat, don't know how to prevent it

I'm making a game in Java, and I made it so that if you right click, the player teleports to the mouse to "escape". I want to make it so that you can only use it every 2 mins. and after trying and failing THAT, I found out that you can just hold down right mouse and the player will follow your mouse/clicker. I am using Processing 3.1.2 if that helps at all.
Every time you allow that player power to be used, note the current timestamp.
Next time the player attempts to activate that power, check the saved timestamp against the current time. If an insufficient number of seconds have passed, disallow the power.
If sufficient time has passed and you allow the power to activate, update the variable holding the time that the power was last used.
This is often called a "cool down" in games.
I would suggest using a javax.swing.timer. I have done this before, and within the mouseClicked event you set a boolean canTeleport = false. At the end of the javax.swing.timer, set canTeleport = true. The first thing that you can do when going inside mouseClicked,
if(canTeleport)
{
//teleport
}
//start timer

Is it good to separate game thread and display thread?

It is the first time I want to write a java game, and I chose to do a Snake Line.
I learnt from a piece of source code from online. It updates the game states and displays in one thread. I changed around that code, and when I changed the FPS (from 60 to 30), animation slows down. More to this, the game behavior changes too. It is duck shooting game, and the space between ducks get narrower.
So I decided to separate the game thread and the display thread to avoid the above problem. But then I realize it brings out the concurrency problem which will be all over the place.
So as the title indicates, is it good to separate game thread and display thread? What is the common practice and why?
From the changes you experience, it sounds like you are using frame as a unit of time measurement. Or, more precisely, you use pixel/frame(or something like that) for velocity and second for time.
This might be OK for a simple game like yours, ones that are light enough on the system resources so that the delay between frames you specify in the code is practically the same as the real delay, meaning you are in complete control over the FPS. When the game get heavier and modern systems can no longer guarantee that property, you have a problem.
The solution is usually not to separate the game and display loops to separate threads, but to not use frames as unit of measurement for game mechanics calculations. Instead, each frame measure the time from the previous frame and use that value for the calculations, eg. multiply it by the speed to know how much to move a game object in this frame.
Not that separating those loops is such a bad idea. You don't get concurrency problems "all over the place", since the interaction between the game logic and the display shouldn't be "all over the place". The interaction should be one-way: the game loop writes data and the display loop reads it. That means you shouldn't have race conditions, but you can still get other multithreading hazards, which you can solve with volatile variables.

Make a simple timer in Java

I can't seem to figure out how to make a simple timer in java. All I need it to do is just display time, really. So just a start method, and it keeps counting up like 0:00, 0:01, 0:02, etc. I've seen some other similar forum posts on this, but all the code is kind of complicated for my level of understanding; I'm kind of new to java. But it shouldnt be that hard to make a timer that just performs such a basic function? If anyone could help it would be greatly appreciated :)
This is not difficult. However, I would caution you that I have seen some very confused answers on stack overflow, in some cases shockingly poor coding habits, so be very careful. First let me answer the question.
If seem that the biggest mistake that programmers make in implementing a timer, is thinking that they need something to keep track of the current time. That is, they write some sort of loop that increments a variable every second or some such silly thing. You do not need to write code to keep track of the time. The function System.currentTimeMillis() will do that for you, and it does it quite accurately.
Timer code will involve two aspects which many programmers mix up:
calculation of the time
refresh of the display
All you need to do to calculate the time to display, is to record the time that the timer started:
long startTime = System.currentTimeMillis();
Later, when you want to display the amount of time, you just subtract this from the current time.
long elapsedTime = System.currentTimeMillis() - startTime;
long elapsedSeconds = elapsedTime / 1000;
long secondsDisplay = elapsedSeconds % 60;
long elapsedMinutes = elapsedSeconds / 60;
//put here code to format and display the values
The biggest mistake that programmers make is to think they need a variable to hold the current time and then to write code to increment that variable every second, e.g. something called "elapsedSeconds" which they maintain. The problem is that you can schedule code to be called every second, but there is no guarantee of exactly when that code will be called. If the system is busy, that code might be called quite a bit later than the second. If the system is extremely busy (for example page fetching from a faulty disk) it could actually be several seconds late. Code that uses the Thread.sleep(1000) function to loop every second will find that the error builds up over time. If sleep returns 300ms late one time, that error is compounded into your calculation of what time it is. This is all completely unnecessary because the OS has a function to tell you the current time.
The above calculation will be accurate whether you run this code every second, 100 times a second, or once every 3.572 seconds. The point is that currentTimeMillis() is the accurate representation of the time regardless of when this code is called -- and that is an important consideration because thread and timer events are not guaranteed to be accurate at a specific time.
The second aspect of a timer is refresh of the display. This will depend upon the technology you are using to display with. In a GUI environment you need to schedule paint events. You would like these paint events to come right after the time that the display is expected to change. However, it is tricky. You can request a paint event, but there may be hundreds of other paint events queued up to be handled before yours.
One lazy way to do this is to schedule 10 paint events per second. Because the calculation of the time does not depend on the code being called at a particular point in time, and because it does not matter if you re-paint the screen with the same time, this approach more or less guarantees that the displayed time will show the right time within about 1/10 of a second. This seems a bit of a waste, because 9 times out of 10 you are painting what is already on the screen.
If you are writing a program with animation of some sort (like a game) which is refreshing the screen 30 times a second, then you need do nothing. Just incorporate the timer display call into your regular screen refresh.
If paint events are expensive, or if you are writing a program that does terminal-style output, you can optimize the scheduling of events by calculating the amount of time remaining until the display will change:
long elapsedTime = System.currentTimeMillis() - startTime;
long timeTillNextDisplayChange = 1000 - (elapsedTime % 1000);
The variable timeTillNextDisplayChange holds the number of milliseconds you need to wait until the seconds part of the timer will change. You can then schedule a paint event to occur at that time, possibly calling Thread.sleep(timeTillNextDisplayChange) and after the sleep do the output. If your code is running in a browser, you can use this technique to update the page DOM at the right time.
Note, that there is nothing in this calculation of the display refresh that effects the accuracy of the timer itself. The thread might return from sleep 10ms late, or even 500ms late, and the accuracy of the timer will not be effected. On every pass we calculate the time to wait from the currentTimeMillis, so being called late on one occasion will not cause later displays to be late.
That is the key to an accurate timer. Do not expect the OS to call your routine or send the paint event exactly when you ask it to. Usually, of course, with modern machines, the OS is remarkably responsive and accurate. This happens in test situations where you are not running much else, and the timer seems to work. But, in production, under rare stress situation, you do not want your timer "drifting" because the system is busy.
You can either use Timer class from java.util or another way, which is more complicated, is with Threads. Timer also has thread action, but it's pretty easy to understand to use it.
For creating a simple timer as you explained as per your need , it is very easy to write a code for that. I have written the below code for your reference. If you wish you can enhance it.
import java.util.concurrent.TimeUnit;
public class PerfectTimer {
public static void main(String[] args) throws InterruptedException
{
boolean x=true;
long displayMinutes=0;
long starttime=System.currentTimeMillis();
System.out.println("Timer:");
while(x)
{
TimeUnit.SECONDS.sleep(1);
long timepassed=System.currentTimeMillis()-starttime;
long secondspassed=timepassed/1000;
if(secondspassed==60)
{
secondspassed=0;
starttime=System.currentTimeMillis();
}
if((secondspassed%60)==0)
displayMinutes++;
System.out.println(displayMinutes+"::"+secondspassed);
}
}
}
if you want to update something in the main thread (like UI components)
better to use Handler
Handler h = new Handler();
h.postDelayed(new Runnable() {
#Override
public void run() {
//do something
}
}, 20);
20 - the delay In MS to do something.
and run it in a loop.
I have created a Timer that has everything you might need in it.
I even documented it!
And I also compiled it for faster usage.
Here's an example:
//...
//For demo only!
public static void main(String[]a){
Timer timer=new Timer();
timer.setWatcher(new Timer.TimerWatcher(){
public void hasStopped(boolean stopped){
System.out.print(stopped+" | ");
}
public void timeElapsed(long nano, long millis, long seconds){
System.out.print(nano+", ");
System.out.print(millis+", ");
System.out.print(seconds+" | ");
}
public void timeLeft(long timeLeft){
System.out.print(timeLeft+"\r");
}
});
//Block the thread for 5 seconds!
timer.stopAfter(5, Timer.seconds); //You can replace this with Integer.MAX_VALUE.
//So that our watcher won't go to waste.
System.out.println();
}
//...
This is not for promotion, made this to help people not waste their time in coding classes themselves!

How can I use a timer to delay a specific task not associated with the timer class (java.util.timer)?

I am making a text-based RPG for a personal project in Java. In the game the protagonist will have at his/her disposal the ability to use a spell or ability. I would like to add a cool down to the aforementioned spell or ability. I have researched both the javax.swing.Timer and java.util.Timer classes but have not found a way to go about using this cool down. I am not using threads or daemons (primarily because I don't think I need to and I have zero experience with them).
Any help or ideas on how to go about this would be appreciated, thanks.
Alumnus
Just save System.currentTimeMillis() at the time the spell is cast and check the time elapsed when the hero tries to cast it again.
When you use your spell, set some variable to say that the spell is now unavailable. Then start a timer that will act as your cool down. When the timer ticks, reset that variable to indicate that it has cooled down and can be used again.
If possible you could save the current game time when the spell/ability gets triggered inside your application and disable the ability.
Then again if yo can do it you can check every "frame update" if the cool down time has already elapsed by computing the time difference between the current time and the time the spell/ability got triggered and reenable the ability when the desired time has elapsed.
If this RPG is turn based combat then do this:
Make a cooldown variable with the number of turns needed to wait for cooldown.
Now make another variable for current cooldown turn, now set its value to the same as the cooldown like
curcooldown = waitforcooldown, something like that.
And then if you check that the player wants to use the spell and then check it like this.
If player wants to use spell & curcooldown is 0
UseSpell
Else if (player wants to use spell & curcooldown greater or equal to 0
saytoplayerthatspellisundercooldown
and if spell is used then curcooldown = waitforcooldown
set it to the cooldown value turn value.
and every time a turn ends then decrease the curcooldownvalue by 1 that means your cooldown just lost 1 turn and so on...
Hope this helped

Timer implementation

How can you implement some kind of timer, to know how much time did user spend for one round of a game?
Getting System.currentTimeMillis will get your system time to the millisecond. If you want to do a Swing event intermittently, such as displaying the current time in a stop watch or a simple animation, then a Swing Timer would work well.
One can easily find the time spent by a user on one round of a game by using System.nanoTime() function. However if you want to implement in a game, you would probably like the timer to also be displayed to the user, you can you use multi-threading for the same.

Categories

Resources