I’m attempting to implement jumping in my 2D platformer. The way I’m doing it works but it has numerous issues. I’m using the new Unity input system with unity events as my method of checking input; however, I’m not sure how to get the equivalent of GetKeyDown. With the following code the player jump input is read MANY times due to jumpInput equaling 1f numerous times per key press. (Since humans can’t exactly hit the key for only one frame.)
public void JumpInput(InputAction.CallbackContext context) {
jumpInput = context.ReadValue<float>();
}
private void ProcessJumping() {
Vector2 jumpVelocity = new Vector2(0f, jumpHeight);
if (jumpInput == 1) {
rb.velocity += jumpVelocity;
}
Vector2 vel = rb.velocity;
vel.y += Physics2D.gravity.y;
}
I’m not too familiar with the new input system so this may not be the best possible way to do it but this is how I did it,
using UnityEngine.InputSystem;
private void Awake() {
inputAction = new PlayerInputActions()
inputAction.PlayerControls.Jump.performed += Jump();
}
private void Jump() {
// Function that makes the player jump
}
private void OnEnable() {
inputAction.Enable();
}
private void OnDisable() {
inputAction.Disable();
}
Where PlayerInputActions is my input actions, PlayerControls is my action map and Jump is my jump action.
Edit: added in OnEnable() and OnDisable() functions that are also required.
you can check for a bool with inputAction.PlayerControls.Jump.triggered, assuming your input action is set up to work like a button. This will cause it to fire once on the frame, and not again.
You still need to do the OnDisable and OnEnable functions mentioned earlier, but this gets you as close to the old Input.GetKeyDown as you can get.
EDIT: The code would look like this:
using UnityEngine.InputSystem;
private void Awake() {
PlayerInputActions inputAction = new PlayerInputActions()
}
private void Update(){
if (inputAction.PlayerControls.Jump.triggered) {
Jump();
}
private void Jump() {
*Do your jump here*
}
private void OnEnable() {
inputAction.Enable();
}
private void OnDisable() {
inputAction.Disable();
}
Using the new Input system with DOTS
I have a Jump action defined in my PlayerInputActions asset. This Jump action has an action type of Button. It has two bindings: Space (for the Keyboard & Mouse control scheme) and Button South (for the Gamepad control scheme).
I then have the following System:
using UnityEngine;
using Unity.Entities;
using Unity.Jobs;
using UnityEngine.InputSystem;
// PlayerInputActions is the name of my Input asset
// Generated Input asset classes include an interface; making it easy to
// handle all the actions you created in code
public class GatherInput : SystemBase, PlayerInputActions.IPlayerActions {
private PlayerInputActions input;
private float jumping = 0;
// This is the handler for my Jump action
public void OnJump(InputAction.CallbackContext context) {
jumping = context.ReadValue<float>();
}
protected override void OnCreate() {
input = new PlayerInputActions();
// This registers this class as a handler for input events
// For every action you define you need an appropriate OnAction
// method in this class
input.Player.SetCallbacks(this);
}
protected override void OnStartRunning() => input.Enable();
protected override void OnStopRunning() => input.Disable();
// NOTE: Multiple input events can happen between executions of OnUpdate.
// This means that you need to be sure you sum up the data from all events
// between OnUpdate invocations for things like Delta bindings
protected override void OnUpdate() {
float j = jumping;
Entities.ForEach((ref PlayerInputData input) => {
input.Jumping = j;
}).Schedule();
// Resetting this value allows the player to press jump again
// NOTE: This means the player can spam the jump button
// Some sort of timeout would be nice if you wanted to do
// support double/triple jumps
jumping = 0;
}
}
PlayerInputData is a component:
using System;
using Unity.Entities;
using UnityEngine;
[Serializable]
[GenerateAuthoringComponent]
public struct PlayerInputData : IComponentData {
[HideInInspector]
public float Jumping;
public float JumpHeight;
}
This component is added to the player GameObject. I use sub-scenes, so my player GameObject gets converted to an entity automatically. If you’re not using sub-scenes, just make sure to add a ConvertToEntity component (you’ll likely want to specify Convert and Destroy as the Conversion Mode) to your player GameObject.
I then have a PlayerJump system:
using Unity.Entities;
using Unity.Physics;
public class PlayerJump : SystemBase {
protected override void OnUpdate() {
Entities.ForEach((
ref PhysicsVelocity velocity,
in PlayerInputData input
) => {
velocity.Linear.y += input.Jumping * input.JumpHeight;
}).Schedule();
}
}
This system causes the player to jump. If you don’t want to use physics, you could animate the player’s Translation.Value.y until it reaches input.JumpHeight.
The problem that I am having is that jump is not defined by my input system, but I have set it up just the same as I did with move and run which work perfectly. Does anybody know how to fix this? 