How Do I time events?

Let’s say I want some event to happen 2 seconds after the clock starts, then have a second event occur 2 more seconds (4 total) after that.

How can this be accomplished in a game?

You keep these variables:
time = 0f, threshold = 2f,
count = 0, event[] = {event0, event1}

Every frame you do:

time = time + delta
if time >= threshold and count < event.length
    execute event[count]
    time = time - threshold
    count = count + 1

delta is the time in seconds between update/render loop calls (60fps ~> 0.016s).
:-*

…Or you could just use the java.util.Timer class, which allows you schedule delayed events. However, this happens on a different thread, so I don’t know if the Timer class is what you want…

He’s talking about having this in a game, his event is probably modifying game data, it would be suicide (or at least too much effort and also inconsistent with game time) to use an asynchronous threaded timer.

Don’t you mean 0.016 mins?

Well, in that case, I guess he should just do it on the main thread.

search is your friend…

http://www.java-gaming.org/index.php?topic=24220.0

http://lmgtfy.com/?q=0.016s+to+ms

I keep a custom timer which is updated automatically at the same time as game update events. Here is the class I’m using.

https://github.com/sriharshachilakapati/SilenceEngine/blob/silenceengine-1.0.1/silenceengine/src/main/java/com/shc/silenceengine/utils/GameTimer.java

It is just implemented based on keeping track of elapsed time since last update. These should be updated each frame, and the callback is called once the elapsed time is greater than the scheduled time. And the usage, how I use it.

[icode]Run once timer[/icode]


GameTimer timer = new GameTimer(2, TimeUtils.Unit.SECONDS);
timer.setCallback(() ->
{
    // Do the timer task here.
});
timer.start();

[icode]Repeating timer[/icode]


GameTimer timer = new GameTimer(2, TimeUtils.Unit.SECONDS);
timer.setCallback(() ->
{
    // Do the timer task here.

    // Reschedule the timer
    timer.setTime(newTime, newUnit);
    timer.start();
});
timer.start();

In case you didn’t set the new time, it will just use the old values. Hope this helps.

Just keep track of game time. You actions are scheduled to take place at some point in the future. When the time passes a certain point, do the action.

When triggering events from another thread, which I do a lot (e.g., between the GUI and my audio-processing thread, or the audio-processing and the game loop thread), a good technique is to have one thread throw a flag on the other, often via a volatile boolean. The other thread spots the flag and acts accordingly.

I’m not sure if this is strictly the design pattern named “loose coupling” or just one form of it. But it is good to understand patterns for messaging between threads. If one is worried about opening up a can of worms by using another thread, maybe the real concern should be that one is holding a can of worms, and that looser-coupling/better messaging would improve the structure of the code.

@philfrei

Any chance you could provide a simple example?
I feel this would be the best way going about things since I wish to sync to an audio clip.


import java.awt.Color;
import java.util.Timer;
import java.util.TimerTask;

public class Avatar {

	public enum EmotionalState { GLOWING, DEPRESSED, ENVIOUS, EMBARRASSED };
	
	private EmotionalState currentEmo;
	private Color avatarColor;
	private volatile boolean changeEmotions;
	
	private Color golden = new Color( 248, 248, 0 );
	
	// This next method is the "loosely coupled" hook.
	// We don't DO anything here except flip a switch. 
	// The thread with the game loop updates and renders in its own time.
	public void setChangeEmotions(boolean bool)
	{
		changeEmotions = bool;
	}	
	
	public void update()
	{	
		if (changeEmotions)
		{
			// clear flag
			changeEmotions = false;

			int random = (int)(Math.random() * 4);
			switch (random)
			{
			case 0: currentEmo = EmotionalState.GLOWING; break;
			case 1: currentEmo = EmotionalState.DEPRESSED; break;
			case 2: currentEmo = EmotionalState.ENVIOUS; break;
			case 3: currentEmo = EmotionalState.EMBARRASSED ; 
			}			
		}
	}
	
	public void render()
	{
		switch (currentEmo)
		{
		case GLOWING:
			avatarColor = golden;
			break;
		case DEPRESSED:
			avatarColor = Color.BLUE;
			break;
		case ENVIOUS:
			avatarColor = Color.GREEN;
			break;
		case EMBARRASSED :
			avatarColor = Color.RED;			
		}
		
		drawAvatar(avatarColor);
	}
	
	private void drawAvatar(Color color) 
	{
		// draws avatar based on current emotional state
	}
}
	
	
class GameLoopThread 
{
	private boolean running;
	private Avatar avatar;
	
	public GameLoopThread(Avatar avatar)
	{
		this.avatar = avatar;
	}
	
	public void run()
	{
		while (running)
		{
			// ...code to regulate frame rate to 60 fps...
			
			avatar.update();
			avatar.render();
		}
	}
}


class LaunchTimerTask
{
	Timer timer = new Timer();
	
	public void launchTask(Avatar avatar)
	{
		EmotionTrigger triggerTask = new EmotionTrigger();
		triggerTask.avatar = avatar;
		
		timer.schedule(triggerTask, 1000 * 60, 1000 * 60);
	}
	
	
	class EmotionTrigger extends TimerTask
	{
		public Avatar avatar;
		
		@Override
		public void run() 
		{
			avatar.setChangeEmotions(true);
		}
	}
}

The main tools for triggering from audio are the Listeners that monitor when a Clip or SourceDataLine opens/starts/ends/closes, that sort of thing. The design pattern, I think, is called “Observer”. Check the method:
javax.sound.sampled.line.addLineListener

Also this:
http://docs.oracle.com/javase/7/docs/api/javax/sound/sampled/LineEvent.html

For more granularity, I count sound frames and have rolled my own “Listener” equivalent.
For the following link, see the last section “Manipulating the Audio Data Directly”
http://docs.oracle.com/javase/tutorial/sound/controls.html