Interaction and input

Interaction runs on each player's game: the player who uses or grabs an object gets the callback on their own game. To show it to the others, sync it (synced objects and values) or send an event (network events). The server has no player: these calls are refused there, so make them in a script marked [ClientOnly] or behind if (!World.isServer).

Objects players use

csharp
using NodeWorld.Flux;

namespace MyWorld
{
    public class Doorbell : FluxScript
    {
        public AudioSource chime;

        protected override void Start()
        {
            if (World.isServer) return;
            Interaction.SetInteractable(gameObject, true);
            Interaction.SetText(gameObject, Player.language == "fr" ? "Sonner" : "Ring");
        }

        protected override void OnInteract() => chime.Play();
    }
}
  • Interaction.SetInteractable(go, true): players point at the object and use it (the trigger in VR, the left click with keyboard and mouse: see controls): OnInteract() runs on the scripts of that object, on that player's game.
  • The object needs a collider, on it or a child; a trigger collider works too. Without one, the log says 'Doorbell' has no collider: it cannot be clicked.
  • Interaction.SetText(go, text): the text a player sees when pointing at it ("Sit", "Take off"…); empty: none. GetText(go) reads it.
  • SetInteractable(go, false) turns it off.

Objects players grab

  • Interaction.SetGrabbable(go, true): players take the object in their hand. OnGrab() and OnDrop() run on that player's game; while they hold it, the trigger gives OnUseDown() and OnUseUp().
  • It needs a collider ('Cup' needs a collider to be grabbed.) and gets a Rigidbody if it has none. Its Rigidbody decides how it is let go: kinematic, it stays where it is let go; not kinematic, it is thrown.
  • Interaction.SetGrabOptions(go, exactGrip, allowTheft): exactGrip keeps it where the hand took it (otherwise it snaps to the hand); allowTheft lets another player take it from the hand that holds it.
  • Interaction.IsHeld(go), Interaction.GetHand(go) (Hand.Left, Hand.Right or Hand.None), Interaction.GetHeld(hand) and Interaction.Drop(go) for the local player.

An object is grabbable or interactable, not both: 'Cup' is interactable: an object is grabbable or interactable, not both (a grabbable gets OnUseDown / OnUseUp).

A grabbed object stays in the hand of one player only, unless you sync it: give it a Network Id and call Networking.SyncTransform in Start. Grabbing it then takes its ownership. The SyncedGrabbable script of the example world does just that.

Zones the player walks into

On an object with a trigger collider (Is Trigger), OnPlayerTriggerEnter() and OnPlayerTriggerExit() run when the local player's body enters or leaves it. Each player's game tells its own player: a zone that opens a door "for whoever stands in it" opens it on that player's game, then syncs it.

For any collider entering a trigger (a ball, an object), see OnTriggerEnter in physics.

Keys, buttons and sticks

Input reads the local player's controls each frame:

Input.GetKey(key), GetKeyDown(key), GetKeyUp(key)A key of the keyboard (Key.Space, Key.E, Key.F1…), for players on a computer.
Input.GetButton(button), GetButtonDown(button), GetButtonUp(button)InputButton.Jump, Use (trigger of either hand), Grab (grip of either hand), LeftTrigger, RightTrigger, LeftGrip, RightGrip, LeftPrimary, RightPrimary (A, X), LeftSecondary, RightSecondary (B, Y), Down (crouch; C or Ctrl on a computer).
Input.GetAxis(axis)InputAxis.MoveHorizontal, MoveVertical (-1 to 1), LookHorizontal, LookVertical, and how far each trigger and grip is pressed (LeftTrigger… 0 to 1).
Input.isDesktopThe player plays with keyboard and mouse.

Some keys and buttons are the player's and always read as not pressed: Esc, P, Shift+R, and Y on the left controller. While the player types in a text field, your scripts get no key at all. See what a script cannot block and text fields.