-
Notifications
You must be signed in to change notification settings - Fork 2.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add Interactable event via script #5013
Comments
@fcagnetta , hello! Can you elaborate on what you mean by "add events"? Do you mean just subscribe to the OnClick Unity event inside Interactable.cs and thus be able to assign actions at runtime when a user selects the Interactable? If so, this is possible.
|
Hi Troy, sorry I try to explain better: If you programmatically add Interactable component to an object, and then you want to add a listener for OnClick event and for OnFocus (on and off) event, and X other event you may need, how can you do that? OnClick event is automatically provided so you can just add a listener to it, but what about the others? In the inspector you can just click add event and choose among a list of events, then you drag the script on which the method you want to call resides onto. How to script this? |
Ah I see now. I know in Unity inspector it says "Add event", but to be all on the same page, you mean add InteractableEvent objects dynamically. The "Add event" in the inspector I am pretty sure just represent InteractableEvent objects. The property we want is Interactable.Events and I believe if added correctly this could work. But the InteractableEvent creation isn't super obvious. For example, protected SetupEvent() in Interactable gets called on Awake so you would have to link in those pieces yourself? @killerantz can you help with better guidance? |
Meanwhile I would like to add a bit of code of a use case for the OnClick() event registration:
I get a null exception when Interactable.cs runs SetupStates() (line 272) |
A good way to do this is implement the IInteractableHandler interface and call the Interactable.AddHandler(IInteractableHandler handler) method. This will call two events methods and track all the state changes currently being set in Interactable. public virtual void OnStateChange(InteractableStates state, Interactable source)
{
print(source.HasFocus);
// the state has changed, do something new
/*
bool hasDown = state.GetState(InteractableStates.InteractableStateEnum.Pressed).Value > 0;
bool focused = state.GetState(InteractableStates.InteractableStateEnum.Focus).Value > 0;
bool isDisabled = state.GetState(InteractableStates.InteractableStateEnum.Disabled).Value > 0;
bool hasInteractive = state.GetState(InteractableStates.InteractableStateEnum.Interactive).Value > 0;
bool hasObservation = state.GetState(InteractableStates.InteractableStateEnum.Observation).Value > 0;
bool hasObservationTargeted = state.GetState(InteractableStates.InteractableStateEnum.ObservationTargeted).Value > 0;
bool isTargeted = state.GetState(InteractableStates.InteractableStateEnum.Targeted).Value > 0;
bool isToggled = state.GetState(InteractableStates.InteractableStateEnum.Toggled).Value > 0;
bool isVisited = state.GetState(InteractableStates.InteractableStateEnum.Visited).Value > 0;
bool isDefault = state.GetState(InteractableStates.InteractableStateEnum.Default).Value > 0;
bool hasGesture = state.GetState(InteractableStates.InteractableStateEnum.Gesture).Value > 0;
bool hasGestureMax = state.GetState(InteractableStates.InteractableStateEnum.GestureMax).Value > 0;
bool hasCollistion = state.GetState(InteractableStates.InteractableStateEnum.Collision).Value > 0;
bool hasCollistion = state.GetState(InteractableStates.InteractableStateEnum.VoiceCommand).Value > 0;
bool hasCustom = state.GetState(InteractableStates.InteractableStateEnum.Custom).Value > 0;
*/
}
/// <inheritdoc />
public virtual void OnVoiceCommand(InteractableStates state, Interactable source, string command, int index = 0, int length = 1)
{
// Voice Command Happened
}
/// <inheritdoc />
public virtual void OnClick(InteractableStates state, Interactable source, IMixedRealityPointer pointer = null)
{
// Click Happened
} Another option is to have a component that monitors Interactable.HasFocus or Interactable.HasPress on update. Since we could be trying to tack any combination of states to detect the pattern we care about, we didn't set up all the state changes as events, but an OnStateChanged event may be helpful. |
At the moment, I workarounded this with a script which implement a couple of interfaces, including IMixedRealityInputHandler and its "sisters", and programmatically attached to the gameobjects I need to interact with. |
I've just verified that adding OnClick event handler to dynamically instantiated interactable actually works in the GA release, added a test for this. Yay! |
## Overview Most UI frameworks allow for event listeners to be added not only from a GUI editor, but also from code. MRTK currently makes it easy for event listeners on Interactable (except OnClick) to be configured in the editor, but configuring at run-time from script is not possible. This PR does the following: 1. Fixes bugs preventing adding events at run-time 1. Adds utility scripts to Interactable to simplify adding Interactable event listeners 1. Adds tests to verify all event listeners available in interactable by default 1. Adds examples to documentation ### Demo: Old vs. new way to add event listeners Here's the old way to listen to focus enter/exit events: ```csharp public static void AddFocusEvents(Interactable interactable) { var ie = new InteractableEvent(); var fr = new InteractableOnFocusReceiver(ie.Event); ie.Receiver = fr; interactable.Events.Add(ie); ie.Event.AddListener(() => Debug.Log("Focus on")); ie.OnFocusOff.AddListener(() => Debug.Log("Focus off")); } ``` And the new way to add focus enter/exit events: ```csharp public static void AddFocusEvents(Interactable interactable) { var onFocusReceiver = interactable.AddReceiver<InteractableOnFocusReceiver>(); onFocusReceiver.OnFocusOn.AddListener(() => Debug.Log("Focus on")); onFocusReceiver.OnFocusOff.AddListener(() => Debug.Log("Focus off")); } ``` - Fixes: #5013 ## Verification Verify that new tests pass, and that they did not pass before.
Fixed |
Describe the problem
It would be useful to add events to interactables via script. Imagine cases in which we add the script at runtime.
Describe the solution you'd like
It would be great a simple way to do that (still I can't find out how). Ok, maybe not same as OnClick event that is completely exposed, but something easy to implement.
Describe alternatives you've considered
Use a global listener instead of interactable script
Additional context
Same for interactable receiver script, and so on.
The text was updated successfully, but these errors were encountered: