New Input System how to fire events continuously?

Hi guys,

I’m using the “new” input system, and I’m trying to get an OnMove event to continuously fire if the key binding is held down. I figured the best way to do this would be to have a bool that calls OnMove in Update if true, but in practice I’m not entirely sure how to get it to work, since the actions obviously need a callback context and I’m not even entirely sure what that is. Here’s what I tried:

public class PlayerController : MonoBehaviour
{
    [SerializeField] private int moveSpeed = 5;
    public bool isMoving;
    private Rigidbody2D rb;
    private void Awake()
    {
        rb = GetComponentInParent<Rigidbody2D>();
    }

    public void OnMoveStart(InputAction.CallbackContext context)
    { 
        rb.velocity = new Vector2(moveSpeed * InputManager.inputActionAsset.Ground.Move.ReadValue<float>(), 0);
        isMoving = true;
    }

    public void OnMoveEnd(InputAction.CallbackContext context)
    {
        isMoving = false;
    }
    private void Update()
    {
        if (isMoving)
        {
            OnMoveStart(); //obviously this line is not syntactically correct, as it needs a context parameter. rider's advice was to create a new instance of the callback context, which first of all doesn't work,but secondly I don't know how callback context works so it's confusing.

        }
    }
}

My Input Manager just subscribes the events to the input action asset and enables the action map, here it is:

public class InputManager : MonoBehaviour
{
    public static Controls inputActionAsset;
    public PlayerController Player;

    private void OnEnable()
    {
        inputActionAsset = new Controls();
        inputActionAsset.Ground.Move.started += Player.OnMoveStart;
        inputActionAsset.Ground.Move.performed += Player.OnMoveEnd;
        
        inputActionAsset.Enable();
    }


}

I made the Input Manager a child of the player which I intend on turning into a prefab to instantiate the player, because this seems like a good way to keep things separate. Thanks for any advice.

Why are you using a manual implementation to do this? Cant you use one of the built in bindings/ interaction types?

Oops I was answering the wrong post I will do one for you too.

2 Answers

2

You can read the context and get a vector2 which can be used to move a player.

public class Player : MonoBehaviour
{
    private Vector2 movementDirection;

    public void UpdatePlayerMovementVector2(InputAction.CallbackContext context)
    {
        movementDirection = context.ReadValue<Vector2>();
    }
}

Then you could invoke that from the player input move event.

[189484-333.jpg|189484]

This will return a vector 2 (0, 0) that tells you the direction.

(1, 0) = right
(-1, 0) = left
(0, 1) = forward
(0, -1) = back
(1, 1) = forward right diagonal, etc

private void Update()
{
    transform.Translate(new Vector3(movementDirection.x, 0, movementDirection.y) * Time.deltaTime, Space.World);
}

Hm. I'm trying to do this using events/delegates, ideally avoiding using an Update function if at all possible. The reason for that is mostly encapsulation, but also that it seems the entire point of the new input system is to use events instead of an Update function as Update() is quite an expensive operation. Am I incorrect in this assumption? This seems like the implementation I already have listed on the scripts above, just in an Update function instead of fired events. Is that the right way to do it? Hopefully I'm not coming off as demeaning, I'm genuinely trying to learn. Thanks.

Here’s a video explaining a way to do it:

----------

Additional “Reading”:


oh my god, this was so far beyond what I expected that I'm actually floored. Thank you for taking the time out of your day to help me with this, it's cleared up so much for me.