I made my first game in Java - Snake,
it's main loop looks like this
while (true)
{
long start = System.nanoTime();
model.eUpdate();
if (model.hasElapsedCycle())
{
model.updateGame();
}
view.refresh();
long delta = (System.nanoTime() - start) / 1000000L;
if (delta < model.getFrameTime())
{
try
{
Thread.sleep(model.getFrameTime() - delta);
} catch (Exception e)
{
e.printStackTrace();
}
}
}
But in my project's requirments there is a responsivity point, so I need to change the Thread.sleep() into something else, but I have no idea how to do this in an easy way.
Thanks in advance for any advice.
I've done a simple game or two with Java and to handle the main game loop I've used a Swing Timer. The timer will allow you to set an ActionListener to be fired after a provided delay has elapsed. The in-between delay would be derived from your frame rate. The most basic usage would look like:
Timer timer = new Timer(delay, listener);
timer.start();
This would set the initial and in-between delays to the same value. You could also set them to be different values if needed like so:
Timer timer = new Timer(delay, listener);
timer.setInitialDelay(0);
timer.start();
In the above example, the listener will fire ASAP after starting and with a delay in-between thereafter.
A better idea is to use a Timer as suggested above which will allow you to trigger after a specified delay without calling sleep().
if you want it a little more complicated but self-made start a new Thread to handle the sleeps.
You can put pooling mechanism with some pooling frequency to avoid thread.sleep.Put your condition in while loop and wait for some tine if condition is not met.And wait time should be less so it will poll with small interval.
//more code here It is a sample code
synchronized(this) {
while (delta < model.getFrameTime()) {
this.wait(500);
}
//more code
Related
while(!isRunning){
now = getSystemTime();
deltaTime = now - lastTime;
lastTime = now;
if(deltaTime >= 1000){
//do something
}
}
This piece of code looks awkward to me. I want the thread to "do something" every 1000 units of time, but the while loop will run infinitely before 1000 units of time passes, which wastes resoure of CPU. How do you think I could refactor this piece of pseudo code? Notice that it may be true that "do something" may take more than 1000 units of time.
PS:
I am coding using java and want a solution to the problem with Java.
Take a look at Java scheduled executors. There is a method called scheduleAtFixedRate you can use. There is a class called TimeUnit which is used in this method to make things run at certain periods. Disadvantage to this is you have to create a instanve of Callable or Runnable which is a bit clunky in my opinion
First, I would make a function just to keep track of time so the code looks cleaner. Second, if you put a sleep inside the while so we dont occupy CPU time with busy wait. You can have more timed sections with more timer variables.
int countTime(int & time){
now = getSystemTime();
deltaTime = now - time;
lastTime = now;
return deltaTime
}
...
while(!isRunning){
if(countTime(timer) >= 1000){
//do something
}
usleep(100000) // sleep so we don't occupy CPU
}
The problem here is that the code is performing a busy wait, meaning, wasting CPU cycles until delta is bigger than 1 second.
It would be better to simply sleep for a second instead, and allow other processes to take advantage of the CPU cycles while your process is doing nothing:
while(!isRunning){
doSomething();
sleep(1000); // see implementation below
}
...
void sleep(int milli) {
try {
Thread.sleep(milli);
} catch (InterruptedException e) {
// ignore
}
}
Is it going to run forever? What is the context?
Try to make it like this:
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
final Runnable beeper = new Runnable() {
public void run() { algorithm something here! }
};
final ScheduledFuture<?> beeperHandle =
scheduler.scheduleAtFixedRate(beeper, 1000, 1000, TimeUnit.MILLISECONDS);
Maybe it solve your problem!
If you have some question about the methods posted above, please check the oracle documentation:
https://docs.oracle.com/javase/6/docs/api/java/util/concurrent/ScheduledExecutorService.html
I want to have a thread that loops at a constant amount of times per second for example a render loop that aims for a constant framerate. The loop would obviously slow if the time it takes exceeds the time allowed.
Thanks.
How about
ScheduledExecutorService ses = Executors.newSingleThreadScheduledExecutor();
ses.scheduleAtFixedRate(0, delay, TimeUnit.MILLI_SECONDS, new Runnable() {
public void run() {
// do something
}
});
or
long delay = ....
long next = System.currentTimeMillis();
while(running) {
// do something
next += delay;
long sleep = next - System.currentTimeMillis();
if (sleep > 0)
Thread.sleep(sleep);
}
There are two basic techniques you need two consider:
seperate updateing your model or state of the world from rendering it.
If you have done that, you can sleep/wait the appropriate amount of time before rendering stuff or skip the rendering for some frames if you fall behind your planed schedule.
I can recommend two good tututorials on how to implement something like a game loop in java/android.
First one about the basics is http://obviam.net/index.php/a-very-basic-the-game-loop-for-android/
and the second one has a focus on constant Frames per Second: http://obviam.net/index.php/the-android-game-loop/. I think the lessons apply to regualar java as well.
Im trying to get a timer to work in my current java project that adds 1 to an integer variable every n microseconds (e.g. 500 for 1/2 a second), within an infinite loop, so that it is always running while the program runs.
Heres the code i have currently:
public class Ticker
{
public int time = 0;
long t0, t1;
public void tick(int[] args)
{
for (int i = 2; i < 1; i++)
{
t0 = System.currentTimeMillis();
do
{
t1 = System.currentTimeMillis();
}
while (t1 - t0 < 500);
time = time + 1;
}
}
}
Everyone was so helpful with my last question, hopefully this one is just as easy
Here is an comparable ScheduledExecutorService example which will update the time variable with a 500 millisecond interval:
ScheduledExecutorService exec = Executors.newScheduledThreadPool(1);
exec.scheduleAtFixedRate(new Runnable(){
private int time = 0;
#Override
public void run(){
time++;
System.out.println("Time: " + time);
}
}, 0, 500, TimeUnit.MILLISECONDS);
This approach is preferred over using Timer.
I think you want
Thread.sleep(500);
At the moment you're consuming CPU cycles waiting for 500ms (you mention microseconds but I believe you want milliseconds). The above puts your current thread to sleep for 500ms and your process won't consume any CPU (or minimal at least - garbage collection will still be running). If you watch the CPU when you run your version you should see the difference.
See here for more info.
If you need to do it in a different thread, take a look on Timer:
int delay = 500; //milliseconds
ActionListener taskPerformer = new ActionListener() {
public void actionPerformed(ActionEvent evt) {
time++
}
};
new Timer(delay, taskPerformer).start();
Note that the code above cannot utilize a local variable (they must be declared as final to access them in an anonymous class). It can be a member however.
What you have is rather inefficient, since it wastes CPU cycles waiting for the next wakeup time. If I were you, I'd rewrite the function using Thread.sleep().
As to why your current code doesn't work, your for loop conditions are off, so the loop is never entered.
To have the timer code run concurrently with whatever other logic you have in your program, you'll need to look into threading.
It sounds like you might want to look into multithreading. If you search SO for this, you will find several good question/answer threads. There are also tutorials elsewhere on the web...
Have a look at Timer or better ScheduledExecutorService. They enable you to execute some action periodically and handle the computations surrounding that.
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().
I'm trying to get a JProgressBar to increment by 1 every 100th of a second, and at the moment I'm using Thread.sleep(100) inside a while statement like so:
try {
while (i<=100){
doTime();
}
} catch (InterruptedException ex) {
Logger.getLogger(SplashScreen.class.getName()).log(Level.SEVERE, null, ex);
}
public void doTime() throws InterruptedException{
jLabel1.setText("sleeping");
Thread.sleep(100);
jLabel1.setText("start");
i++;
pb.setValue(i);
pb.repaint();
}
and If I debug by doing a System.out.println it displays in real time but the swing GUI freezes until it drops out of the while loop can anyone help?
thanks
matt
As derivation said, you should use SwingWorker. From its javadoc:
"SwingWorker is designed for situations where you need to have a long running task run in a background thread and provide updates to the UI either when done, or while processing. Subclasses of SwingWorker must implement the doInBackground() method to perform the background computation."
With this slight change to ProgressBarDemo.java in the java tutorial, you almost get what you want.
public Void doInBackground() {
Random random = new Random();
int progress = 0;
//Initialize progress property.
setProgress(0);
while (progress < 100) {
//Sleep for up to one second.
try {
//original code: Thread.sleep(random.nextInt(1000));
Thread.sleep(10);
} catch (InterruptedException ignore) {}
//Make random progress.
//originalcode: progress += random.nextInt(10);
progress++;
setProgress(Math.min(progress, 100));
}
return null;
}
The problem is that you are sleeping the Swing Event thread. You'll want to create a new thread for running the loop, and then have that loop update the progressbar on the swing event thread.
I would use the Swing Worker thread for the loop. Then use invokeLater for updating the progressbar.
Another good swing/thread tutorial.
Besides what derivation said, you are sleeping for 100 milliseconds. That means you are only updating every tenth of a second, not every hundredth.
If doTime() is being called within the Event Dispatch Thread (EDT), which it should since it is calling UI code (jLabel1.setText() and others), then it should not be calling sleep() at all. You do not want to freeze your UI.
The correct way of doing this is to use a timer to wake up in the correct moments (say, every 10 ms) and update the progress. The code by Jala is also a good answer, and it is the official Swing Way of doing things (timers are lower level than SwingWorkers).