From a978a79d1626af6b8a9162b6fa7884d407720afc Mon Sep 17 00:00:00 2001 From: ehofman Date: Wed, 30 Mar 2005 09:53:00 +0000 Subject: [PATCH] Melchior FRANZ: - light class added (for lights and other pulsing/blinking objects) - fixed and improved documentation - all property args may be path strings or nodes - existing nodes aren't overwritten any more - better naming of class vars (for outside access) Tested with the bo105 (which I fully ported to use aircraft.nas) and the fokker70 (which are the only aircraft using the new classes :-) --- Nasal/aircraft.nas | 174 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 148 insertions(+), 26 deletions(-) diff --git a/Nasal/aircraft.nas b/Nasal/aircraft.nas index a7e2dd177..f3d20d4a2 100644 --- a/Nasal/aircraft.nas +++ b/Nasal/aircraft.nas @@ -1,16 +1,61 @@ -# door: class for objects moving at constant speed, with the ability to +# These classes provide basic functions to use in aircraft specific +# Nasal context. Note that even if a class is called "door" or "light" +# this doesn't mean that it can't be used for other purposes. The classes +# implement only commonly used features, but are easily to extend, +# as all class members are accessible from outside. For example: +# +# # add custom property to door node: +# frontdoor.node.getNode("name", 1).setValue("front door"); +# +# # add method to class instance (or base class -> aircraft.door.print) +# frontdoor.print = func { print(me.position.getValue()) }; +# +# Wherever a property argument can be given, this can either be a path, +# or a node (i.e. property node hash). For example: +# +# beacon = aircraft.light.new("sim/model/foo/beacon"); +# +# strobe_node = props.globals.getNode("sim/model/foo/strobe", 1); +# strobe = aircraft.light.new(strobe_node, 0.05, 1.0); +# +# Classes do create properties, but they don't usually overwrite the contents +# of an existing property. This makes it possible to preset them in +# a *-set.xml file or on the command line. For example: +# +# $ fgfs --aircraft=bo105 --prop:/controls/doors/door[0]/position-norm=1 + + + +# helper functions +# ============================================================================== +# creates (if necessary) and returns a property node from arg[0], +# which can be a property node already, or a property path +# +makeNode = func { + if (isa(arg[0], props.Node)) { + return arg[0]; + } else { + return props.globals.getNode(arg[0], 1); + } +} + + + +# door +# ============================================================================== +# class for objects moving at constant speed, with the ability to # reverse moving direction at any point. Appropriate for doors, canopies, etc. # # SYNOPSIS: # door.new(, [, ]); # -# property ... parent property (available as door.base) +# property ... door node: property path or node # swingtime ... time in seconds for full movement (0 -> 1) # startpos ... initial position (default: 0) # # PROPERTIES: -# /position-norm (type="double") -# /enabled (type="bool") +# /position-norm (double) +# /enabled (bool) # # EXAMPLE: # canopy = aircraft.door.new("sim/model/foo/canopy", 5); @@ -18,44 +63,121 @@ # door = { new : func { - d = { parents: [door] }; - d.base = props.globals.getNode(arg[0], 1); - d.pos = d.base.getNode("position-norm", 1); - d.enabled = d.base.getNode("enabled", 1); - d.enabled.setBoolValue(1); - + d = { parents : [door] }; + d.node = makeNode(arg[0]); d.swingtime = arg[1]; + d.position = d.node.getNode("position-norm", 1); + d.enabled = d.node.getNode("enabled", 1); + if (d.enabled.getValue() == nil) { + d.enabled.setBoolValue(1); + } pos = if (size(arg) > 2 and arg[2] != nil) { arg[2] } else { 0 }; - d.pos.setDoubleValue(pos); + if (d.position.getValue() == nil) { + d.position.setDoubleValue(pos); + } d.target = pos < 0.5; return d; }, + # door.enable(bool) -> set /enabled + enable : func { me.enabled.setBoolValue(!!arg[0]) }, - # door.enable(bool) -> set /enabled - enable : func { me.enabled.setBoolValue(arg[0]) }, + # door.setpos(double) -> set /position-norm without movement + setpos : func { me.position.setValue(arg[0]); me.target = arg[0] < 0.5 }, - # door.setpos(double) -> set /position-norm without movement - setpos : func { me.pos.setValue(arg[0]); me.target = arg[0] < 0.5 }, + # double door.getpos() -> return current position as double + getpos : func { me.position.getValue() }, - # double door.getpos() -> return current position as double - getpos : func { me.pos.getValue() }, + # door.close() -> move to closed state + close : func { me.move(me.target = 0) }, - # door.close() -> move to closed state - close : func { me.move(0) }, + # door.open() -> move to open state + open : func { me.move(me.target = 1) }, - # door.open() -> move to open state - open : func { me.move(1) }, - - # door.toggle() -> move to farther away end position - # (0 -> 1, 1 -> 0, 0.3 -> 1, 0.6 -> 0) + # door.toggle() -> move to opposite end position toggle : func { me.move(me.target) }, - # door.move(double) -> move to arbitrary position + # door.move(double) -> move to arbitrary position move : func { time = abs(me.getpos() - arg[0]) * me.swingtime; - interpolate(me.pos, arg[0], time); + interpolate(me.position, arg[0], time); me.target = !me.target; }, }; + +# light +# ============================================================================== +# class for generation of pulsing values. Appropriate for controlling +# beacons, strobes, etc. +# +# SYNOPSIS: +# light.new( [, [, [, ]]]); +# +# property ... light node: property path or node +# ontime ... time in seconds that the light is on when blinking (default: 0.5) +# offtime ... time in seconds that the light is off when blinking (default: ontime) +# switch ... property path or node to use as switch (default: /enabled) +# If the switch node isn't given or nil, it gets +# created and the light turned on. +# +# PROPERTIES: +# /state (bool) +# /enabled (bool) (except if given) +# +# EXAMPLES: +# beacon = aircraft.light.new("sim/model/foo/beacon", 0.4); +# strobe = aircraft.light.new("sim/model/foo/strobe", 0.05, 1.0, "controls/lighting/strobe"); +# strobe.set(1); +# +light = { + new : func { + d = { parents : [light] }; + d.node = makeNode(arg[0]); + d.ontime = if (size(arg) > 1 and arg[1] != nil) { arg[1] } else { 0.5 }; + d.offtime = if (size(arg) > 2 and arg[2] != nil) { arg[2] } else { d.ontime }; + if (size(arg) > 3 and arg[3] != nil) { + d.switch = makeNode(arg[3]); + } else { + d.switch = d.node.getNode("enabled", 1); + } + if (d.switch.getValue() == nil) { + d.switch.setBoolValue(1); + } + d.state = d.node.getNode("state", 1); + if (d.state.getValue() == nil) { + d.state.setBoolValue(0); + } + d.continuous = 0; + d._loop_(); + return d; + }, + # light.set(bool) -> set light switch (also affects other lights + # that use the same switch) + set : func { me.switch.setBoolValue(!!arg[0]) }, + + # light.toggle() -> toggle light switch + toggle : func { me.switch.setBoolValue(!me.switch.getValue()) }, + + # light.cont() -> continuous light + cont : func { me.continuous = 1 }, + + # light.blink() -> blinking light + blink : func { me.continuous = 0 }, + + _loop_ : func { + if (!me.switch.getValue()) { + value = 0; delay = 0.5; + } elsif (me.continuous) { + value = 1; delay = 0.5; + } elsif (me.state.getValue()) { + value = 0; delay = me.offtime; + } else { + value = 1; delay = me.ontime; + } + me.state.setValue(value); + settimer(func { me._loop_() }, delay); + }, +}; + +