You can also use the "Install from Git URL" option from Unity Package Manager to install the package.
https://github.com/Studio-23-xyz/InteractionSystem.git#upm
https://openupm.com/packages/com.studio23.ss2.interactionsystem/
The samples scene contains an example setup. You will need in the scene:
- An
InteractionManager
singleton. - An
InteractionPromptController
configured in the scene - The
InteractionPromptController
will require anInteractionPromptModel
andInteractionPromptView
configured in the scene. - A
PlayerInteractionFinder
to detect interactables in the scene.
Interactables can be in 3 states:
public enum InteractionState{
Inactive,//interaction hasn't started yet.
Active,//runing interaction logic
Paused,// running a sub-interaction or some other case when we don't want the interaction to run logic
}
The CurState
field returns the Interactable's current state. InteractableBase handles setting the value. So Custome Interactables inheriting from it don't need to manually set it.
If you start an interaction while one is running, the old interaction is paused and the new interaction is started as a subinteraciton. When the subinteraction ends, the old interaction is resumed.
You can define your own Interactable by inheriting from InteractableBase
.
Be sure to use the cancelaltion token when overriding DoNormalInteraction()
and DoDisabledInteraction()
if you want subinteractions.
If you want to push another interaction over an interaction(like dialogue during inspection),
public abstract bool CanBeInterrupted { get; }
should be overridden to true. Otherwise false.
The interaction ends immediately when the DoNormalInteraction returns. Write the async function that lasts as long as the interaction should last. Ex: If you play the door opening animation, you could make the async function wait until the door is played.
Pick one of the buttons in InteractionManager.Instance.InputHandler
public override InputButtonSlot InputButton => InteractionManager.Instance.InputHandler.ToggleButton;
-
Interaction.HandleInteractionStarted()
-
Interaction.HandleInteractionResumed()
-
Interaction.HandleInteractionPause()
-
Interaction.HandleInteractionCompleted()
Add InteractionConditions to the InteractionConditions list in the InteractableBase monobehavior. Interaction System goes through all Interactables in a given gameobject and picks the first interactable whose conditions return InteractionConditionResult.Show
. The Interactable component order on the gameobject affects this.
Additionally if the Interactable is not enabled, it is skipped. So you can control which interactable gets picked by disabling them.
This may be overhauled in the future.
We want to open the door if the player has the key, Otherwise we want to play a locked door rattling animation
Make two interactables. One for opening. One for the locked door rattling interaction. Put both on same door object.
On the open door interaction, add a InteractionCondition that returns InteractionConditionResult.show
if the player has the key.
No need for any conditions on the locked door interaction. It will be the "default" interaction. However, the component order should come after the open door interaction.
InteractionConditions return an InteractionConditionResult
result with 3 values:
-
Show: Shows the prompt for the interactable when this result is returned
-
Hide: Hides the prompt for the interactable when this result is returned
-
Passthrough: Defers to next InteractionCondition in list when this result is returned. If this is the last InteractionCondition in the list, the final result becomes
InteractionConditionResult.Hide
Ex: If Interaction1, Interaction2 is in list, and Interaction1 returns Passthrough-
If interaction2 returns Show or Hide, the final result is show or hide accordingly
-
If interaction2 returns Passthrough, the final result is Hide.
-
You can write your own InteractionCondition in SS2 implementing the InteractionCondition class.
-
Be sure to use the cancellation token . Otherwise interrupt will not work
-
DoNormalInteraction()
can be called multiple times if the interaction can be interrupted.-
Flow:
-
Interaction.HandleInteractionStarted()
-
Interaction.DoNormalInteraction()
-
Interrupt happens by starting a sub interaction
-
Interaction.HandleInteractionPause()
-
SubInteraction.HandleInteractionStarted()
-
SubInteraction.DoNormalInteraction()
-
Assuming the SubInteraction runs until completion
-
SubInteraction.HandleInteractionCompleted()
-
Interaction.HandleInteractionResumed()
-
Interaction.DoNormalInteraction()
-
Assuming this time Interaction runs until completion
-
Interaction.HandleInteractionCompleted()
-
-
Do your setup work in
HandleInteractionStarted()
andHandleInteractionResumed()
-
Ensure that there is no issue if DoNormalInteraction is called multiple times and can be cancelled.
-
-
You don't have to worry about interrupt if you override
CanBeInterrupted
to false.
The PlayerInteractionFinder
class raycasts through the scene to detect interactables. The _interactionLayerMask
field controls which layers it checks.
To show them:
var interactables = _interactionFinder.FindInteractables();
InteractionManager.Instance.ShowNewInteractables(interactables);
InteractionPromptController handles hold confirmation and starting interation.. The InteractionManager will automatically start a confirmation once the InteractionPromptController confirms one.
If the _interactionHoldTime
field on the interactable is > 0, then the InteractionPromptController will require holding the button for that amount of time.
You have to tell the InteractionManager to start the interaction:
Override the following functions:
/// <summary>
/// Interaction prompt prefix(ex: "Inspect")
/// </summary>
/// <returns></returns>
public abstract string GetPromptPrefix();
/// <summary>
/// Interaction prompt suffix that appears after the prompt
/// </summary>
/// <returns></returns>
public abstract string GetPromptSuffix();
/// <summary>
You can inherit from the InteractionPromptView
class to customize the Prompt UI.
InteractionManager fires the following events to tell you that
/// <summary>
/// Fired when we start the first interaction on the stack
/// Not fired when subinteractions are started
/// </summary>
public event Action OnInteractionChainStarted;
/// <summary>
/// Fired when we complete all the interactions on the stack
/// Or when we cancel the interaction confirmation without anything in the stack
/// Not fired when subinteractions are completed
/// </summary>
public event Action OnInteractionChainEnded;
public bool IsRunningInteraction{get;}
InteractionManager.IsRunningInteraction
can also be used to synchronously check if an interaction is running
Camera Stacking is removed