1
0
Fork 0
fgdata/Aircraft/Generic/update_loop.nas

148 lines
3.9 KiB
Text
Raw Normal View History

# update_loop.nas - Generic Nasal update loop for implementing sytems,
# instruments or physics simulation.
#
# Copyright (C) 2014 Anton Gomez Alvedro
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 2 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
# Component
#
# The update loop accepts a vector of Components that it will update at regular
# intervals. In order to make custom components, you should add Component to
# the parents vector of your object:
#
# var CustomComponent = {
# parents: [Component],
# ...
# };
#
# Your component shall then implement an "update" and a "reset" methods that
# the UpdateLoop will call when needed.
var Component = {
reset: func { },
update: func(dt) { },
};
##
# Helper generator for updating a property on every element update
#
# Example:
#
# var needle = Dampener.new(
# input: probe,
# dampening: 2.8,
# on_update: update_prop("/instrumentation/variometer/te-reading-mps"));
#
# See Aircraft/Instruments-3d/glider/vario/ilec-sc7.nas and
# Aircraft/Generic/soaring-instrumentation-sdk.nas for usage examples.
# You can also refer to the soaring sdk wiki page.
var update_prop = func(property) {
func(value) { setprop(property, value) }
};
# UpdateLoop
# Wraps a set of components and updates them periodically.
# Takes care of critical sim signals (reinit, fdm-initialized, speed-up).
var UpdateLoop = {
# UpdateLoop.new(components, [update_period], [enable])
#
# components: Vector of components to update on every iteration.
# update_period: Time in seconds between updates (optional).
# enable: Enable the loop immediately after creation (optional).
new: func(components, update_period = 0, enable = 1) {
var m = { parents: [UpdateLoop] };
m.initialized = 0;
m.enabled = enable;
m.update_period = update_period;
m.time_last = 0;
m.sim_speed = 1;
m.components = (components != nil)? components : [];
m.timer = maketimer(update_period,
func { call(me._update, [], m) });
m.lst = [];
append(m.lst, setlistener("/sim/speed-up",
func(n) { m.sim_speed = n.getValue() }, 1, 0));
append(m.lst, setlistener("sim/signals/reinit", func {
m.timer.stop();
m.initialized = 0;
}));
append(m.lst, setlistener("sim/signals/fdm-initialized", func {
if (m.timer.isRunning) m.timer.stop();
call(me.reset, [], m);
if (m.enabled) m.timer.start();
}));
return m;
},
del: func {
foreach (var l; me.lst) removelistener(l);
},
##
# Resets internal state for all components controlled by the loop.
# It is of course responsibility of every component to clean their internal
# state appropriately.
reset: func {
me.time_last = getprop("/sim/time/elapsed-sec");
foreach (var component; me.components)
component.reset();
me.initialized = 1;
},
##
# Enables the loop if it was disabled, i.e. the loop will start updating
# the components under control
enable: func {
if (me.initialized) me.timer.start();
me.enabled = 1;
},
##
# Disables the loop if it was enabled, i.e. the loop will freeze and its
# components will not get updates until enabled again
disable: func {
me.timer.stop();
me.enabled = 0;
},
_update: func {
var time_now = getprop("/sim/time/elapsed-sec");
var dt = (time_now - me.time_last) * me.sim_speed;
if (dt == 0) return;
me.time_last = time_now;
foreach (var component; me.components)
component.update(dt);
},
};