Written by SnoWFLakE0s - Last updated March 30, 2022
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 a 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 are 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. Simply put, 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 (among other things) into different types.
There are largely two different kinds of variables available to you in Funky Trees. The first are the "original" variety and the ones that have been here since the beginning of Funky Trees: "input variables". These variables contain various kinds of data that are related to the current state of the game, including (but not limited to) things like the speed of the current aircraft, the time elapsed since the beginning of the sandbox session, and so on and so forth. These are given to you by default, and can be accessed at any time without any other procedures aside from just writing them in your code.
The following is a list of all input variables. It most certainly looks quite daunting, but 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 (with their possible range of 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 | The 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) |
Brake | Whether or not Brake is pressed | 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 |
---|---|---|
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 for the second type of variables available to you in Funky Trees--custom variables. A recent addition to the growing abilities of Funky Trees, custom variables were introduced in version 1.11 of SimplePlanes. Custom variables are special because you can create them (and thus are not available by default). There are two sub-categories of custom variables, the first and most common kind being setter variables, and the second and less-used variety being part variables.
Variables allow for some powerful methods of Funky Trees coding not previously available, and also greatly simplifies certain tasks that lead to long, complicated, and unreadable Funky Trees code prior to their introduction. However, you do not need to use them for basic snippets of Funky Trees code! Do not make things more complex than they need to be--this is a common mistake for beginning programmers. That being said, let's begin with setter variables.
Setter variables are the kind of variables you will use the most. First, to access these and begin writing into them, you must open the "variable setters" menu next to the "start sandbox" menu, indicated by an icon that looks like an "x":
Once opened, you will see the "Variable Setters" window open:
You can then press "Add Variable" to create a new "variable setter".
This creates a new "variable setter", the namesake of which comes from the fact that SimplePlanes will use this in order to constantly set the custom variable with the name in the "Variable Name" field with the Funky Trees code in the "Expression" field. Do precisely that, simply writing any custom variable name (that is not already reserved by the Input Variables). For example, we'll use x as our variable name, with the expression Throttle as our value. If you now use the variable x in any of your code, it will hold the value Throttle. This can be extrapolated to any reasonable extent, which is great when you have large, repeating sections of your code, say for example, an expression that calculates the number of shots you have fired with your cannon. This can make your Funky Trees code more compact, modular and easily readable and modifiable without having to worry that you misspelled a part of that long repeating section. If you want to delete your variable, simply press the button at any time to remove it.
Setter variables also have additional attributes accessible by the small dropdown button to the left of the delete button. This reveals some new options, named "Priority" and "Activator":
It is convinient to think of the variable setters as a "list". That is because SimplePlanes will calculate the value of variables in order from top to bottom as shown in your variable setters menu. You can change the order of that list by moving a setter up and down with those buttons in the dropdown menu. Now, if you have multiple variable setters with the same variable name, normally the last setter will determine the final value of the variable. You may test this by creating two setters for a variable x, the first with any value, and second with value 0. If you check the value of the variable in the sandbox, you will find that x always evaluates to 0. Now, the priority of a variable can alter this behavior by determining which "gets the final say" in the determination of the final value of a variable. The priority is by default 0, but can be set to any whole number (even negative numbers). However, it is good practice to just use positive integers. A setter with higher postive priority will determine the final value of the variable, meaning that in the previous example, if you set your first setter with priority 1 and the second left at 0, the variable x will no longer evaluate to 0 but instead whichever value you set it to.
Activators are what they sound like--they either enable or disable the functioning of the its respective variable setter. An activator must be a boolean value (refer to the relevant section for information). If the value is "true", the variable setter will function normally. If the activator is "false" however, the variable setter will not function: the variable's value will no longer be changed by that variable setter. This is an important distinction from "the variable is disabled", because once created the variable always exists and holds a value. You can still use the variable in your code, but the if the setter is disabled it will no longer update that variable's value. A common application for this can be to store values in memory. As a quick note, if a variable is created but is disabled by default, it will by default have value 0. There is no "null" value for variables.
What makes these setter variables so powerful is that when their nature of being evalulated in steps, the priority feature, and activators are combined, they can do incredibly useful logical processing, such as even program games like Snake or Tetris.
Part variables are arguably less useful, but can prove crucial when you have various components of your craft doing different things, or want special kinds of data available to you. You can access them by first selecting a part in the editor, pressing the edit button , then the part variables button , which looks identical to its normal setter counterpart. Open it, and you will see the following kind of menu appear:
The labels indicate what kind of data that setter represents, but the method for using these setters are identical to the normal ones described earlier. For example, for the cockpit part, if you use the setter for "Altitude" and call it x, x will now hold the value of that cockpit part's altitude. These also have the same priority and activator options like their normal brethren. Now, not all kinds of parts have part variables, and each type of part typically has different types of data accessible. As a quick note, from empirical testing, it has been found that without any priority or activator modifications, any part variables are evaluted last, after your normal setters are finished calculating.
For a quick overview of which parts have what kinds of part variables that can be set, refer to the graphic below. This graphic is not exhaustive and you should check for yourself to see what part variables are available for any given part.
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. Note that ceil() always rounds away from zero for positive numbers, but towards zero for negative numbers. |
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. floor() always rounds towards zero for positive numbers, but away from zero for negative numbers. |
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. Read 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). |
For boolean operators, if the first argument of the operator is terminal, that is, it immediately dictates the output of the evaluation, it will not check the second argument at all. This applies for both the OR and AND operator.
Example
In sum(Time) > 1 | sum(2*Time) > 1
, while sum(Time) > 1
, sum(2*Time)
will not update (i.e. not change, making it stay at 0 until the first condition is no longer true). If you need to use these operators in conjunction with update-sensitive time-based functions, try to use boolean algebra instead, that is, try to figure a numerical comparison method instead of logic-based.
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.