On Timer node design

The current design of the On Timer node doesn’t seem very practical. Since it’s only good for measuring time from the beginning of the game, it can’t perform a basic function like delaying action. While an appropriate behaviour can be built using the more atomic Time node, timers are such a common thing in games that it merits a bigger, more functional node to handle common use cases.

IMHO a good timer node would have the following inputs and outputs:

(impulse) Start - impulse to start the timer
(impulse) Pause - impulse to stop the timer
(impulse) Stop - impulse to interrupt a timer, or stop repeating and reset the time and Repetition counter to zero
(float, seconds) Duration - timer length in seconds
(bool) Repeat - in addition to using the Stop impulse to stop the timer, this bool should be checked for at the beginning of every repetition
(int) Repetitions - the timer should stop automatically after this number of repetitions. Used only if Repeat is true. If it’s set to 0, the node will repeat forever.

(impulse) Out - this main output fires the timed event
(bool) Running - returns true if the timer is active, false if it’s stopped or paused.
(float, seconds) Seconds Passed -returns seconds since the timer, or current repetition was started
(float, seconds) Seconds Left - returns seconds left until Out fires
(normalized float) Progress - convenience feature, while this can be calculated from the other outputs, this would be immensely useful for progress bars and the like, and reduce the node spaghetti.
(int) Repetitions - returns number of repetitions completed since the timer was started. It should be incremented at the beginning of each loop. Alternatively, this could output a float that gives an exact fractional value of repetitions completed (e.g. 3.5 repetitions), and would also obviate the need for the Progress output, but then people will inevitably run into issues with float precision when they check for this with an Equal comparison.

The current behaviour of measuring time since the beginning of the game can easily be implemented with this just by connecting an On Init to the Start input.

As before, this is meant more as a starting point for a discussion than a final design.

I’ve also posted this in the issue tracker: https://github.com/armory3d/armory/issues/612

1 Like

To fuel this initial discussion, I needed a loop on objects stored in a Array with the ability to manage, in addition to their indice, a delay between each loop, thus action… if it can help thereafter the “Array Loop Indice Wait”


and it’s code

package armory.logicnode;
class ArrayLoopIndiceWaitNode extends LogicNode {
	var value:Dynamic;
var index:Int;
var ar:Array<Dynamic>;
var artaille:Int;
var time:Float;
public function new(tree:LogicTree) {

override function run() {
	ar = inputs[1].get();
	artaille = ar.length;
	time = inputs[2].get();
	index = 0;
	if(artaille > 0) iron.system.Tween.timer(time, done);
	else runOutputs(2);		

function done() {		
	value = ar[index];
	index = index +1;
	if( index <  artaille ) iron.system.Tween.timer(time, done);
	else runOutputs(2);

override function get(from:Int):Dynamic {
	if (from == 1) return value;
	else if (from == 3) return index;
	else return index;