- Home /
How to get multiple inputs from keyboard at once?
Hi, I have this problem: I write the code for moving a ball in a 3D enviroment by using Input.GetKey. When I want to move the ball to a diagonal direction and jump at the same time I press up arrow + left arrow and space to jump. but the player doesn't jump, It only translates in the diagonal direction. How can I solve this problem? It can be a problem of my keyboard settings?
Thank you in advance for any answer!
I let you the code:
using System.Collections; using System.Collections.Generic; using UnityEngine;
public class Giocatore : MonoBehaviour {
public float moveSpeed; // magnitude of velocity
public bool jump; // variable to know if the player is touching the terrain or not
Vector3 direction; // unit vector to define the direction of the force to be applied on the player
public float drag = 0.9f; // friction
public float terminalRotationSpeed = 100.0f;
private Rigidbody controller;
void Start()
{
controller = GetComponent<Rigidbody>();
controller.maxAngularVelocity = terminalRotationSpeed;
controller.drag = drag;
moveSpeed = 10.0f;
direction = new Vector3(0.0f,0.0f,0.0f);
}
void Update()
{
// INPUTS: here I define the component of the unit vector "direction"
if(Input.GetKey(KeyCode.UpArrow))
{direction.z = 1f;}
else if (direction.z > 0f)
{direction.z = 0f;}
if(Input.GetKey(KeyCode.RightArrow))
{direction.x = 1f;}
else if(direction.x > 0f)
{direction.x = 0f;}
if(Input.GetKey(KeyCode.LeftArrow))
{direction.x = -1f;}
else if(direction.x < 0f)
{direction.x = 0f;}
if(Input.GetKey(KeyCode.DownArrow))
{direction.z = -1f;}
else if(direction.z < 0f)
{direction.z = 0f;}
if(direction.magnitude > 1)
{direction.Normalize();}
if(Input.GetKey(KeyCode.Space) && jump == false) // jump only if the player is touching the ground
{direction.y = 1.0f; }
else if(direction.y > 0f)
{direction.y = 0f;}
}
void FixedUpdate()
{
direction.y = direction.y * 20.0f;
controller.AddForce(direction * moveSpeed, ForceMode.Force);// Force
}
void OnCollisionEnter(Collision col)
{
if(col.gameObject.tag == "Terrain") // if the player is touching the ground, It can jump
{jump = false;}
}
void OnCollisionExit(Collision col)
{
if(col.gameObject.tag == "Terrain") // if the player isn't touching the ground, It can't jump
{jump = true;}
}
}
By pressing the arrows key, you set the component of an unit vector (called direction) which will be used to define the direction of the force that will be applied on the player.
There is no code there for when you press space nor anything setting a direction for the y axis.
Answer by Bunny83 · Sep 27, 2019 at 01:18 AM
This is known as key-ghosting and is a hardware limitation that you can not bypass besides buying a new / better keyboard that allows either n-key-rollover or has a different matrix layout so the ghosting doesn't happen on the desired keys. Some gaming keyboards have a specialized matrix layout that avoids ghosting more or less around the wasd keys. Though the exact wireing depends on the manufacturer of the keyboard.
The best solution for you as developer is to provide a key config for the user so he can change the keys. A common alternative is to use keys which are almost always on seperate scan lines like the CTRL or ALT keys. For more information see this question
Answer by Rocketman_Dan · Sep 26, 2019 at 01:57 AM
Your question is missing quite a lot of context so I'll try to cover all the bases.
You're already getting multiple keyboard inputs at once by getting multiple directional keys. The problem you have is a logic one not an issue of getting more than one key at a time.
You currently must be always translating by direction
for movement. If direction
is an angled vector and you don't change the logic to be any different from your movement code you will simply translate on a diagonal. Depending on the type of game you are going for there are some ways to tackle this.
If every frame you are doing an Input.GetKey
you will get translation over time. To get a onetime effect when you press a button you need to use Input.GetKeyDown
which only fires if this is the first frame where that button was pressed. I personally wouldn't use either but I'll get to that later. Point is that without seeing your code my best guess is that this is what you are doing.
If this is a sidescrolling game then give the ball a rigidbody and collider and give the surface that it sits on a collider also. Then you can use RigidBody.Addforce(direction * jumpStrength)
(where jumpStrength is a multiplier to get the length of the vector you want to use) to throw the ball along a vector and it will fall back down according to gravity. This is a jump.
If this is a topdown plane with a ball rolling on top of it like the roll a ball tutorial then you'll want to do the same thing but just define a unit vector for up and do the same thing. You will get a decent looking jump where the hop happens in the direction of travel. before you press the jump key.
If you do either of these you get the added benefit of being able to use unity physics collisions to check if you are grounded so that you can't repeatedly jump mid air instead of using raycasts. If this ends up being the route you go I'm happy to explain that further but it's not relevant to this specific question.
Finally I'd recommend that instead of using GetKey(Keycode.UpArrow)
etc use Input.GetAxis("Horizontal")
, Input.GetAxis("Vertical")
and Input.GetButton("Jump"). The axes will return positive or negative 1 for keypresses of WASD or up, down, left, right and also works with controllers. GetButton("Jump") works on space or a user defined jump button (defaults to A on xbox and X on dualshock controllers). It simply returns a bool to say whether or not the button is pressed. If you want it to fire once like I mentioned above you'll want to use `Input.GetButtonDown("Jump").
I know that looks like a lot but there are really a lot of ways of implementing what you want. The best way changes depending on context but the basic principles stay the same :fire jump actions only once, use GetAxis or GetButton, and take advantage of unity physics to save you brainpower on the maths.
I can't jump and at the same time translate the player in a diagonal direction if I press right arrow + uparrow (and plus space to jump) or down arrow + right arrow (and plus space to jump), in the others cases this problem doesn't exist. I have the same problem by using GetAxis to translate and GetButton("Jump") as you adivised to me :(
Answer by 9NICK6 · Sep 26, 2019 at 09:08 PM
I don't know why, but I have this problem only if I use arrow Keys. If I use WASD, there isn't this problem. Thus, my problem is partially solved
Answer by maw0041 · Sep 27, 2019 at 08:47 PM
You can try this...
Conditional Operators:
&& " AND "
|| " OR "
Using these within the if statement may help you achieve your goals. Here is some pesudocode...
if(pressing mouse && pressing arrow)
...
// This means that both mouse button and arrow button must be pressed before it will enter the if statement, and execute the code in it
if(pressing mouse || pressing arrow)
...
// This means that if either one of those things are happening the if statement will run. One could be false/inactive, while the other would be true and so it would still execute the if.
Sorry if this wasn't what you were looking for in an answer. I thought it may help a little to check for specific conditions like jumping and moving in a direction at the same time.