- Home /
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?
Okay, assu$$anonymous$$g you're talking about the types like "HoldInteraction" etc, I've never seen these before. So far I see that they're types, but I don't really understand how I'm supposed to connect these to an action. How do I make the HoldInteraction refer to a specific action on an action map? Thanks
No what I mean is why are you invoking your events instead of having unity invoke them.
You are supposed to just handle them.
Oops I was answering the wrong post I will do one for you too.
Answer by sacredgeometry · Dec 04, 2021 at 04:44 PM
Here's a video explaining a way to do it:
https://www.youtube.com/watch?v=jhjYyomSbYY
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.
Thats quite alright. On closer inspection it looks like maybe you can bind directly to fields from value actions too. So that would be shorthand for getting the mouse position
I havent tried it but thats what it looks like from the video I made
Answer by Jnsptz · Dec 03, 2021 at 05:52 AM
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.
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 co$$anonymous$$g off as demeaning, I'm genuinely trying to learn. Thanks.
I guess it depends on the situation. You're already trying to do something when Move is triggered but you're trying to feed a vector2 to a rigidbody velocity but that is a vector3. You can get the value like this movementDirection = context.ReadValue<Vector2>();
then, in your OnMoveStart set the velocity using the direction and speed. velocity = new Vector3(movementDirection.x, 0f, movementDirection.y)
Are you calling OnMoveStart in the player input (the 2nd screenshot)?