Difference between revisions of "Oolite JavaScript Reference: Timer"

From Elite Wiki
(Moving Oolite JS reference into a subcategory of Oolite scripting.)
(Added more about Frame Callbacks)
 
(13 intermediate revisions by 8 users not shown)
Line 1: Line 1:
 
<small>'''Prototype:''' <code>Object</code></small><br />
 
<small>'''Prototype:''' <code>Object</code></small><br />
<small>'''Subtypes:''' none
+
<small>'''Subtypes:''' none</small>
 
 
{{Oolite-class-added|1.70}}
 
  
 
'''Timer''' objects are used to perform tasks after a delay or on a repeating schedule. When a timer is created, it is given a function to call, and a ''delay'' and an optional ''interval'' in seconds in [[Time scales in Oolite#Game real time|game real time]]. The ''next fire time'' of the timer is set to the current time + the delay. When the game clock reaches (or passes) the next fire time, the function is called. If the timer has a positive interval, the interval is added to the next fire time. Otherwise, the timer stops.
 
'''Timer''' objects are used to perform tasks after a delay or on a repeating schedule. When a timer is created, it is given a function to call, and a ''delay'' and an optional ''interval'' in seconds in [[Time scales in Oolite#Game real time|game real time]]. The ''next fire time'' of the timer is set to the current time + the delay. When the game clock reaches (or passes) the next fire time, the function is called. If the timer has a positive interval, the interval is added to the next fire time. Otherwise, the timer stops.
  
'''Note:''' in order for a timer to work consistently, you must keep a reference to it as long as it is in use. The easiest way is to make it a property of your script: <code>this.timer = new Timer(this, this.doSomething, 5, 5)</code>. If this is not done, the JavaScript runtime may delete the timer at any time to free up memory.
+
'''Note:''' in order for a timer to work consistently, you must keep a reference to it as long as it is in use. The easiest way is to make it a property of your script: <code>this._timer = new Timer(this, this.doSomething, 5, 5)</code>. If this is not done, the JavaScript runtime may delete the timer at any time to free up memory.
 
 
'''N.B.:''' Before 1.74, timers associated with ship scripts did not stop when the ship itself died.
 
If scripting for Oolite 1.73.4 or earlier, either the timer is deleted inside the ship's this.shipDied, or a check for the existence of the ship must be placed inside the timer itself, as in the timers examples at the bottom of this page. Timers run independent of the script and are not deleted with a ship script. When the timer is not stopped and uses a property of a removed ship script, it can crash Oolite.
 
  
 
== Constructor ==
 
== Constructor ==
 
  '''new Timer'''(this : Object, function : Function, delay : Number [, interval : Number]) : Timer
 
  '''new Timer'''(this : Object, function : Function, delay : Number [, interval : Number]) : Timer
Creates a new timer which will call <code>function</code> after <code>delay</code> seconds, and optionally repeatedly every <code>interval</code> seconds. If <code>delay</code> is zero or more, the timer will be started automatically. If <code>interval</code> is 0 or less, the timer will not repeat. If <code>interval</code> is greater than 0 but less than 0.25, it will be rounded up to 0.25.
+
Creates a new timer which will call <code>function</code> after <code>delay</code> seconds, and optionally repeatedly every <code>interval</code> seconds. If <code>delay</code> is zero or more, the timer will be started automatically. If <code>interval</code> is 0 or less, the timer will not repeat. If <code>interval</code> is greater than 0 but less than 0.25, it will be rounded up to 0.25. The timer "fires" roughly 4 times a second. For more accuracy (needed for ''eg''. animations, see Frame Callbacks in links below).
  
'''N.B.:''' as of Oolite 1.74, if the first parameter ('this : Object') goes out of scope (usually because the ship attached to the 'this' object is destroyed, or left behind when the player executes a hyperspace jump), the timer will now be stopped and removed automatically.
+
 
 +
If <code>delay</code> is negative and <code>interval</code> is positive, the timer will initially be stopped. After it is started, it will fire at multiples of <code>interval</code> after its creation time. For instance, if a timer is created stopped with a five-second interval, and started after seven seconds, it will fire after three seconds (which is ten seconds after it was created).
 +
 
 +
If the <code>this</code> parameter becomes invalid (usually because it’s attached to a ship that’s destroyed, or left behind when the player executes a hyperspace jump), the timer will be stopped and removed automatically. You should use [[Oolite JavaScript Reference: Ship script event handlers#entityDestroyed|entityDestroyed]] in ship scripts to clean up timers.
  
 
== Properties ==
 
== Properties ==
Line 21: Line 19:
 
  '''interval''' : Number (read/write)
 
  '''interval''' : Number (read/write)
 
The rate at which the timer repeats. For a one-shot timer, this will be -1. If set to 0 or a negative number, it will be treated as -1. If set to a number between 0 and 0.25, it will be rounded up to 0.25.
 
The rate at which the timer repeats. For a one-shot timer, this will be -1. If set to 0 or a negative number, it will be treated as -1. If set to a number between 0 and 0.25, it will be rounded up to 0.25.
 
=== isPersistent ===
 
{{Oolite-script-item-deprecated|property|1.74|test}}
 
'''isPersistent''' : Boolean (read/write)
 
A persistent timer will continue to run when the game resets (i.e., the player dies or loads a new game). A non-persistent timer will be stopped when the game is reset (but can be restarted using <code>[[#start|start()]]</code>). Timers are not persistent by default.
 
  
 
=== isRunning ===
 
=== isRunning ===
Line 44: Line 37:
 
Stops the timer, if it is currently running.
 
Stops the timer, if it is currently running.
  
 +
Important: Always stop a timer before deleting its JS reference, or a copy of the object will stay around in a timer queue and will keep firing. Without explicit stopping, the timer will only stop with an error when the script it belongs to no longer exists.
  
== Examples ==
+
== Links ==
 
+
*[https://bb.oolite.space/viewtopic.php?f=3&t=21355 Unrooted Timers and Garbage Collection] (Nite Owl, 2023)
Timer connected to ship. When the ship dies or when the player leaves the system, its timer is removed.
+
=== Frame Callbacks ===
 
+
Frame callbacks are user-defined JavaScript functions that run on every single game "frame update".
this.shipSpawned = function () {
+
*[https://bb.oolite.space/viewtopic.php?p=256981#p256981 The normal, widely-used standard for creating the callback function] (Phkb, 2017)
    this.shipTimer = new Timer(this, this.testTimer, 10, 10);
+
*[https://bb.oolite.space/viewtopic.php?t=8941 Jens Ayton explaining frame callbacks] (2011)
    delete this.shipSpawned;
 
};
 
 
this.shipDied = function () {
 
    if (this.shipTimer) {
 
        this.shipTimer.stop(); delete this.shipTimer;
 
    }
 
    // other shipDied actions.
 
        ...
 
};
 
 
this.playerWillEnterWitchspace = function () {
 
    if (this.shipTimer) {
 
        this.shipTimer.stop(); delete this.shipTimer;
 
    }
 
        ...
 
};
 
 
this.testTimer = function () {
 
    // main timer code.
 
    ...
 
};
 
 
 
Timer connected to ship. The timer itself keeps track of the ship it's attached to, and removes itself when necessary.
 
 
 
this.shipSpawned = function () {
 
    this.shipTimer = new Timer(this, this.testTimer, 10, 10);
 
    delete this.shipSpawned;
 
};
 
 
this.testTimer = function () {
 
    // stop the timer if its associated ship doesn't exist anymore
 
    if (!this.ship || !this.ship.isValid) {
 
        log(this.name, "ERROR detected; Timer fired but this.ship is undefined");
 
        if (this.shipTimer) {
 
            this.shipTimer.stop();
 
            delete this.shipTimer;
 
        }
 
        return;
 
    }
 
    // main timer code.
 
    ...
 
};
 
 
 
'''N.B.:''' as of Oolite 1.74, timers will be removed automatically by Oolite when the 'this' object goes out of scope, without the need to use any of these examples.
 
  
[[Category:Oolite JavaScript reference]]
+
[[Category:Oolite JavaScript Reference]]

Latest revision as of 10:58, 31 July 2024

Prototype: Object
Subtypes: none

Timer objects are used to perform tasks after a delay or on a repeating schedule. When a timer is created, it is given a function to call, and a delay and an optional interval in seconds in game real time. The next fire time of the timer is set to the current time + the delay. When the game clock reaches (or passes) the next fire time, the function is called. If the timer has a positive interval, the interval is added to the next fire time. Otherwise, the timer stops.

Note: in order for a timer to work consistently, you must keep a reference to it as long as it is in use. The easiest way is to make it a property of your script: this._timer = new Timer(this, this.doSomething, 5, 5). If this is not done, the JavaScript runtime may delete the timer at any time to free up memory.

Constructor

new Timer(this : Object, function : Function, delay : Number [, interval : Number]) : Timer

Creates a new timer which will call function after delay seconds, and optionally repeatedly every interval seconds. If delay is zero or more, the timer will be started automatically. If interval is 0 or less, the timer will not repeat. If interval is greater than 0 but less than 0.25, it will be rounded up to 0.25. The timer "fires" roughly 4 times a second. For more accuracy (needed for eg. animations, see Frame Callbacks in links below).


If delay is negative and interval is positive, the timer will initially be stopped. After it is started, it will fire at multiples of interval after its creation time. For instance, if a timer is created stopped with a five-second interval, and started after seven seconds, it will fire after three seconds (which is ten seconds after it was created).

If the this parameter becomes invalid (usually because it’s attached to a ship that’s destroyed, or left behind when the player executes a hyperspace jump), the timer will be stopped and removed automatically. You should use entityDestroyed in ship scripts to clean up timers.

Properties

interval

interval : Number (read/write)

The rate at which the timer repeats. For a one-shot timer, this will be -1. If set to 0 or a negative number, it will be treated as -1. If set to a number between 0 and 0.25, it will be rounded up to 0.25.

isRunning

isRunning : Boolean (read-only)

true if the timer is running, false if it is stopped.

nextTime

nextTime : Number (read/write when stopped)

The next time the timer will fire, if it is running at that time. This can be modified if the timer is stopped. Note that this is an absolute time, not a delay. You can get the current absolute time using clock.absoluteSeconds.

Methods

start

function start() : Boolean

Starts the timer, if it is not currently running. This will fail if it is a one-shot timer (i.e., its interval is -1) and its nextTime is in the past. Returns true if successful or the timer was already running, false on failure (i.e., the same as isRunning after start() is called).

stop

function stop()

Stops the timer, if it is currently running.

Important: Always stop a timer before deleting its JS reference, or a copy of the object will stay around in a timer queue and will keep firing. Without explicit stopping, the timer will only stop with an error when the script it belongs to no longer exists.

Links

Frame Callbacks

Frame callbacks are user-defined JavaScript functions that run on every single game "frame update".