How to delay somthing without stopping the gameloop?

Hi!
I’m trying to delay something in my game and the only thing I found in the internet is Thread.sleep but the problem is that it stops my gameloop.
I also tryed this:


		while(alive == false) {
			timer ++;
			if(timer > 10){
				handler.NextLevel();
				timer = 0;
			}
			

and it freezed the game.
What is the right way to do it? thanks!

See: Timers. It works by creating a separate thread for timing things. You can start the timer, and it will not pause your loop.

EDIT:
As PandaMoniumHUN pointed out, multithreading actually isn’t too optimal unless you need extreme accuracy. I would recommend his approach before you use threads.

replace the while with an if, and place the block inside your game loop -

while(!endFlag)
{
//Game loop goes here

if (alive == false)
{
timer ++;
if(timer > 10)
{
handler.NextLevel();
timer = 0;
}
}
}

The reason the while loop froze your game loop, is because whilst you were looping around inside the alive==false loop, you never updated anything else of the game. Which means nothing got drawn or updated - causing everything to freeze.:slight_smile:

Bear in mind though, that code will make the timer wait for 10 frames. Which is about a 6th of a second, assuming your game is running at 60fps - you probably won’t notice the delay. Consider setting it to something higher, like 60.

While what ipe says is right, I think your “int timer” was just for test, I think you want ‘real’ time (like 10 seconds?).
In that case, what wessles suggests is right, but only if you use Java2D… (at least many libraries (like libgdx) don’t support multithreading and so don’t support the Timer class).

Well lucky you, you can easily make a timer yourself:


long startMillisTime = System.currentMillis(); //do this whenever timer has to start
boolean timer = true;
// do this in your gameLoop:
if(timer && System.currentMillis()-startMillisTime >= 10000){ //10 seconds here
   handler.NextLevel();
   timer = false;
}

Thanks, work great !!

Yes, the timer was just for test I’m using like 5 seconds now.
At first I had a problem that it didnt stop moving levels but then I saw your idea of setting a boolean timer, thanks!!

How do I change the subject to solved?

Do NOT use Timers on separate threads.
Unless you have some very specific reason to do that (like the need to start events with extreme time accuracy) you should be always handling timed events in your game loop.
Check the current time on every frame and if it’s more than the beginning of the event’s time trigger the event.
The accuracy of this method will depend on the framerate of your game (at 60FPS the worst case scenario is that the time will off by ~16.66ms) but this way you don’t have to deal with concurrency issues and context switching only for a timer.
Also your original code with the timer counter is a framerate based solution and not a time based one. If the framerate varies the event may trigger way earlier or later than you want it to.

Here’s a code example that you can run in your game loop to handle timed events:


long eventStart = System.currentTimeMillis()+5000L;
		
public void yourGameLoop(){
	long time = System.currentTimeMillis();
	if(time >= eventStart){
		triggerEvent();
		// ...
	}
}

Side note here’s that Java’s [icode]System.currentTimeMillis();[/icode] can be pretty inaccurate on some machines so you might want to consider switching to [icode]System.nanoTime();[/icode] or if you’re using LWJGL just use the [icode]Sys.getTime()*1000f/Sys.getTimerResolution();[/icode] method to get the current unix time in millis. :slight_smile:

Wouldn’t eventtime always be greater than time? How does eventtime become less than or equal to time? I don’t understand.

Time is always increasing. Basically, it’s saying “when the current time is greater or equal to than 5 seconds after the starting time”

[quote=“AppleSauce,post:7,topic:49880”]
I was trying to demonstrate this with a usable demo, that’s why I set [icode]eventStart[/icode] to [icode]System.currentTimeMillis()+5000L[/icode] and not some random value like [icode]53246[/icode].
In my code I suppose that the eventStart variable is declared in a class, meaning that it will be initialized only once per class (when you create an instance of that class) and will not be increased or modified as the time goes on.
I thought it should be pretty obvious because of the [icode]public void yourGameLoop(){…[/icode] underneath that this is inside a class but if not sorry for the confusion.

Comparing timestamps is indeed the way to go. Typing this in somewhat quickly but it should be pretty good:


abstract class Event implements Runnable {
	
	final long timestamp;
	
	public Event(long millisFromNow) {
		timestamp = System.nanoTime() + millisFromNow * 1000000L;
	}
}

class EventManager {
	
	private static final Comparator<Event> COMPARATOR = new Comparator<Event>() {
		public int compare(Event e1, Event e2) {
			return Long.compare(e1.timestamp, e2.timestamp);
		}
	};
	
	private final PriorityQueue<Event> queue = new PriorityQueue<Event>(10, COMPARATOR);
	
	public void add(Event e) {
		queue.add(e);
	}
	
	public void tick() {
		while (!queue.isEmpty() && queue.peek().timestamp < System.nanoTime())
			queue.remove().run();
	}
}

Just call manager.tick(); each iteration of your gameloop.

Either extend Event or use an anonymous class for those quick little tasks that need to be scheduled:

manager.add(new Event(5000) {
    public void run() {
        System.out.println("Hello World! I'm late!");
    }
});

Priority Queue = good answer.

Yep, tick() is O(1) when all events are in the future as it only has to check the top of the queue, so it doesn’t slow down when you have lots of events piling up. Just for posterity.