Input System and instantiating object

Hello,
it’s been a while since I worked with Unity, and the “new” Input System wasn’t a thing back then.

I wrote this simple script to instantiate an object when I press a key:

using UnityEngine;
using UnityEngine.InputSystem;

public class UIExitShipPrompt : MonoBehaviour
{
    public GameObject humanPrefab;
    public Transform humanSpawnPosition;

    private float exitShipInput;

    private void Update()
    {
        ExitShipInvoked();
    }

    public void OnExitShip(InputAction.CallbackContext context)
    {
        exitShipInput = context.ReadValue<float>();
    }

    private void ExitShipInvoked()
    {
        if (exitShipInput >= 0.1f || exitShipInput <= -0.1f)
        {
            GameObject human = Instantiate(humanPrefab, humanSpawnPosition.position, humanSpawnPosition.rotation);
            PlayerEntity.instance.MovePlayerEntity(human);
        }
    }
}

Now, the problem is the human gets instantiated twice. It’s like the input is being detected more than needed. It acts like I’m somehow holding the key, but all I want is a “press only” behaviour.

In the Player Input component, I’m using Unity Events. The action is mapped to the Spacebar key, Action Type “passthrough” and Control Type “button”.
What’s going wrong in here?

Thanks in advance!

ExitShipInvoked() is called every frame.

Its condition on line 23 could certainly be valid for more than one frame.

Why not just keep the human in another class instance variable and don’t spawn him when you already have him?

Hello and thanks for answering. I have been away so I couldn’t reply sooner.

I have made a few changes in various scripts. Regarding the enter/exit ship functionality, I still have a problem.
I have the same button for both the enter and exit ship action, and those actions are separate actions in the InputActions asset.

When I press the key to enter the ship, it performs both the enter and immeditely after the exit ship action (I added a Debug.Log(context.phase) line):

It seems like the performed phase is too “long” and it detects more than one input, so the second input triggers the OnExitShip method.

This is the Enter Ship code:

using UnityEngine;
using UnityEngine.InputSystem;

public class EnterShip_PE : MonoBehaviour
{
    public void OnEnterShip(InputAction.CallbackContext context)
    {
        Debug.Log($"OnEnterShip: {context.phase}");
        EnterShipInvoked();
    }

    private void EnterShipInvoked()
    {
        PlayerEntity.instance.MovePlayerEntity(GameManager.instance.nearShip);
        Destroy(GameObject.Find("Human(Clone)"));
    }
}

Input should generally be gathered in one step (into local variables), then processed in a second step, where those variables can be “consumed.”

This way you don’t have two separate functionalities trigger off the same intent.

Otherwise yes, you can have weird chains of cross-behaviour triggered off of one trigger leading to another.

Usually with getting in and out of doors, the ONLY thing the trigger says is “you are close enough that the exit key might work.”

Then over in Update() you check if the exit was hit: if it was, you clear the variable and exit the ship.

1 Like

Enter ship and exit ship are mapped on the same key but they belong to two different action maps (one for entering, one for exiting).

I already have a few player states in GameManager that check for possible situations:

  • if player can enter ship → the enter ship action map is enabled and the exit ship action map is disabled, since if he can enter a ship it means he’s not actually inside a ship
  • Once entered, the enter ship action map is disabled and the exit ship action map enabled
  • etc

So, I tried to implement what you suggested but it actually gives the same result: the exit ship action gets triggered immediately after entering. I suspect I didn’t implement it correctly then:

using UnityEngine;
using UnityEngine.InputSystem;

public class EnterShip_PE : MonoBehaviour
{
    private float enterShipInput;

    private void Update()
    {
        if (enterShipInput > 0.1f)
        {
            enterShipInput = 0;
            EnterShipInvoked();
        }
    }

    public void OnEnterShip(InputAction.CallbackContext context)
    {
        enterShipInput = context.ReadValue<float>();
    }

    private void EnterShipInvoked()
    {
        PlayerEntity.instance.MovePlayerEntity(GameManager.instance.nearShip);
        Destroy(GameObject.Find("Human(Clone)"));
    }
}

In Update, I check for the variable containing the input. If I detect input, I clear the variable and perform the enter ship action. The problem is I still have the exit ship action performed.

EDIT: wait, I didn’t apply the same solution to the Exit Ship code. Now that in both codes I read the input “variable”, things work as expected. Thank you!

1 Like