Written by SnoWFLakE0s
First implemented in game version 1.9, Funky Trees is a special subset of XML editing/modding in SimplePlanes that specifically deals with the group
, activationGroup
, and input
attributes of parts. By nature, Funky Trees is a special subfield of what's known as XML editing/modding in SimplePlanes. Difficulty with basic XML editing may prove detrimental to learning the Funky Trees system.
To be more specific, when an user does things in SimplePlanes, like controlling an aircraft by moving the joystick or pressing the keyboard, essentially what's being done is that the user is sending a signal to the various functional components on the craft to move it as the user intends it to. Funky Trees expands the options here and allows for much more complex programming of the inputs to allow for very special input programming to allow creation of incredibly powerful and useful parts.
For example, users have created parts that carry out complex actions that weren't possible before 1.9, such as functional all-altitude bombsights, the first functionally complete chronographs, and automatic flight control systems. As it stands, Funky Trees can be considered a very specifically designed programming language- it fufills the definition of one.
For a new learner, it is strongly recommended that the document be read in its full length, in chronological order. This particular guide is primarily tailored to help the learning of newer learners.
Funky Trees isn't some entirely new field of study, but given the broad expanse of what it covers, the following concepts are recommended for full mastery of Funky Trees capability. These come in no particular order, there is no need for you to master all of them, but to use everything in Funky Trees, you must know all of these concepts.
* indicates required fields of knowledge. Usage of calculus is largely limited to a couple of functions, but is still quite useful to know. Programming/CS knowledge is extremely useful to know when structuring Funky Tree inputs (FT is practically a programming language) and will help in understanding FT in general, but is not necessary.
Not unlike other conventional programming languages, Funky Trees utilizes a system of inputs and outputs. It takes various inputs
, processes them, and relays an output
that is then taken by the part (whatever "part" you're putting FT inputs into) to result in some kind of of behavior by the part.
By the same token, Funky Trees follows a set of predefined rules to make the system work. This is commonly known as "syntax". There aren't a large number of rules in Funky Trees- they can be generalized to the following:
Hello
and hello
are two very different things
Another common idea from programming comes into play in Funky Trees- when a certain, specifc order of symbols a grouped together in a very specifc way, they can hold meaning in the eyes of the system. This is commonly known as "semantics". For example, in the eyes of Funky Trees, the expression altitude
has no meaning to the system. However, the expression Altitude
has a very specifc value and meaning to the system, and the expression will evaluate accordingly. If these "very specifc combinations of symbols" are likened to functional "elements", it is possible to categorize these elements into to one of three categories. They are:
The following sections elaborate on these three categories in great detail, just after the data types section.
To give an input
to the part, you probably need some sort of data to work with, right? Since version 1.9.2, Funky Trees was revamped to have data type organization.
To explain, all usable data types in Funky Trees have now been organized into one of three categories- numbers, booleans, and strings. Here’s a rundown:
Hopefully, this made sense. If you're new to computer science, these terms may sound completely alien to you- but don't worry, it'll make sense in due time (this is the only reason why programming experience comes in handy, to help orient yourself quicker).
I first want to make sure that you understand what variables are in Funky Trees. Variables are special words that have a special value in Funky Trees. They contain data. The data type organization, in other words, is a way of organizing these variables into different types. The following is a list of all input variables. Don't panic, this is simply for reference.
Pitch | Roll | Yaw | Throttle | Brake |
Trim | VTOL | LandingGear | GearDown | FireGuns |
FireWeapons | LaunchCountermeasures | Activate1 | Activate2 | Activate3 |
Activate4 | Activate5 | Activate6 | Activate7 | Activate8 |
Altitude | AltitudeAgl | GS | IAS | TAS |
Fuel | AngleOfAttack | AngleOfSlip | PitchAngle | RollAngle |
Heading | Time | GForce | VerticalG | SelectedWeapon |
Latitude | Longitude | PitchRate | RollRate | YawRate |
TargetSelected | TargetHeading | TargetElevation | TargetDistance |
We can now categorize these variables based on their data category (their possible values included in parentheses).
By far the most numerous, the numbers datatype contains variables that equate to the number
class of variables. They’re conceptually easy to manipulate, but there are a great variety of number type variables and each has a unique range of values.
TL;DR: simply numbers, but everything is unique (requiring special attention from you).
The following is a list of all number type variables and their possible values.
Variable | Variable Description | Range of Values |
---|---|---|
Pitch | The amount of Pitch input as a proportion | (-1, 0, 1) / alternatively (-1~1) if joystick |
Roll | The amount of Roll input as a proportion | (-1, 0, 1) / alternatively (-1~1) if joystick |
Yaw | The amount of Yaw input as a proportion | (-1, 0, 1) / alternatively (-1~1) if joystick |
Trim | The amount of Trim input as a proportion | (-1~1) |
VTOL | The amount of VTOL input as a proportion | (-1~1) |
Throttle | The amount of Throttle input as a proportion | (0~1) |
Altitude | Aircraft's altitude in meters | (-inf~inf) |
AltitudeAgl | Aircraft's altitude above ground level in meters | (-inf~inf) |
GS | he speed relative to the ground (m/s) | (0~inf) |
IAS | The speed relative to the air (m/s) | (0~inf) |
TAS | The speed relative to the air, adjusted for the density of the air (m/s) | (0~inf) |
Fuel | The amount of fuel remaining as a proportion of capacity | (0~1) |
AngleOfAttack | The angle of attack (angle airflow vertically meets the boresight) in degrees | (-180~180) |
AngleOfSlip | The horizontal equivalent of angle of attack (degrees) | (-180~180) |
PitchAngle | The pitch of the aircraft (degrees) | (-90~90) |
RollAngle | The roll of the aircraft (degrees) | (-180~180) |
Heading | The heading of the aircraft (degrees) | (-180~180) |
Time | The time since the level loaded (seconds) | (0~inf) |
GForce | (omnidirectional "force" acting on the pilot, in g) | (0~inf) |
VerticalG | G-force (vertical component of G-force) | (0~inf) |
Latitude | The y-position of the craft in the sandbox map | (-inf~inf) |
Longitude | The x-position of the craft in the sandbox map | (-inf~inf) |
PitchRate | The rate at which the aircraft pitches (deg/s) | (-inf~inf) |
RollRate | The rate at which the aircraft rolls (deg/s) | (-inf~inf) |
YawRate | The rate at which the aricraft yaws (deg/s) | (-inf~inf) |
LandingGear | Archaic FT input type. Use GearDown instead when making FT inputs. |
(0, 1) |
TargetHeading | Returns the heading of the selected target, relative to the position of your cockpit, in bearing (degrees). Note that this is global, meaning that it is not relative to your current heading. View an explanatory diagram here. | (0~360) |
TargetElevation | Returns the line-of-sight angle to the selected target, relative to the position of your cockpit, in degrees. Note that this is global, meaning that it is not relative to your PitchAngle. View an explanatory diagram here. | (-90~90) |
TargetDistance | Returns the line-of-sight distance to the selected target, relative to the position of your cockpit, in meters. | (0~inf) |
Booleans were previously inconsistent in Funky Trees due to a couple errors. The system has been revamped completely, removing the root source of that error. Now, if you only use boolean statements independent of other data types, you will get the value true
or false
. If you use booleans in conjunction with the number data type, they will automatically convert to 1 or -1 (true or false respectively). That also means, in the table down below, all the booleans can also be considered to have a possible range of values of -1 or 1.
TL;DR: All boolean data type variables return either true or false, or 1 or -1 depending on its usage. This makes these logically consistent.
The following is a list of all number type variables and their possible values.
Variable | Variable Description | Range of Values |
---|---|---|
Brake | Whether or not Brake is pressed | true / false |
GearDown | Whether or not landing gear is on or off | true / false |
FireGuns | Whether or not guns button is pressed | true / false |
FireWeapons | Whether or not fire ordnance button is pressed | true / false |
LaunchCountermeasures | Whether or not launch countermeasures button is pressed | true / false |
Activate1 | Whether or not activation group 1 is on | true / false |
Activate2 | Whether or not activation group 2 is on | true / false |
Activate3 | Whether or not activation group 3 is on | true / false |
Activate4 | Whether or not activation group 4 is on | true / false |
Activate5 | Whether or not activation group 5 is on | true / false |
Activate6 | Whether or not activation group 6 is on | true / false |
Activate7 | Whether or not activation group 7 is on | true / false |
Activate8 | Whether or not activation group 8 is on | true / false |
TargetSelected | Whether or not a target is selected | true / false |
Simply put, strings are just lines of text, like "text". The number of actual strings datatype variables is technically only one as of the time of writing. However, whatever you make your string- be it “this string” or “that string”- are all valid strings. Strings don't really have a large variety of applications right now, but they can be useful.
Variable | Variable Description |
---|---|
SelectedWeapon | Outputs the name of the selected weapon in the weapons drawer as a string, e.g. "Boom 50", "Cannon" |
Now is the time to jog your brain for actual school math: remember functions? All that f(x) and g(x) and stuff? Well, now it's in SimplePlanes, and you can use it to do cool stuff. Functions are special objects that take in inputs
and return an output
, each depending on what the function does. Functions, in Funky Trees, are designed like so:
function(input)
Functions are defined to the system by the function name- in the example, the word 'function'
. Functions also have one more crucial attribute: they also have an 'input'
within the parentheses following the function name. Some functions take more than one input, for example, the clamp
function takes inputs in the form of clamp(x, a, b)
. Functions can only take specific datatypes as inputs (which is why I previously covered the data types)- there are functions that only accept string
-type data as inputs, like the ammo
function. The following is a list of all available functions as of game version 1.9.205. The following is simply for reference.
abs() | ceil() | clamp() | deltaangle() | exp() | floor() | inverselerp() | lerp() | lerpangle() | lerpunclamped() |
log() | log10() | pingpong() | max() | min() | pow() | repeat() | round() | sign() | smoothstep() |
sqrt() | sin() | cos() | tan() | asin() | acos() | atan() | rate() | sum() | smooth() |
PID() | ammo() |
Moreover, each function acts in unique ways, which is how they are classified in the following few subsections.
Number based functions are the most conceptually simple. It takes inputs that would be classified under the ‘number’ data type, and outputs a ‘number’ data type. However, if you recall Section 2A, it was mentioned that booleans can be converted to a number of 1 or -1 (true or false)- this means that number based functions can take boolean inputs, but note that the number function is taking not the boolean themselves as input, but only the number-converted boolean. A number function will not take a string input, like the string "thisstring"
. They will also only ouput a number, i.e. a number function might take the value 1 and output 0.2.
The following table organizes all the number based functions, their input syntax, and their usage.
Function Name/Syntax | Usage |
---|---|
abs(x) | The absolute (positive) value of x. |
ceil(x) | x rounded up to an integer. |
clamp(x, min, max) | x clamped between min and max. |
clamp01(x) | x clamped between 0 and 1. Equivalent to clamp(x, 0, 1) |
deltaangle(a, b) | The smallest angle delta between angles a and b in degrees. |
exp(x) | Returns e raised to the power of x. |
floor(x) | x rounded down to an integer. |
inverselerp(a, b, x) | Calculates the linear parameter t that produces the interpolant value within the range [a, b]. |
lerp(a, b, t) | Linearly interpolates between a and b, by a proportion of t. |
lerpangle(a, b, t) | Similar to lerp, but interpolates correctly when values pass 360 degrees. |
lerpunclamped(a, b, t) | Similar to lerp, but doesn't clamp the value between a and b. |
log(x, p) | The logarithm of x in base p. |
log10(x) | Equivalent to log(x, 10). |
pingpong(x, l) | "Ping-pongs" the value x so it is never larger than l and never less than 0. |
max(a, b) | The largest value between a and b. |
min(a, b) | The smallest value between a and b. |
pow(x, p) | x raised to the power of p. |
repeat(x, l) | Loops the value x so it is never larger than l and never less than 0. |
round(x) | Rounds x to the nearest integer. |
sign(x) | The sign of x (1 if x positive, -1 if x negative) |
smoothstep(a, b, t) | Similar to lerp, but with smoothing at the ends. |
sqrt(x) | The square root of x. |
sin(x) | The sine of x (degrees) |
cos(x) | The cosine of x (degrees) |
tan(x) | The tangent of x (degrees) |
asin(x) | The arc-sine of x (degrees) |
acos(x) | The arc-cosine of x (degrees) |
atan(x) | The arc-tangent of x (degrees) |
These functions were added in game version 1.9.2. These are functions that measure things with respect to time. In particular, the rate and sum functions are the FT equivalent of derivatives (d/dx) and integrals (∫dx), which enables the creation of far advanced inputs. These functions can be greatly useful but most things can be done without them, so do not fret- if your math is on the level to understand derivatives and integrals, then you don’t really need much explanation on what these will do. We're not working with variable expressions, so more of the academic calculus like the power rule is pretty much useless- you will really only be utilizing the practical application of them.
Function Name/Syntax | Usage |
---|---|
rate(x) | The rate of change of x. |
sum(x) | The integration of x over time. Time starts from level load (no integration bounds can be specified). |
smooth(x, rate) | The output follows x, but only at a maximum speed of rate units per second. |
PID(target, current, p, i, d) | A PID controller with the parameters p, i and d. Read more about PID controllers on Wikipedia. Learn a quick beginner's guide on tuning PIDs. |
There’s currently only one string-based function as of version 1.1.104- it’s the ammo()
function. Since it takes a string as input, that also means that the input the ammo function can be a string-type variable- i.e. the SelectedWeapon
variable.
Function Name/Syntax | Usage |
---|---|
ammo("string") | The amount of ammo left for the weapon “someweaponname”. That is, whatever the name of your weapon is, is the string you want to input into “string”, to which the function will return the amount of remaining ammo. |
The Funky Trees system offers a variety of operators to use within input expressions. Simply put, operators are symbols indicating a mathematical operation. There are two types of operators in Funky Trees:
Refer to the following two sections for information on each.
Math operators are conceptually very simple. They perform basic algebraic calculations. The following table lists all available math operators, their usage, and examples. Take a, b, c
as other expressions or constants.
Symbol | Usage | Example | Explanation |
---|---|---|---|
+ |
Addition | a + b |
Yields the value a + b . While spaces may not be required, sometimes no spacing can cause errors. For the sake of consistency, it is highly advised you put single spaces around the operator. Additionally, strings can be concatenated through the addition operator. For example, the statement "He" + "llo" will yield the resulting string "Hello" . |
- |
Subtraction or Negative sign | a - b or -c |
Yields the value a - b . While spaces may not be required, sometimes no spacing can cause errors. For the sake of consistency, it is highly advised you put single spaces around the operator. |
* |
Multiplication | a * b |
Yield the value a * b . While spaces may not be required, sometimes no spacing can cause errors. For the sake of consistency, it is highly advised you put single spaces around the operator. |
/ |
Division | a / b |
Yield the value a / b . While spaces may not be required, sometimes no spacing can cause errors. For the sake of consistency, it is highly advised you put single spaces around the operator. |
() |
Parentheses to group statements | (a + b) * c |
Groups statements. In this example, the operation a + b is done before c is multiplied. Note: implied multiplication, like in the form of (a)(b) , is not supported. To do this, you must use the multiplication operator. |
To illustrate the math operators in context, here's an example: assume that the value of the variable, Roll
, is set to 1 because the positive roll button is pressed. If a final value of 5 is desired, adding 4 to the current Roll value will yield 5. Therefore the expression Roll + 4
would evaluate (result) in: (+1) + (+4) == (+5)
. All of the math operators are used in similar fashion to the example illustrated.
Logic operators are conceptually more abstract, as they rely on boolean logic instead of simple algebra. They always output a boolean value as the ouput- either true
or false
. There are three types of operators- comparison, boolean, and selection operators. Each is explained below. For some operators, a truth table is also included for reference.
Comparison operators are very conceptually simple. They compare the two values on each side of the operator and output the result as a boolean. Comparison operators only take numbers as input (or number-converted booleans).
Symbol | Usage | Example | Explanation |
---|---|---|---|
= |
Equality | a = b |
Checks if a = b . If a is equal to b , the output will be true . In any other case, it will be false . |
!= |
Nonequality (NOT) | a != b |
Checks if a != b . If a is NOT equal to b , the output will be true . In any other case, it will be false . |
> |
Greater than | a > b |
Checks if a > b . If a is greater than b , the output will be true . In any other case, it will be false . |
< |
Less than | a < b |
Checks if a < b . If a is less than b , the output will be true . In any other case, it will be false . |
>= |
Greater than or equal to | a >= b |
Checks if a >= b . If a is greater than, or equal to b , the output will be true . In any other case, it will be false . |
<= |
Less than or equal to | a <= b |
Checks if a <= b . If a is less than, or equal to b , the output will be true . In any other case, it will be false . |
Boolean, or logic operators operate based on booleans, that is, the values true
or false
. This also means they only take boolean operands.
Symbol | Usage | Example | Explanation |
---|---|---|---|
& |
Boolean AND | a & b |
Checks if both a and b are true . If any one of the two operands are false , the expression will output false . |
| |
Boolean OR | a | b |
Checks if either one of a and b are true . If any one of the two operands are true , expression will output true . This operator only ouputs false if both operands are false . |
! |
Boolean Invert | !a |
This operator inverts the value of a boolean. That is, !true is false , and !false is true . This effectively is the same as doing -a , where a is a boolean, but only works for unary (booleans), while - (the negative sign) can work on both unary and binary (booleans and numbers). |
Selection operators output one of the two expressions as output depending on the value of the initial condition.
Symbol | Usage | Example | Explanation |
---|---|---|---|
? : |
IF (ternary selection) | a ? b : c |
Checks if a is true or false . If a is true , the operator outputs the value b . If a is false , the operator outputs the value c . This also means the selection operator can have a variety of types of outputs (but a must be a boolean value). |
Once again, it is worth noting that the boolean operators take only boolean operands. To generate a boolean, the standard comparison operators must be utliized.
The first three sections of this guide provides apt commentary / explanation on the theoretical aspect of Funky Trees. However, the practical aspect of designing and programming a Funky Trees input has yet to be discussed; as such, this section will discuss practical implementation of Funky Trees inputs. Specifcally, this section deals with actual writing of inputs, as many struggle with this. As with any other XML editing, there are two approaches to editing the XML file of a creation. One is using inbuilt Overload XML editor (cross-platform) or using a text editor to directly edit XML files. Either approach allows for the same kind of editing, although for mass edits a search-replace function that comes inbuilt with most text editors may be far more preferable.
Funky Trees inputs are compatible with three types of attributes within XML editing: the input
attribute within the inputController
class of attributes, and the activationGroup
and group
attributes for certain parts. The behavior of Funky Trees in each of these is different, which warrants an explanation.
The input
attribute is usually the primary application of Funky Trees. Most gizmo-type parts and propulsion-type parts contain an inputController
class of attributes that contains the input
attribute. The following image is an example of an input
attribute Overload window.
Note the highlighted sections. The under the inputController
class, the input
attribute is visible, with the value of the input
attribute on the side. In the example, the input is Throttle
. A Funky Trees expression can be entered here. The behavior of parts is unique for each part- an input will simply determine the degree to which an part responds. It is the fine-tuning and programming of these "degree of response" that Funky Trees is concerned with, producing very useful and special behavior.
The activationGroup
attributes are usually of lesser importance for Funky Trees (but can prove to be useful). Practially all parts, aside from structural parts like fuselage blocks, contain an activationGroup
attribute, typcially contained under inputController
classes or part-specifc classes. The following image is an example of an activationGroup
attribute Overload window.
Note the highlighted sections. For the example, under the Magnet
class (a part-specifc class), the activationGroup
attribute is visible, with the value of the activationGroup
attribute on the side. In the example, the value is 1
. A Funky Trees expression can be entered here.
The group
attribute is practically the same as activationGroup
, but only applies for certain types of types like detachers. The following image is an example of an activationGroup
attribute Overload window.
Note the highlighted sections. For the example, under the Detacher
class (a part-specifc class), the group
attribute is visible, with the value of the group
attribute on the side. In the example, the value is 1
. A Funky Trees expression can be entered here.
The difference in response to Funky Trees defines the difference between input
attributes and activationGroup
/ group
attributes. For input
attributes, the behavior of parts simply depends on the numerical value of the input. However, for activationGroup
and group
attributes, the behavior is a boolean (true / false
, on / off
), defined by the value of the FT expression being larger than 0. For example, for a detacher with some FT expression, the detacher will activate / fire the moment the FT expression in it returns a value larger than 0. For this reason, it may be largely preferable to have FT expressions for the activationGroup
and group
attributes be based on booleans instead of mathematical systems.
Sections 1 to 4 cover practically all that can be taught in the realm of the Funky Trees system. The actual formulation of actual Funky Trees expressions largely depend on the creator's own ability to manipulate these features included in the Funky Trees package- studying expressions by other creators may help apply the same style of patterns to one's own. Additionally, there also exist standardized/generalized FT expression for specifc purposes, which may be helpful to the common creator. A full index of commonly used general Funky Trees expressions can be found in the commonly used FT expressions page (currently under construction). This final fifth section covers other tools that can assist in forming FT programs.
Whilst creating FT expressions, especially for longer, more complicated expressions, it may be desirable to be able to obtain an live readout of the actual values of expressions. Using the inbuilt game console, accessed using the ` key on PC platforms and three finger taps on mobile platforms, a debugger console is available to debugging FT expressions. Type the following command into the console:
DebugExpression "expression"Where expression is the FT expression you are attempting to debug. This can be used with any FT expression- however, for FT expressions that contain quotation marks ("") (for string values), the quotation marks inside the FT expression must be replaced with sharp marks (##). This is to avoid issues with confusing the console.
Once the DebugExpression command is used, a small window will appear on the top left corner of the screen displaying your entered expression, and also the value of the expression aside a colon mark :.
To clear the debugger console, enter the command ClearDebugExpressions into the console.
When writing Funky Trees code, you may find that it is quite difficult to actually make sense of what you're writing, especially in terms of code structure and trying to figure out if you have the right number of parentheses in the expression. Sometimes you want to stop writing the same variable name over and over again. Or you just might want a good text editor, especially for programming.
Atom is a great open source software that does everything you really need for funky trees. It has a parentheses highlighting function that helps you figure out pairings, word autofill for variables that you are repeatedly using, and a lot more that can help you do funky trees easier. Of course, Notepad or TextEdit is fine, but Atom is a great software that just makes life easier. You can also custom-code extensions that do things for you.