Optimiza la entrada de tu juego en Unity con el mapeo por acciones. Al pasar de teclas específicas a acciones como Jump y Submit, el control se vuelve flexible y escalable: funcionará con teclado, ratón o mando sin cambiar código. Además, podrás ajustar sensibilidad y zona muerta para evitar entradas indeseadas en mandos usados.
¿Cómo unificar la entrada con el input manager de Unity?
El panel de Input en Project Settings ofrece un conjunto de ejes y botones ya configurados por Unity. Allí encontrarás axes como Horizontal y Vertical, acciones como Jump, Fire, y lecturas de ratón como Mouse X, Mouse Y o el scroll. Unity actúa como un manager: recibe señales del hardware y te devuelve una acción con nombre para tu código.
Jump viene asignado a la barra espaciadora. Útil para saltar de inmediato.
Fire suele estar en mouse 0. Puede reutilizarse si no hay disparo.
Submit equivale a Enter. Ideal para iniciar partida.
Horizontal/Vertical soportan flechas y teclas A/D como alternativas.
¿Qué configuraciones clave debes revisar?
Positive button: define la tecla principal de la acción.
Sensibilidad: suaviza o acelera la respuesta, útil en mandos desgastados.
Zona muerta: evita entradas por pequeñas vibraciones en sticks.
Botón positivo y negativo: dirección a favor o en contra del movimiento.
Alternativos (alt positive/negative): A/D además de flechas, por ejemplo.
Cuidado con reutilizar mouse 0 en varias acciones. Podría crear conflictos si luego implementas disparo.
¿Qué acciones útiles vienen preconfiguradas?
Horizontal y Vertical: flechas y A/D como alternativas.
Jump: generalmente en Space.
Fire: configurado con mouse 0.
Mouse X/Y y scroll: lectura de ratón.
Submit: asociado a Enter.
¿Cómo migrar el código a acciones?
La clave es sustituir lecturas directas de teclas por Input.GetButtonDown("NombreAcción"). Así te abstraes del hardware y cambias la configuración sin tocar scripts.
¿Cómo reescribir el salto con acciones?
Usa la acción Jump en lugar de la barra espaciadora. Si necesitas también ratón, añade mouse 0 como alternativa en el Input Manager o reutiliza Fire si no disparas.
// Antes: if (Input.GetKeyDown(KeyCode.Space)) { Saltar(); }// Después, con acción configurada en el Input Managerif(Input.GetButtonDown("Jump")){Saltar();}
¿Cómo iniciar la partida con submit?
Cambia la tecla fija (por ejemplo, "S") por la acción Submit para arrancar el juego con Enter.
// Antes: if (Input.GetKeyDown(KeyCode.S)) { EmpezarPartida(); }// Después: acción de entrada configurableif(Input.GetButtonDown("Submit")){EmpezarPartida();}
¿Qué ventajas obtienes con esta abstracción?
Te desacoplas del hardware.
Reconfiguras controles sin recompilar.
Preparas el juego para teclado, ratón o mando.
¿Cómo controlar el movimiento por estado y corregir bugs?
El personaje solo debe moverse cuando el GameManager esté en estado InGame. Si estás en Menú o Muerte, pausa el movimiento. Las indentaciones y comentarios ayudan a leer el código y entender la lógica al volver más tarde.
voidFixedUpdate(){if(GameManager.Instance.CurrentGameState == GameState.InGame){// Movimiento normal del personaje.AumentarVelocidadSiCorresponde();MoverPersonaje();}else{// Pausar solo el eje X, conservando caída natural en Y.var rb =GetComponent<Rigidbody2D>(); rb.velocity =newVector2(0f, rb.velocity.y);// Comentario: si no estamos dentro de la partida, detenemos el avance.}}
¿Cómo pausar sin frenar la caída?
Evita usar Vector2.zero al pausar, porque anula también la velocidad en Y y simula una caída a cámara lenta. La solución es crear un nuevo vector con X = 0 y Y = rb.velocity.y para mantener la gravedad.
¿Qué mejora queda pendiente como ejercicio?
Aun con el juego en pausa, el salto puede seguir activo. Envuélvelo en un if igual al del movimiento para que solo salte en InGame usando Input.GetButtonDown("Jump").
¿Con qué combinación de acciones vas a mapear primero? Comparte tu configuración y cómo resolviste el salto en pausa.
Yo logre detener el movimiento del personaje llamado a un método de su RigidBody2D
rigid.Sleep();
Mi código. Yo le tengo configurado para que no camine automáticamente, sino cuando yo presiono las flechas.
voidUpdate(){if(GameManager.sharedInstance.currentGameState==GameState.inGame){if(Input.GetButtonDown("Jump")){Jump();}} animator.SetBool(STATE_ON_THE_GROUND,isTouchingTheGround());Debug.DrawRay(this.transform.position,Vector2.down*1.4f,Color.red);// for debug purposes}voidFixedUpdate(){// if(rigidBody.velocity.x < runningSpeed){// rigidBody.velocity = new Vector2(runningSpeed, rigidBody.velocity.y);// }if(GameManager.sharedInstance.currentGameState==GameState.inGame){playerMovement();}}voidplayerMovement(){ float isWalking =Input.GetAxisRaw("Horizontal");if(isWalking !=0){//is true animator.SetBool(STATE_IS_QUIET,false); animator.SetBool(STATE_IS_WALKING,true); rigidBody.velocity=newVector2(isWalking * runningSpeed,rigidBody.velocity.y); spriteRenderer.flipX=(isWalking ==-1)?true:false;//if the value returns -1 that means is walking to the left and we need to make a flip in X}else{ animator.SetBool(STATE_IS_QUIET,true); animator.SetBool(STATE_IS_WALKING,false);}}
Yo lo tengo igual pero un poco diferente:
private void FixedUpdate()
{
if(Input.GetAxis("Horizontal") < 0)
{
rb.GetComponent<SpriteRenderer>().flipX = true;
rb.velocity = new Vector2(-walkSpeed , rb.velocity.y);
if (Input.GetKey(KeyCode.LeftShift))
{
rb.velocity = new Vector2(rb.velocity.x * runSpeed, rb.velocity.y);
animator.speed = animationRunMulti;
}
else
{
animator.speed = 1;
}
}else if(Input.GetAxis("Horizontal") > 0)
{
rb.GetComponent<SpriteRenderer>().flipX = false;
rb.velocity = new Vector2(walkSpeed, rb.velocity.y);
if (Input.GetKey(KeyCode.LeftShift))
{
rb.velocity = new Vector2(rb.velocity.x * runSpeed, rb.velocity.y);
animator.speed = animationRunMulti;
}
else
{
animator.speed = 1;
}
}else
{
rb.velocity = new Vector2(0, rb.velocity.y);
}
}
Podemos encontrar la herramienta de Input Manager en Edit > Project Settings > Input.
Solo hay que hacer eso para declarar que el personaje solo salte en modo juego, sin embargo al probarlo les recomiendo cambiar un momento la tecla de salto o intenten saltar con el mouse, ya que como tenemos designado que se cambie el estado del juego a inGame con la tecla Enter, unity me reconoce el spacebar tambien como enter, por ende al orpimir la barra espaciadora el personaje salta y me cambia el estado del juego automaticamente.
<if(GameManager.sharedInstance.currentGameState==GameState.inGame)// solo puede saltar si esta en modo juego{if(Input.GetButtonDown("Jump"))//condicional para que se ejecute metodo jump al oprimir espacio o click derecho{Jump();}}>
Sí, porque la tecla space esta configurada como alternativa.
entonces hay que quitar el spacebar como alternativa al submit
Para los que lo están viendo en Diciembre 2021 la ruta es
Edit > Project Settings > Input Manager
Muchas gracias! 2023 y sigue sirviendo :)
Saludos. Activé el brinco solo si el estado del Juego está en "inGame":
En el caso de que se quiera usar movimiento tanto horizontal como vertical controlado por el usuario. se debe usar la palabra "Horizontal" y "vertical" y para saber si es movimiento positivo o negativo, se debe usar el metodo GetAxisRaw.
// movimiento a la derechaif(Input.GetButton("Horizontal")&&Input.GetAxisRaw("Horizontal")>0)// movimiento a la izquierdaif(Input.GetButton("Horizontal")&&Input.GetAxisRaw("Horizontal")<0)// movimiento hacia arribaif(Input.GetButton("Vertical")&&Input.GetAxisRaw("Vertical")>0)// movimiento hacia abajoif(Input.GetButton("Vertical")&&Input.GetAxisRaw("Vertical")<0)
Yo lo solucione de esta forma
//saltara solo si se presiona la tecla designada por unity para el salto y si estamos en modo juegoif(Input.GetButtonDown("Jump")&&Gamemanager.ShareInstance.currentGameState==GameState.inGame){Jump();}```
Yo lo coloqué ahí para ahorrar recursos? Lo revisará solamente al saltar en lugar de buscar en cada frame, imagino que servirá mas adelante :D
Buena solución!
arregle el bug apagando el rigidbody en vez de modificando su velocidad, de esta manera no se ve afectado por las fisicas
Yo programé que mi personaje se mueva a izquierda o derecha cuando oprimo A/D o las flechas, pero cuando quiero poner el código como dice en el video (El "GetButton") y le pongo el botón horizontal ((Input.GetButton("Horizontal")), mi personaje solo camina hacia la derecha pero no a la izquierda, a pesar de que en el Input Manager viene como botón positivo la derecha y negativo la izquierda.
¡Hola! :D
Si pudieras compartirnos tu código sería más sencillo encontrar el problema. Puedes copiar y pegar utilizando el botón de </> código.
También puedes agregar una imagen para conocer más sobre tu programa. Solo tienes que arrastrar la imagen o archivo que quieres subir a la sección de comentarios. También puedes agregar imágenes copiando la url de internet y pegando entre los paréntesis donde dice URL utilizando el botón de esta caja de comentarios. Sustituyes la palabra entre paréntesis URL por la dirección de la imagen. Puedes utilizar IMGUR (así lo encuentras en google) para subir tus imágenes a internet y después copias y pegas la dirección.!gif
¡Saludos!
Gracias, este es el codigo del movimiento del personaje.
void FixedUpdate()
{
Move();
{
if (Input.GetButton("Horizontal"))
{
Rb.velocity = new Vector2(runningSpeed * 1, Rb.velocity.y);
}
else if (Input.GetButton("Horizontal") || Input.GetKey(KeyCode.LeftArrow))
{
Rb.velocity = new Vector2(runningSpeed * -1, Rb.velocity.y);
}
else
{
Rb.velocity = new Vector2(runningSpeed * 0, Rb.velocity.y);
}
En mi caso al teclear la barra espaciadora se iba a inGame porque en el input manager en el segundo submit lo tiene configurado con esa tecla
Si al utilizar el input manager ''Jump", lo configure para que salte con la tecla "w", pero salta tambien con "space".
Por que pasa esto??
Nota: No hay ningun alternative o negative button
publicclassGameManager:MonoBehaviour{publicGameState currentGameState =GameState.menu;//"Singleton" is a unique script that will be used for a specific set of functionalities or a particular group, and it cannot conflict with others of the same type, such as the current state of the game.publicstaticGameManager sharedInstance;//se llama shared instance porque hace mas enfacis al singletonvoidAwake(){if(sharedInstance ==null){ sharedInstance =this;}}// Start is called before the first frame updatevoidStart(){ currentGameState =GameState.menu;}// Update is called once per framevoidUpdate(){if(Input.GetButtonDown("Submit")){if(currentGameState ==GameState.menu){StartGame();}else{BackToMenu();}}}publicvoidStartGame(){SetGameState(GameState.inGame);}publicvoidGameOver(){SetGameState(GameState.gameOver);}publicvoidBackToMenu(){SetGameState(GameState.menu);}voidSetGameState(GameState newGameState){ currentGameState = newGameState;switch(newGameState){caseGameState.menu:// TODO: Implementar la lógica para mostrar el menúTime.timeScale=0;break;caseGameState.inGame:// TODO: Implementar la lógica para iniciar el juegoTime.timeScale=1;break;caseGameState.gameOver:// TODO: Implementar la lógica para mostrar la pantalla de Game Over y reiniciar el juegoTime.timeScale=0;break;default:break;}}```yo preferi hacerlo directamente en el game manager, ya que es mucho mas sencillo encontrarlo, ademas modificando el timescale te ahorras codigo en el playercontroller.
yo creo que esto lo deberia de programar en el game manager, a pesar de que el profe lo haga en el player controller, ya que es mucho mas sencillo ademas encontrar estas cosas aqui. por sierto utilice otro metodo que es modificando la escala de tiempo, es decir, si estas en in game, la escala es 1 y el tiempo corre normal, sin embargo, estando en menu, o game over deberia ser 0 y el tiempo se ve parado. ```js
public class GameManager : MonoBehaviour
{
public GameState currentGameState = GameState.menu;
//"Singleton" is a unique script that will be used for a specific set of functionalities or a particular group, and it cannot conflict with others of the same type, such as the current state of the game.
public static GameManager sharedInstance; //se llama shared instance porque hace mas enfacis al singleton
void Awake(){
if (sharedInstance == null){
sharedInstance = this;
}
}
// Start is called before the first frame update
void Start()
{
currentGameState = GameState.menu;
}
// Update is called once per framevoidUpdate(){if(Input.GetButtonDown("Submit")){if(currentGameState ==GameState.menu){StartGame();}else{BackToMenu();}}}publicvoidStartGame(){SetGameState(GameState.inGame);}publicvoidGameOver(){SetGameState(GameState.gameOver);}publicvoidBackToMenu(){SetGameState(GameState.menu);}voidSetGameState(GameState newGameState){ currentGameState = newGameState;switch(newGameState){caseGameState.menu:// TODO: Implementar la lógica para mostrar el menúTime.timeScale=0;break;caseGameState.inGame:// TODO: Implementar la lógica para iniciar el juegoTime.timeScale=1;break;caseGameState.gameOver:// TODO: Implementar la lógica para mostrar la pantalla de Game Over y reiniciar el juegoTime.timeScale=0;break;default:break;}}
PlayerController:
voidUpdate(){// Se gestionan las animaciones arriba para evitar bugs visuales in-game anim.SetBool(STATE_GROUNDED,IsGrounded()); anim.SetBool(STATE_WALKING, rigidBody.velocity.x!=0);// Se invierte este if para mejorar la legibilidad y reducir la complejidad cognitivaif(GameManager.sharedInstanceGM.currentGameState!=GameState.inGame)return;if(Input.GetButtonDown("Jump")){Jump();}Debug.DrawRay(this.transform.position-newVector3(0, playerCollider.size.y/2,0),Vector2.down* gndRaycastLenght,Color.red);}
voidFixedUpdate(){// Se invierte este if para mejorar la legibilidad y reducir la complejidad cognitivaif(GameManager.sharedInstanceGM.currentGameState!=GameState.inGame)return; float xAxis =Input.GetAxis("Horizontal");if(xAxis !=0){Walk(xAxis);}}
Finalmente se edita el Input Submit para que no se ejecute al presionar la barra espaciadora.
A mi me sale un error al tratar de cambiar el GameState.
Me sale este error:
NullReferenceException: Object reference not set to an instance of an object
Player_controler.FixedUpdate () (at Assets/Scripts/Player_controler.cs:46)
¿Qué debo de hacer?
copie lo mismo del profesor
coloca un print screen para ver mejor la falla, pero revisa, que estes instanciando correctamente la clase del gamemanager con isntances
voidJump(){if(GameManager.sharedInstance.currentGameState==GameState.inGame){if(IsTouchingTheGround())//dependiendo del valor regresado del metodo, si es true pasara al salto{ playerRB.AddForce(Vector2.up* jumpForce,ForceMode2D.Impulse);}}}```