-
Notifications
You must be signed in to change notification settings - Fork 4
New_Variables
Just like Orders
and EventHandlers
you can inherit from the BaseVariable
class and define your own type of variables to be used in the LUTE engine. For more complex variables you could inherit from other variable class types such as custom collections but in this example we will construct a simple variable.
using UnityEngine;
[VariableInfo("Other", "Foo")]
[AddComponentMenu("")]
public class FooVariable : BaseVariable<Foo>{ }
-
VariableInfo
Attribute: Adds the variable to the AddVariable menu. The first parameter sets the category, and the second parameter sets the name in the list. -
AddComponentMenu
Attribute: When given an empty string, this Unity attribute prevents the class from appearing in the AddComponent menu on regular game objects. -
Inherit from
VariableBase
: Use T as the type of your variable.VariableBase
provides most of the type-specific requirements that variables need generically. This is suitable for most variable types. Inheriting directly fromVariable
instead ofVariableBase
means some functionality will not be automatic, making interoperability with other parts of the system harder, as they expect to check or cast to VariableBase.
When using variables is custom defined condition statements (such as the If
Order) the statement will query the Variable itself to determine how it should be evaulated (this is also true for the setting of a variable). The BaseVariable and Variable class contains methods which can be used by your custom defined Variables to define how these methods are handled (or they will be used in a typical sense). This allows you to be creative with how you use variables in such situations (rather than simply comparing two variables of the same type you could extend this and you can see this being used in Inventory variable types where we compare Inventory Items in an Inventory rather than comparing two Inventories).
We can observe this by taking a peek at some simplified methods in our IntegerVariable
class:
public override void Apply(SetOperator setOperator, int value)
{
switch (setOperator)
{
case SetOperator.Negate:
Value = Value * -1;
break;
case SetOperator.Add:
Value += value;
break;
case SetOperator.Subtract:
Value -= value;
break;
case SetOperator.Multiply:
Value *= value;
break;
case SetOperator.Divide:
Value /= value;
break;
default:
base.Apply(setOperator, value);
break;
}
}
public override bool Evaluate(ComparisonOperator comparisonOperator, int value)
{
int leftSide = Value;
int rightSide = value;
bool condition;
switch (comparisonOperator)
{
case ComparisonOperator.LessThan:
condition = leftSide < rightSide;
break;
case ComparisonOperator.LessThanOrEquals:
condition = leftSide <= rightSide;
break;
case ComparisonOperator.GreaterThan:
condition = leftSide > rightSide;
break;
case ComparisonOperator.GreaterThanOrEquals:
condition = leftSide >= rightSide;
break;
default:
condition = base.Evaluate(comparisonOperator, value);
break;
}
return condition;
}
- The
Apply
method will set the current value of the variable to the value that has been provided (through another class or through serialised properties). - The
Evaluate
method is what is used to determine whether or not the current value of the variable is equal (or not equal etc.) to the value provided typically in LUTE condition statements (but can be used in reference in other classes).
Most built-in variables have a data structure and a drawer that allow setting either a variable or a local value of the same type in the inspector. For example, to use an integer for a custom IntegerVariable, you would declare a variable of type IntegerData and use .Value to get the internal value, regardless of which was set in the inspector.
These data objects are structs, meaning they don't share a common base class but follow the same structure for ease of use.
[System.Serializable]
public struct IntegerData
{
[SerializeField]
[VariableProperty("<Value>", typeof(IntegerVariable))]
public IntegerVariable integerRef;
[SerializeField]
public int integerVal;
public IntegerData(int v)
{
integerVal = v;
integerRef = null;
}
public static implicit operator int(IntegerData integerData)
{
return integerData.Value;
}
public int Value
{
get { return (integerRef == null) ? integerVal : integerRef.Value; }
set { if (integerRef == null) { integerVal = value; } else { integerRef.Value = value; } }
}
public string GetDescription()
{
if (integerRef == null)
{
return integerVal.ToString();
}
else
{
return integerRef.Key;
}
}
}
This then also needs a Drawer in an Editor Folder, which can be included in a new or existing class. Such as:
[CustomPropertyDrawer(typeof(IntegerData))]
public class IntegerDataDrawer : VariableDataDrawer<IntegerVariable> { }
The drawer relies heavily on the field names within Variable Data to render correctly.
In order for Variables to be accesible and supported you will need to add your new types to the AllVariableTypes.cs
. Specifically, you need to add the type to the AllLogaVarTypes
collection and the Dictionary typeActionLookup
where you can define specific evaulation and set methods if you intend to use this way.
As with defining new Orders and Event Handlers, one should tred with caution if they are not entirely sure and always test well.