I’m trying to connect the Input System to the Localization system (to show input prompts), elaborating @karl_jones example from: Localisation for Input Keys
I’ve made some headway with this, but currently I’m stuck on how to process the IVariableValueChanged.ValueChanged event within my custom ISource. I am detecting when the input device changes and firing the event on my IVariables, but there are no subscribers to that event. Is it because of my custom implementation of ISource?
Even though I’m adding the IVariable to the FormatCache.VariableTriggers.
The system only subscribes to variables that it is using in the Smart String. So adding it to the local variables is not enough, you need to actually use the source in the smart string.
I think this may be simpler if you implemented it as a variable group instead of creating a new ISource.
I would use IVariableGroup and then add that as a group to the GlobalVariables source.
Yes, I think this will keep things a bit simpler. You will only need 1 class instead of 3. Depending on how you want to update you can then just have a single IVariableValueChanged on the group which will trigger an update for any input changes, or you could return a nested IVariableValueChanged from the group which could then be used to trigger updates for that input only.
“You will only need 1 class instead of 3.” Yeah! That makes a lot of sense. My ISource wasn’t doing much except duplicating functionality anyway.
I feel dumb … how do I “use IVariableGroup and then add that as a group to the GlobalVariables source.”.
PersistentVariablesSource takes a “VariableGroupAsset” and what I have is just an IVariableGroup (in a ScriptableObject Asset).
[EDIT: Okay I think I got it. Haha posted simultaneously.]
I think I got it? The custom IVariableGroup should not be an Asset. (ScriptableObject).
Instead, it has to be a [Serializable] Class that also implements IVariable. Then it can be added inside the Variables Group Asset as a nested Variable (Group) ?
Arghh looks like you need to inherit from VariablesGroupAsset however the methods are not virtual so you wont be able to implement the behavior.
Ok, instead add the variable group to your global variables asset. It will mean you need to add an extra value to the smart strings though.
e.g {global.input.left}
Ill look into making those methods virtual in the future.
Alright, I got it working! (with the caveat of having to add {global}, but eh)
<3
Thanks so much for the help!
Love the way the Input System and Localisation system are built, they’re extensible but also they feel very at home inside of Unity!
I might post it up after a bit if cleaning. (Especially regarding the way the BindingDisplayString is resolved to a sprite, because currently I have some issues with Keyboard “X” vs Gamepad “X”. I guess I should use the control Path instead of the BindingDisplayString. )
I want to represent the bindings of the InputActions in the localization system. However, I can’t quite follow the described explanations.
What would be the best practice to include the InputActions in the localization system in a newer version of the localization package as either local or global variables?
Hey @karl_jones , finally took time to pour this into a neat little package that does the plumbing between the Input System and the Localization System:
@karl_jones I’m trying to implement similar thing with your LiteralTextSource and custom formatter.
[DisplayName("Input Action Formatter")]
public class InputActionFormatter : FormatterBase
{
private const string SpriteAssetName = "InputHints";
public override string[] DefaultNames => new[] { "input" };
public override bool TryEvaluateFormat(IFormattingInfo formattingInfo)
{
if (formattingInfo.CurrentValue is string actionName)
{
InputAction action = GetAction(actionName);
string displayString = action.GetBindingDisplayString(group: "Gamepad");
Debug.Log(displayString);
formattingInfo.Write($"<sprite=\"{SpriteAssetName}\" name=\"{displayString}\">");
return true;
}
return false;
}
public InputAction GetAction(string actionName)
{
return InputSystem.actions.FindAction(actionName);
}
}
With this i can just write something like Press {"Attack":input()} to attack
But I’m not sure how to notify this formatter when input device or binding is changed so it can update itself with new values. Maybe with custom variable I can update formatter with current device but I don’t know how to use literal text and variable at the same time. Do you have any thoughts how this can be implemented?