Howto:Basic OOP Programming: Difference between revisions

From FlightGear wiki
Jump to navigation Jump to search
No edit summary
No edit summary
Line 6: Line 6:
var screen_power_consumption = nil;
var screen_power_consumption = nil;
var screens = nil;
var screens = nil;
# set the dimming properties to reasonable values, in order to be able to test the code
setprop("/controls/lighting/DU/du1", 0.5);
setprop("/controls/lighting/DU/du2", 0.6);
setprop("/controls/lighting/DU/du3", 0.9);
setprop("/controls/lighting/DU/du4", 0.1);
setprop("/controls/lighting/DU/du5", 1.0);
setprop("/controls/lighting/DU/du6", 0.4);
</syntaxhighlight>
</syntaxhighlight>


Line 12: Line 20:
var screen = {
var screen = {
         # first, create the attributes of the screen
         # first, create the attributes of the screen
name: "",
name: "", # a string. Note the comma at the end, it is important
type: "",  
type: "", # also a string
max_watts: 0,
max_watts: 0, # a number
dim_watts: 0,
dim_watts: 0, # a number
dim_prop: "",
dim_prop: "", # a property: defined in the same format as the string. We could run getprop(me.dim_prop) to fetch the contents of the format.
 
        # next we have a function that measures the power consumption and returns it
 
power_consumption: func() {
var dim_prop = me.dim_prop; # define it as a variable, so we can just do getprop(dim_prop)


power_consumption: func() { # next we have a function that measures the power consumption and returns it
var dim_prop = me.dim_prop;
if (getprop(me.dim_prop) != 0) { # if the screen is not off
if (getprop(me.dim_prop) != 0) { # if the screen is not off
screen_power_consumption = (50 + (10 * getprop(dim_prop))); # y = 50 + 10d, where d = the value of the dimming property.
screen_power_consumption = (50 + (10 * getprop(dim_prop))); # calculate the power consumed by the string
} else { # if the screen is off, it consumes no power.
} else { # if the screen is off, it consumes no power.
screen_power_consumption = 0;
screen_power_consumption = 0; # so we set screen_power_consumption to 0
}  
}  
return screen_power_consumption; # this means that when you run this function, you will get a value returned to you.
 
}, # power_consumption()
return screen_power_consumption; # this means that when you run this function, you will get a value returned to you as a number.
 
}, # again we have a comma closing the brackets


new: func(name,type,max_watts,dim_watts,dim_prop) { # finally the creator function, that creates instances of the class
new: func(name,type,max_watts,dim_watts,dim_prop) { # finally the creator function, that creates instances of the class
var s = {parents:[screen]};
var s = {parents:[screen]}; # the instances will each be a "copy" of the screen class: screen is the "parent"
s.name = name;
s.name = name; # associate the func(name...) with the name attribute of the screen class
s.type = type;
s.type = type;
s.max_watts = max_watts;
s.max_watts = max_watts;
Line 49: Line 62:
var ELEC = {
var ELEC = {
init: func() { # initialization function
init: func() { # initialization function
               # Create the instances of the screen class, and add them to a vector in order to use a foreach loop
               # Create the instances of the screen class, inside a vector so we can use a foreach loop later
               screens = [screen.new("DU1","LCD",60,50,"controls/lighting/DU/du1"),
              # format: screen.new(name,type,max_watts,dim_watts,dim_prop)
 
               screens = [screen.new("DU1","LCD",60,50,"controls/lighting/DU/du1"),  
screen.new("DU2","LCD",60,50,"controls/lighting/DU/du2"),
screen.new("DU2","LCD",60,50,"controls/lighting/DU/du2"),
screen.new("DU3","LCD",60,50,"controls/lighting/DU/du3"),
screen.new("DU3","LCD",60,50,"controls/lighting/DU/du3"),
Line 56: Line 71:
screen.new("DU5","LCD",60,50,"controls/lighting/DU/du5"),
screen.new("DU5","LCD",60,50,"controls/lighting/DU/du5"),
screen.new("DU6","LCD",60,50,"controls/lighting/DU/du6")];  
screen.new("DU6","LCD",60,50,"controls/lighting/DU/du6")];  
         },
         },
         loop: func() {
         loop: func() {
               foreach(var screena; screens) {  # note that we use a different variable, screena
               foreach(var screena; screens) {  # note that we use a different variable, screena; essentially foreach(var a; b) associates var a with vector b
power_consumption = screena.power_consumption(); # call the power_consumption() for each instance of the screen class
power_consumption = screena.power_consumption(); # call the power_consumption() for each instance of the screen class
setprop("/systems/electrical/DU/" ~ screena.name ~ "/watts",power_consumption); # write the result to a property
setprop("/systems/electrical/DU/" ~ screena.name ~ "/watts",power_consumption); # write the result to a property
Line 66: Line 82:
</syntaxhighlight>
</syntaxhighlight>


Finally, we add the updating function: the following code creates a maketimer and a setlistener that execute the loop(); and init(); functions respectively:
Finally, we add the updating function: the following code creates a maketimer and a setlistener that execute the loop(); and init(); functions respectively: we remove the listener to make sure it does not run repeatedly.
<syntaxhighlight>
<syntaxhighlight>
var Loop = maketimer(0.1, func {
var Loop = maketimer(0.1, func {
Line 86: Line 102:
</syntaxhighlight>
</syntaxhighlight>


<syntaxhighlight lang="nasal">
If you then hooked up the dimming properties to 3D knobs in any aircraft you could control the dimming and thus the power consumption by rotating the knobs.
setprop("/controls/lighting/DU/du1", 0.5);
setprop("/controls/lighting/DU/du2", 0.6);
setprop("/controls/lighting/DU/du3", 0.9);
setprop("/controls/lighting/DU/du4", 0.1);
setprop("/controls/lighting/DU/du5", 1.0);
setprop("/controls/lighting/DU/du6", 0.4);
</syntaxhighlight>
 
If you then hooked up these properties to 3D knobs in any aircraft you could control the dimming and thus the power consumption by rotating the knobs.

Revision as of 20:59, 10 December 2017

First, we need to define some variables at the very beginning of the nasal file. This improves performance, since if you use "var" inside a loop, it degrades performance: the variable is recreated every time the loop is run!.

# Define variables here to prevent them being recreated at every run of the loop() function
var power_consumption = nil;
var screen_power_consumption = nil;
var screens = nil;

# set the dimming properties to reasonable values, in order to be able to test the code
setprop("/controls/lighting/DU/du1", 0.5);
setprop("/controls/lighting/DU/du2", 0.6);
setprop("/controls/lighting/DU/du3", 0.9);
setprop("/controls/lighting/DU/du4", 0.1);
setprop("/controls/lighting/DU/du5", 1.0);
setprop("/controls/lighting/DU/du6", 0.4);

Then, we need to create the class for the screen: we define some attributes, then add a function that calculates the power consumption. Finally, at the end we have the constructor which can be used to create the object over and over by simply running screen.new(); with the attributes defined inside the brackets.

var screen = {
        # first, create the attributes of the screen
	name: "", # a string. Note the comma at the end, it is important
	type: "", # also a string
	max_watts: 0, # a number
	dim_watts: 0, # a number
	dim_prop: "", # a property: defined in the same format as the string. We could run getprop(me.dim_prop) to fetch the contents of the format.

        # next we have a function that measures the power consumption and returns it

	power_consumption: func() { 
		var dim_prop = me.dim_prop; # define it as a variable, so we can just do getprop(dim_prop)

		if (getprop(me.dim_prop) != 0) { # if the screen is not off
			screen_power_consumption = (50 + (10 * getprop(dim_prop))); # calculate the power consumed by the string
		} else { # if the screen is off, it consumes no power.
			screen_power_consumption = 0; # so we set screen_power_consumption to 0
		} 

		return screen_power_consumption; # this means that when you run this function, you will get a value returned to you as a number.

	}, # again we have a comma closing the brackets

	new: func(name,type,max_watts,dim_watts,dim_prop) { # finally the creator function, that creates instances of the class
		var s = {parents:[screen]}; # the instances will each be a "copy" of the screen class: screen is the "parent"
		
		s.name = name; # associate the func(name...) with the name attribute of the screen class
		s.type = type;
		s.max_watts = max_watts;
		s.dim_watts = dim_watts;
		s.dim_prop = dim_prop;
		
		return s;
	}, # new() constructor 
};

Next, we create a new object called ELEC.

In the first part, we have a function called whenever the FDM initialization is complete: inside it, various instances of the screen class are created using the new() constructor. Then, in the second part, we have a loop function that actually does the hard work of calculating the power consumption per screen.

var ELEC = {
	init: func() { # initialization function
              # Create the instances of the screen class, inside a vector so we can use a foreach loop later
              # format: screen.new(name,type,max_watts,dim_watts,dim_prop)

              screens = [screen.new("DU1","LCD",60,50,"controls/lighting/DU/du1"), 
			screen.new("DU2","LCD",60,50,"controls/lighting/DU/du2"),
			screen.new("DU3","LCD",60,50,"controls/lighting/DU/du3"),
			screen.new("DU4","LCD",60,50,"controls/lighting/DU/du4"),
			screen.new("DU5","LCD",60,50,"controls/lighting/DU/du5"),
			screen.new("DU6","LCD",60,50,"controls/lighting/DU/du6")]; 

        },
        loop: func() {
               foreach(var screena; screens) {  # note that we use a different variable, screena; essentially foreach(var a; b) associates var a with vector b 
			power_consumption = screena.power_consumption(); # call the power_consumption() for each instance of the screen class
			setprop("/systems/electrical/DU/" ~ screena.name ~ "/watts",power_consumption); # write the result to a property
	       }
        },
};

Finally, we add the updating function: the following code creates a maketimer and a setlistener that execute the loop(); and init(); functions respectively: we remove the listener to make sure it does not run repeatedly.

var Loop = maketimer(0.1, func {
ELEC.loop(); # runs the loop(); function every 0.1 seconds
});

var l = setlistener("/sim/signals/fdm-initialized", func { # listens to this property. When it changes, the following lines are run, then the listener is removed.
   ELEC.init(); # run the init loop to set things up
   timer.start(); # start the timer.
   removelistener(l); # ensure that the listener only runs once to improve performance
});


This is a basic example of OOP. This code should be reasonably standalone, in that it should work without depending on other code. For instance, to make a test of the code, you could setprop the DU dimming properties at the beginning of the file to reasonable values, as follows, then run it using the UFO. Or, in the Nasal console, you could just copy the first three code snippets and the maketimer to the console (ie skipping the setlistener), then add this at the bottom and execute.

ELEC.init();
timer.start();

If you then hooked up the dimming properties to 3D knobs in any aircraft you could control the dimming and thus the power consumption by rotating the knobs.