Capítulo 5 — Entrada do Jogador: Teclado, Mouse e Controle no MonoGame

Introdução: sem input, não existe jogo de verdade

Um jogo só vira jogo quan­do o jogador con­segue inter­a­gir.

Até aqui, nos capí­tu­los ante­ri­ores, você enten­deu o que é MonoGame, preparou o ambi­ente, estu­dou o game loop com Update e Draw, e apren­deu a desen­har sprites e tex­turas na tela.

Ago­ra chegou o momen­to em que o jogo começa a respon­der ao jogador.

É aqui que entram:

🎮 tecla­do;
🖱️ mouse;
🕹️ controle/gamepad;
⌨️ coman­dos;
👆 cliques;
🎯 ações;
🚀 movi­men­to;
⏸️ pausa;
✅ con­fir­mação;
❌ can­ce­la­men­to.

No MonoGame, a entra­da do jogador é trata­da prin­ci­pal­mente pelo name­space Microsoft.Xna.Framework.Input, que reúne class­es e estru­turas para lidar com tecla­do, mouse, gamepad e out­ros tipos de entra­da. A doc­u­men­tação ofi­cial descreve esse name­space jus­ta­mente como a área respon­sáv­el por key­board, mouse, gamepad e touch input han­dling.

A ideia cen­tral é sim­ples:

O jogador aper­ta algo. O jogo lê esse esta­do no Update. A lóg­i­ca responde. O Draw mostra o resul­ta­do.

Esse capí­tu­lo é fun­da­men­tal porque quase tudo em um jogo depende de input:

  • mover per­son­agem;
  • atacar;
  • pular;
  • abrir menu;
  • clicar em botão;
  • pausar;
  • sele­cionar opção;
  • usar item;
  • mirar;
  • con­fir­mar;
  • can­ce­lar;
  • nave­g­ar em inter­face.

Se o game loop é o coração do jogo, o input é o sis­tema ner­voso. É por ele que a von­tade do jogador entra no mun­do vir­tu­al.


🎮 O que é entrada do jogador?

Entra­da do jogador, ou play­er input, é qual­quer ação fei­ta pelo usuário para con­tro­lar o jogo.

Exem­p­los:

Dis­pos­i­ti­voExem­p­los de entra­da
Tecla­doW, A, S, D, setas, espaço, Enter, Escape
Mouseclique esquer­do, clique dire­ito, posição, scroll
Con­t­rolebotões, analógi­cos, gatil­hos, D‑Pad
Touchtoque, arras­to, gesto

Neste capí­tu­lo, o foco será nos três dis­pos­i­tivos mais comuns para jogos desk­top:

✅ tecla­do;
✅ mouse;
✅ con­t­role.

A doc­u­men­tação ofi­cial do MonoGame tem uma seção especí­fi­ca chama­da “Work­ing with Input”, cri­a­da para demon­strar como escr­ev­er códi­go para geren­ciar entra­da em pro­je­tos MonoGame usan­do tecla­do, mouse, gamepad e touch.


🧠 A regra principal: input deve ser lido no Update

No capí­tu­lo sobre game loop, você apren­deu:

Update pen­sa. Draw mostra.

Essa regra con­tin­ua aqui.

A entra­da do jogador deve ser lida no méto­do:

protected override void Update(GameTime gameTime)
{
// Ler teclado, mouse e controle aqui
}

Não coloque leitu­ra de tecla­do, mouse ou con­t­role den­tro do Draw.

O Draw deve ape­nas ren­derizar o resul­ta­do visu­al.

Exem­p­lo cor­re­to:

protected override void Update(GameTime gameTime)
{
KeyboardState keyboard = Keyboard.GetState();

if (keyboard.IsKeyDown(Keys.Escape))
Exit();

base.Update(gameTime);
}

Exem­p­lo erra­do:

protected override void Draw(GameTime gameTime)
{
KeyboardState keyboard = Keyboard.GetState(); // Evite isso
}

A lóg­i­ca do input per­tence ao Update, porque input altera o esta­do do jogo. O Draw ape­nas mostra esse esta­do.


⌨️ Entrada pelo teclado no MonoGame

O tecla­do é a for­ma mais sim­ples de começar.

No MonoGame, você usa:

Keyboard.GetState()

Esse méto­do retor­na um obje­to do tipo:

KeyboardState

A doc­u­men­tação ofi­cial descreve a classe Keyboard como respon­sáv­el por obter teclas pres­sion­adas do tecla­do, enquan­to KeyboardState man­tém o esta­do das teclas em deter­mi­na­do momen­to.

Exem­p­lo bási­co:

KeyboardState keyboard = Keyboard.GetState();

if (keyboard.IsKeyDown(Keys.Space))
{
// Espaço está pressionado
}

A enu­mer­ação Keys define as teclas do tecla­do disponíveis para uso no MonoGame.


🕹️ Exemplo: mover personagem com teclado

Imag­ine que você tem uma posição do jogador:

private Vector2 _playerPosition;
private float _playerSpeed = 250f;

No Initialize:

protected override void Initialize()
{
_playerPosition = new Vector2(100, 100);
base.Initialize();
}

No Update:

protected override void Update(GameTime gameTime)
{
float deltaTime = (float)gameTime.ElapsedGameTime.TotalSeconds;
KeyboardState keyboard = Keyboard.GetState();

if (keyboard.IsKeyDown(Keys.Escape))
Exit();

if (keyboard.IsKeyDown(Keys.Right))
_playerPosition.X += _playerSpeed * deltaTime;

if (keyboard.IsKeyDown(Keys.Left))
_playerPosition.X -= _playerSpeed * deltaTime;

if (keyboard.IsKeyDown(Keys.Up))
_playerPosition.Y -= _playerSpeed * deltaTime;

if (keyboard.IsKeyDown(Keys.Down))
_playerPosition.Y += _playerSpeed * deltaTime;

base.Update(gameTime);
}

Esse códi­go per­mite mover o per­son­agem usan­do as setas.

A lóg­i­ca é:

  • seta dire­i­ta aumen­ta X;
  • seta esquer­da diminui X;
  • seta para cima diminui Y;
  • seta para baixo aumen­ta Y.

Em jogos 2D, nor­mal­mente o eixo Y cresce para baixo. Por isso, subir sig­nifi­ca diminuir Y.


🧭 WASD ou setas?

Muitos jogos usam:

W = cima
A = esquerda
S = baixo
D = direita

Você pode per­mi­tir os dois for­matos:

if (keyboard.IsKeyDown(Keys.Right) || keyboard.IsKeyDown(Keys.D))
_playerPosition.X += _playerSpeed * deltaTime;

if (keyboard.IsKeyDown(Keys.Left) || keyboard.IsKeyDown(Keys.A))
_playerPosition.X -= _playerSpeed * deltaTime;

if (keyboard.IsKeyDown(Keys.Up) || keyboard.IsKeyDown(Keys.W))
_playerPosition.Y -= _playerSpeed * deltaTime;

if (keyboard.IsKeyDown(Keys.Down) || keyboard.IsKeyDown(Keys.S))
_playerPosition.Y += _playerSpeed * deltaTime;

Isso mel­ho­ra a exper­iên­cia do jogador.

Alguns pref­er­em setas. Out­ros pref­er­em WASD. Em jogos de PC, ofer­e­cer ambos é uma boa práti­ca.


⚠️ Tecla pressionada vs tecla recém-pressionada

Existe uma difer­ença impor­tante entre:

IsKeyDown

e a ideia de “aper­tou ago­ra”.

Quan­do você usa:

keyboard.IsKeyDown(Keys.Space)

isso será ver­dadeiro enquan­to a tecla estiv­er segu­ra­da.

Se você usar isso para pular, pode acon­te­cer de o per­son­agem ten­tar pular várias vezes enquan­to a tecla estiv­er pres­sion­a­da.

Para resolver, você pre­cisa com­parar o esta­do atu­al do tecla­do com o esta­do ante­ri­or.


🧠 Estado atual e estado anterior

Crie dois cam­pos:

private KeyboardState _currentKeyboard;
private KeyboardState _previousKeyboard;

No Update:

protected override void Update(GameTime gameTime)
{
_previousKeyboard = _currentKeyboard;
_currentKeyboard = Keyboard.GetState();

if (IsKeyPressed(Keys.Space))
{
// Executa apenas uma vez quando a tecla é pressionada
}

base.Update(gameTime);
}

private bool IsKeyPressed(Keys key)
{
return _currentKeyboard.IsKeyDown(key) &&
_previousKeyboard.IsKeyUp(key);
}

Ago­ra IsKeyPressed(Keys.Space) só será ver­dadeiro no frame em que a tecla acabou de ser pres­sion­a­da.

Esse con­ceito é chama­do de state track­ing between frames, ou ras­trea­men­to de esta­do entre frames. A doc­u­men­tação ofi­cial do MonoGame pos­sui um capí­tu­lo ded­i­ca­do a geren­ci­a­men­to de input, incluin­do jus­ta­mente tecla­do, mouse, gamepad e ras­trea­men­to de esta­do entre frames para cri­ar um sis­tema reuti­lizáv­el de entra­da.


🧩 Quando usar IsKeyDown e quando usar IsKeyPressed?

Use IsKeyDown para ações con­tínuas:

✅ andar;
✅ cor­rer;
✅ mirar;
✅ segu­rar escu­do;
✅ car­regar ataque;
✅ mover câmera.

Use IsKeyPressed para ações úni­cas:

✅ pular;
✅ abrir menu;
✅ pausar;
✅ con­fir­mar;
✅ ati­rar uma vez;
✅ tro­car item;
✅ ini­ciar diál­o­go.

Exem­p­lo:

if (_currentKeyboard.IsKeyDown(Keys.D))
{
// Andar enquanto segura D
}

if (IsKeyPressed(Keys.Space))
{
// Pular uma vez
}

Essa difer­ença mel­ho­ra muito a sen­sação de con­t­role.


🖱️ Entrada pelo mouse no MonoGame

O mouse é essen­cial para vários tipos de jogos:

  • estraté­gia;
  • puz­zle;
  • point-and-click;
  • con­strução;
  • menus;
  • inven­tários;
  • inter­faces;
  • jogos de tiro com mira;
  • edi­tores de fase.

No MonoGame, você usa:

Mouse.GetState()

Esse méto­do retor­na:

MouseState

A doc­u­men­tação ofi­cial descreve MouseState como uma estru­tu­ra que rep­re­sen­ta o esta­do do mouse, incluin­do posição do cur­sor e infor­mações de botões pres­sion­a­dos.

Exem­p­lo:

MouseState mouse = Mouse.GetState();

int mouseX = mouse.X;
int mouseY = mouse.Y;

📍 Pegando a posição do mouse

A posição do mouse pode ser lida assim:

MouseState mouse = Mouse.GetState();

Vector2 mousePosition = new Vector2(mouse.X, mouse.Y);

Ago­ra você pode usar essa posição para:

  • mover uma mira;
  • destacar um botão;
  • clicar em item;
  • sele­cionar per­son­agem;
  • posi­cionar obje­to;
  • arras­tar inter­face.

Exem­p­lo sim­ples:

private Vector2 _mousePosition;

protected override void Update(GameTime gameTime)
{
MouseState mouse = Mouse.GetState();

_mousePosition = new Vector2(mouse.X, mouse.Y);

base.Update(gameTime);
}

🖱️ Detectando clique do mouse

Assim como no tecla­do, você pode ver­i­ficar se um botão está pres­sion­a­do.

MouseState mouse = Mouse.GetState();

if (mouse.LeftButton == ButtonState.Pressed)
{
// Botão esquerdo está pressionado
}

Mas isso detec­ta enquan­to o botão está segu­ra­do.

Para detec­tar um clique úni­co, você pre­cisa com­parar esta­do atu­al e ante­ri­or.


🧠 Clique único com mouse

Crie cam­pos:

private MouseState _currentMouse;
private MouseState _previousMouse;

No Update:

protected override void Update(GameTime gameTime)
{
_previousMouse = _currentMouse;
_currentMouse = Mouse.GetState();

if (IsLeftClick())
{
// Clique esquerdo detectado uma vez
}

base.Update(gameTime);
}

private bool IsLeftClick()
{
return _currentMouse.LeftButton == ButtonState.Pressed &&
_previousMouse.LeftButton == ButtonState.Released;
}

Ago­ra o clique acon­tece ape­nas uma vez por pres­sion­a­men­to.

Isso é essen­cial para menus e botões.


🎯 Exemplo: botão clicável com mouse

Imag­ine um botão rep­re­sen­ta­do por um retân­gu­lo:

private Rectangle _playButton;

No Initialize:

protected override void Initialize()
{
_playButton = new Rectangle(500, 300, 280, 80);
base.Initialize();
}

No Update:

protected override void Update(GameTime gameTime)
{
_previousMouse = _currentMouse;
_currentMouse = Mouse.GetState();

Point mousePoint = new Point(_currentMouse.X, _currentMouse.Y);

if (_playButton.Contains(mousePoint) && IsLeftClick())
{
StartGame();
}

base.Update(gameTime);
}

private bool IsLeftClick()
{
return _currentMouse.LeftButton == ButtonState.Pressed &&
_previousMouse.LeftButton == ButtonState.Released;
}

private void StartGame()
{
// Troca para a cena de gameplay
}

Esse é o princí­pio de menus clicáveis.

Você ver­i­fi­ca:

  1. o mouse está sobre o botão?
  2. o jogador cli­cou?
  3. então exe­cu­ta a ação.

🧭 Hover: detectando mouse sobre objeto

Para cri­ar efeito visu­al quan­do o mouse pas­sa sobre um botão:

Point mousePoint = new Point(_currentMouse.X, _currentMouse.Y);

bool isHovering = _playButton.Contains(mousePoint);

No Draw, você pode mudar a cor:

Color buttonColor = isHovering ? Color.Yellow : Color.White;

Con­ceito:

  • Update cal­cu­la se está em hov­er;
  • Draw mostra o botão difer­ente.

Lem­bre-se:

A lóg­i­ca do hov­er fica no Update. O visu­al do hov­er fica no Draw.


🕹️ Entrada por controle/gamepad no MonoGame

O con­t­role é fun­da­men­tal para jogos com foco em sofá, platafor­mas, ação, cor­ri­da, aven­tu­ra e exper­iên­cias mais próx­i­mas de con­sole.

No MonoGame, você usa:

GamePad.GetState(PlayerIndex.One)

ou, depen­den­do da sobre­car­ga:

GamePad.GetState(0)

Isso retor­na:

GamePadState

A doc­u­men­tação ofi­cial descreve GamePadState como uma estru­tu­ra que rep­re­sen­ta infor­mações especí­fi­cas sobre o esta­do do con­t­role, incluin­do botões e analógi­cos. A classe GamePad per­mite obter o esta­do atu­al do con­t­role e tam­bém pos­sui sobre­car­gas rela­cionadas a dead zones dos analógi­cos.

Exem­p­lo:

GamePadState gamePad = GamePad.GetState(PlayerIndex.One);

if (gamePad.IsConnected)
{
// Controle conectado
}

🎮 Detectando botões do controle

Exem­p­lo:

GamePadState gamePad = GamePad.GetState(PlayerIndex.One);

if (gamePad.Buttons.A == ButtonState.Pressed)
{
// Botão A pressionado
}

if (gamePad.Buttons.B == ButtonState.Pressed)
{
// Botão B pressionado
}

Botões comuns:

A
B
X
Y
Start
Back
LeftShoulder
RightShoulder

Tam­bém existe o D‑Pad:

if (gamePad.DPad.Right == ButtonState.Pressed)
{
// Direita no D-Pad
}

🕹️ Movimento com analógico

Os analógi­cos são lidos como val­ores numéri­cos.

Exem­p­lo:

Vector2 leftStick = gamePad.ThumbSticks.Left;

Nor­mal­mente:

  • leftStick.X varia de ‑1 a 1;
  • leftStick.Y varia de ‑1 a 1.

Exem­p­lo:

_playerPosition.X += leftStick.X * _playerSpeed * deltaTime;
_playerPosition.Y -= leftStick.Y * _playerSpeed * deltaTime;

Repare no detal­he:

_playerPosition.Y -= leftStick.Y * _playerSpeed * deltaTime;

Em muitos sis­temas de jogo 2D, o eixo Y da tela cresce para baixo. Por isso, depen­den­do do con­t­role, pode ser necessário invert­er o eixo Y.


⚠️ O que é dead zone?

Dead zone é uma área mor­ta do analógi­co.

Analógi­cos físi­cos rara­mente ficam per­feita­mente em zero. Mes­mo sem tocar no con­t­role, pode haver pequenos val­ores resid­u­ais. Isso pode faz­er o per­son­agem andar soz­in­ho lenta­mente.

A doc­u­men­tação ofi­cial da classe GamePad mostra sobre­car­gas de GetState que per­mitem infor­mar o modo de dead zone usa­do nos analógi­cos.

Você pode lidar com isso man­ual­mente:

Vector2 movement = gamePad.ThumbSticks.Left;

if (movement.Length() < 0.2f)
{
movement = Vector2.Zero;
}

Depois:

_playerPosition.X += movement.X * _playerSpeed * deltaTime;
_playerPosition.Y -= movement.Y * _playerSpeed * deltaTime;

Isso evi­ta movi­men­to invol­un­tário.


🎮 Exemplo: teclado e controle juntos

Uma boa práti­ca é per­mi­tir que o jogador use tecla­do ou con­t­role.

Exem­p­lo:

protected override void Update(GameTime gameTime)
{
float deltaTime = (float)gameTime.ElapsedGameTime.TotalSeconds;

KeyboardState keyboard = Keyboard.GetState();
GamePadState gamePad = GamePad.GetState(PlayerIndex.One);

Vector2 movement = Vector2.Zero;

if (keyboard.IsKeyDown(Keys.D) || keyboard.IsKeyDown(Keys.Right))
movement.X += 1;

if (keyboard.IsKeyDown(Keys.A) || keyboard.IsKeyDown(Keys.Left))
movement.X -= 1;

if (keyboard.IsKeyDown(Keys.W) || keyboard.IsKeyDown(Keys.Up))
movement.Y -= 1;

if (keyboard.IsKeyDown(Keys.S) || keyboard.IsKeyDown(Keys.Down))
movement.Y += 1;

if (gamePad.IsConnected)
{
Vector2 stick = gamePad.ThumbSticks.Left;

if (stick.Length() > 0.2f)
{
movement.X += stick.X;
movement.Y -= stick.Y;
}
}

if (movement != Vector2.Zero)
{
movement.Normalize();
_playerPosition += movement * _playerSpeed * deltaTime;
}

base.Update(gameTime);
}

Esse exem­p­lo ensi­na várias coisas:

✅ tecla­do e con­t­role podem coex­i­s­tir;
✅ movi­men­to diag­o­nal pre­cisa ser nor­mal­iza­do;
✅ analógi­co pre­cisa de dead zone;
✅ input deve ser con­ver­tido em uma intenção de movi­men­to.


🧭 Por que normalizar o movimento diagonal?

Sem nor­mal­iza­ção, o per­son­agem pode andar mais rápi­do na diag­o­nal.

Exem­p­lo:

Direita = velocidade 1
Baixo = velocidade 1
Diagonal = combinação de duas direções

Isso pode resul­tar em veloci­dade maior.

Para cor­ri­gir:

if (movement != Vector2.Zero)
{
movement.Normalize();
}

Assim, o vetor man­tém direção, mas sua mag­ni­tude é ajus­ta­da.

Esse pequeno detal­he deixa o jogo mais jus­to e profis­sion­al.


🧱 Criando um InputManager

Con­forme o jogo cresce, não é ide­al deixar toda a leitu­ra de input den­tro do Game1.cs.

O mel­hor é cri­ar uma classe especí­fi­ca para entra­da.

Exem­p­lo:

public class InputManager
{
private KeyboardState _currentKeyboard;
private KeyboardState _previousKeyboard;

private MouseState _currentMouse;
private MouseState _previousMouse;

private GamePadState _currentGamePad;
private GamePadState _previousGamePad;

public void Update()
{
_previousKeyboard = _currentKeyboard;
_previousMouse = _currentMouse;
_previousGamePad = _currentGamePad;

_currentKeyboard = Keyboard.GetState();
_currentMouse = Mouse.GetState();
_currentGamePad = GamePad.GetState(PlayerIndex.One);
}

public bool IsKeyDown(Keys key)
{
return _currentKeyboard.IsKeyDown(key);
}

public bool IsKeyPressed(Keys key)
{
return _currentKeyboard.IsKeyDown(key) &&
_previousKeyboard.IsKeyUp(key);
}

public bool IsLeftMouseClicked()
{
return _currentMouse.LeftButton == ButtonState.Pressed &&
_previousMouse.LeftButton == ButtonState.Released;
}

public Point MousePosition
{
get { return new Point(_currentMouse.X, _currentMouse.Y); }
}

public bool IsGamePadButtonPressed(Buttons button)
{
return _currentGamePad.IsButtonDown(button) &&
_previousGamePad.IsButtonUp(button);
}

public Vector2 GetMovementVector()
{
Vector2 movement = Vector2.Zero;

if (IsKeyDown(Keys.D) || IsKeyDown(Keys.Right))
movement.X += 1;

if (IsKeyDown(Keys.A) || IsKeyDown(Keys.Left))
movement.X -= 1;

if (IsKeyDown(Keys.W) || IsKeyDown(Keys.Up))
movement.Y -= 1;

if (IsKeyDown(Keys.S) || IsKeyDown(Keys.Down))
movement.Y += 1;

if (_currentGamePad.IsConnected)
{
Vector2 stick = _currentGamePad.ThumbSticks.Left;

if (stick.Length() > 0.2f)
{
movement.X += stick.X;
movement.Y -= stick.Y;
}
}

if (movement != Vector2.Zero)
movement.Normalize();

return movement;
}
}

Ago­ra, no Game1.cs:

private InputManager _input;

protected override void Initialize()
{
_input = new InputManager();
base.Initialize();
}

protected override void Update(GameTime gameTime)
{
_input.Update();

if (_input.IsKeyPressed(Keys.Escape))
Exit();

Vector2 movement = _input.GetMovementVector();
_playerPosition += movement * _playerSpeed *
(float)gameTime.ElapsedGameTime.TotalSeconds;

base.Update(gameTime);
}

Esse tipo de orga­ni­za­ção deixa o pro­je­to muito mais limpo.


🎯 Mapeando ações em vez de teclas

Um erro comum é espal­har teclas pelo códi­go inteiro.

Exem­p­lo ruim:

if (keyboard.IsKeyDown(Keys.Space))
{
Jump();
}

Isso parece sim­ples, mas se você quis­er mudar o botão de pulo depois, terá que procu­rar em vários arquiv­os.

Uma abor­dagem mel­hor é pen­sar em ações:

MoveLeft
MoveRight
MoveUp
MoveDown
Jump
Attack
Pause
Confirm
Cancel

Então seu jogo não per­gun­ta:

“A tecla espaço foi pres­sion­a­da?”

Ele per­gun­ta:

“A ação de pular foi aciona­da?”

Exem­p­lo:

public bool IsJumpPressed()
{
return IsKeyPressed(Keys.Space) ||
IsGamePadButtonPressed(Buttons.A);
}

Ago­ra o jogo usa:

if (_input.IsJumpPressed())
{
_player.Jump();
}

Isso é muito mais profis­sion­al.


🧠 Vantagens de mapear ações

Mapear ações traz várias van­ta­gens:

✅ facili­ta tro­car con­troles;
✅ per­mite suporte a tecla­do e con­t­role;
✅ deixa o códi­go mais legív­el;
✅ aju­da a cri­ar tela de con­fig­u­ração;
✅ reduz repetição;
✅ mel­ho­ra manutenção;
✅ sep­a­ra regra de jogo de dis­pos­i­ti­vo físi­co.

Em vez de o jogador ser con­tro­la­do por teclas, ele é con­tro­la­do por intenções.

Isso é arquite­tu­ra de jogo mais madu­ra.


🧩 Exemplo de InputManager com ações

public bool IsPausePressed()
{
return IsKeyPressed(Keys.Escape) ||
IsKeyPressed(Keys.P) ||
IsGamePadButtonPressed(Buttons.Start);
}

public bool IsConfirmPressed()
{
return IsKeyPressed(Keys.Enter) ||
IsKeyPressed(Keys.Space) ||
IsGamePadButtonPressed(Buttons.A);
}

public bool IsCancelPressed()
{
return IsKeyPressed(Keys.Escape) ||
IsGamePadButtonPressed(Buttons.B);
}

public bool IsAttackPressed()
{
return IsKeyPressed(Keys.J) ||
IsGamePadButtonPressed(Buttons.X);
}

Ago­ra seu jogo pode faz­er:

if (_input.IsPausePressed())
{
TogglePause();
}

if (_input.IsAttackPressed())
{
_player.Attack();
}

Esse padrão facili­ta muito a evolução.


🧱 Input em menus

Menus pre­cisam de input difer­ente do game­play.

Durante o game­play, as teclas movem o per­son­agem.

No menu, as teclas naveg­am entre opções.

Exem­p­lo:

if (_input.IsKeyPressed(Keys.Down))
{
_selectedMenuIndex++;
}

if (_input.IsKeyPressed(Keys.Up))
{
_selectedMenuIndex--;
}

if (_input.IsConfirmPressed())
{
ExecuteMenuOption();
}

Con­t­role:

if (_input.IsGamePadButtonPressed(Buttons.DPadDown))
{
_selectedMenuIndex++;
}

if (_input.IsGamePadButtonPressed(Buttons.DPadUp))
{
_selectedMenuIndex--;
}

Aqui, IsKeyPressed é mel­hor do que IsKeyDown, porque você não quer que o menu desça dez opções com um úni­co toque segu­ra­do.


⏱️ Repetição controlada em menu

Em alguns jogos, se o jogador segu­ra a tecla, o menu começa a repe­tir depois de um pequeno atra­so.

Para ini­ciantes, o ide­al é começar com clique úni­co:

if (_input.IsKeyPressed(Keys.Down))
{
MoveSelectionDown();
}

Depois, em pro­je­tos mais avança­dos, você pode cri­ar um sis­tema de repetição com timer:

private double _repeatTimer;
private double _repeatDelay = 0.25;

Mas no começo, man­ten­ha sim­ples.


🖱️ Input em botões de interface

Menus com mouse geral­mente usam retân­gu­los.

Classe sim­ples:

public class Button
{
public Rectangle Bounds { get; set; }
public string Text { get; set; }
public bool IsHovered { get; private set; }

public Button(Rectangle bounds, string text)
{
Bounds = bounds;
Text = text;
}

public bool Update(InputManager input)
{
IsHovered = Bounds.Contains(input.MousePosition);

return IsHovered && input.IsLeftMouseClicked();
}
}

Uso:

if (_playButton.Update(_input))
{
StartGame();
}

Ago­ra o botão sabe se o mouse está sobre ele e se foi cli­ca­do.


🎮 Input e cenas do jogo

Quan­do você começar a tra­bal­har com cenas, cada cena pode tratar input de for­ma difer­ente.

Exem­p­lo:

MenuScene
GameScene
PauseScene
GameOverScene

Cada uma pode ter seu próprio méto­do:

public void Update(GameTime gameTime, InputManager input)
{
// Input específico da cena
}

No menu:

if (input.IsConfirmPressed())
{
StartGame();
}

No game­play:

Vector2 movement = input.GetMovementVector();
_player.Move(movement);

No pause:

if (input.IsPausePressed())
{
ResumeGame();
}

Esse mod­e­lo deixa o pro­je­to muito mais orga­ni­za­do.


🚀 Input responsivo: o que faz um controle parecer bom?

Input não é ape­nas “fun­cionar”.

Input pre­cisa pare­cer bom.

Um jogo com input ruim parece trava­do, atrasa­do ou injus­to.

Boas práti­cas:

✅ leia input no iní­cio do Update;
✅ evite atra­sos desnecessários;
✅ difer­en­cie tecla segu­ra­da de tecla pres­sion­a­da;
✅ nor­mal­ize movi­men­to diag­o­nal;
✅ trate dead zone do analógi­co;
✅ per­mi­ta tecla­do e con­t­role quan­do fiz­er sen­ti­do;
✅ use ações em vez de teclas espal­hadas;
✅ teste com difer­entes dis­pos­i­tivos;
✅ faça menus respon­derem com clareza;
✅ dê feed­back visu­al e sonoro.

Um bom input é quase invisív­el. O jogador só percebe quan­do está ruim.


🧪 Exercício prático: personagem com teclado e controle

Crie estes cam­pos:

private InputManager _input;
private Vector2 _playerPosition;
private float _playerSpeed = 250f;

No Initialize:

protected override void Initialize()
{
_input = new InputManager();
_playerPosition = new Vector2(100, 100);

base.Initialize();
}

No Update:

protected override void Update(GameTime gameTime)
{
_input.Update();

if (_input.IsPausePressed())
{
// Pausar ou sair
}

float deltaTime = (float)gameTime.ElapsedGameTime.TotalSeconds;

Vector2 movement = _input.GetMovementVector();

_playerPosition += movement * _playerSpeed * deltaTime;

base.Update(gameTime);
}

No Draw, você desen­ha nor­mal­mente:

protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);

_spriteBatch.Begin();
_spriteBatch.Draw(_playerTexture, _playerPosition, Color.White);
_spriteBatch.End();

base.Draw(gameTime);
}

Esse exer­cí­cio cria uma base sól­i­da para prati­ca­mente qual­quer jogo 2D.


⚠️ Erros comuns com input no MonoGame

1. Ler input no Draw

Evite. Input altera lóg­i­ca, então per­tence ao Update.

2. Usar IsKeyDown para tudo

Para ações úni­cas, use com­para­ção entre esta­do atu­al e ante­ri­or.

3. Não tratar clique único

Sem con­t­role de esta­do ante­ri­or, o clique pode dis­parar várias vezes.

4. Não normalizar movimento diagonal

O per­son­agem pode ficar mais rápi­do na diag­o­nal.

5. Ignorar dead zone do controle

O per­son­agem pode se mover soz­in­ho.

6. Espalhar teclas pelo código inteiro

Pre­fi­ra mapear ações.

7. Criar um InputManager tarde demais

Quan­to antes orga­ni­zar input, mel­hor.

8. Não testar com controle real

Con­t­role físi­co pode ter com­por­ta­men­to difer­ente do esper­a­do.

9. Não dar feedback ao jogador

Botões pre­cisam mudar visual­mente quan­do sele­ciona­dos ou cli­ca­dos.

10. Misturar input de menu com input de gameplay

Cada esta­do do jogo deve inter­pre­tar input de for­ma ade­qua­da.


📊 Tabela prática: tipos de input

Situ­açãoMel­hor abor­dagem
Movi­men­to con­tín­uoIsKeyDown / analógi­co
Pulotecla recém-pres­sion­a­da
Ataque úni­cobotão recém-pres­sion­a­do
Tiro automáti­cobotão segu­ra­do com timer
Menutecla recém-pres­sion­a­da
Botão clicáv­elmouse sobre retân­gu­lo + clique
Pausaação mapea­da
Con­t­role analógi­codead zone + nor­mal­iza­ção
Diag­o­nalnor­malizar vetor
Mul­ti­dis­pos­i­ti­voInput­Man­ag­er

🧠 Arquitetura recomendada para input

Uma estru­tu­ra profis­sion­al pode ficar assim:

MeuJogo/
├── Core/
│ ├── InputManager.cs
│ ├── GameState.cs
│ └── SceneManager.cs
├── Entities/
│ └── Player.cs
├── Scenes/
│ ├── MenuScene.cs
│ ├── GameScene.cs
│ └── PauseScene.cs
├── UI/
│ └── Button.cs
├── Game1.cs
└── Program.cs

O Game1.cs não pre­cisa saber detal­h­es de cada tecla.

Ele ape­nas atu­al­iza o input:

_input.Update();

E pas­sa para as cenas:

_currentScene.Update(gameTime, _input);

Isso cria uma base muito mais escaláv­el.


🧩 Input e acessibilidade

Mes­mo em jogos pequenos, vale pen­sar em aces­si­bil­i­dade.

Boas ideias:

✅ per­mi­tir tecla­do e con­t­role;
✅ aceitar WASD e setas;
✅ evi­tar depen­der de uma úni­ca tecla descon­fortáv­el;
✅ per­mi­tir rema­pea­men­to futu­ra­mente;
✅ dar feed­back visu­al em menus;
✅ não exi­gir reflex­os extremos sem neces­si­dade;
✅ per­mi­tir pausa;
✅ cri­ar coman­dos con­sis­tentes.

Aces­si­bil­i­dade não é ape­nas recur­so avança­do. É respeito ao jogador.


🎯 Input e sensação de jogo

Dois jogos podem ter a mes­ma mecâni­ca, mas sen­sações com­ple­ta­mente difer­entes por causa do input.

Um per­son­agem pode pare­cer:

  • pesa­do;
  • leve;
  • escor­re­ga­dio;
  • pre­ciso;
  • trava­do;
  • rápi­do;
  • respon­si­vo;
  • lento.

Isso depende de fatores como:

  • veloci­dade;
  • acel­er­ação;
  • desacel­er­ação;
  • tem­po de respos­ta;
  • ani­mação;
  • som;
  • col­isão;
  • feed­back visu­al.

Neste capí­tu­lo, o foco é cap­turar input. Nos próx­i­mos, esse input será com­bi­na­do com movi­men­tação, col­isão, físi­ca sim­ples e ani­mação para cri­ar sen­sação de jogo real.


✅ Checklist do Capítulo 5

Ao final deste capí­tu­lo, você deve enten­der:

✅ o que é entra­da do jogador;
✅ por que input deve ser lido no Update;
✅ como usar Keyboard.GetState;
✅ o que é KeyboardState;
✅ como usar Mouse.GetState;
✅ o que é MouseState;
✅ como ler posição do mouse;
✅ como detec­tar clique úni­co;
✅ como usar GamePad.GetState;
✅ o que é GamePadState;
✅ como ler botões do con­t­role;
✅ como ler analógi­co;
✅ o que é dead zone;
✅ por que nor­malizar movi­men­to diag­o­nal;
✅ como cri­ar um InputManager;
✅ por que mapear ações em vez de teclas;
✅ como aplicar input em menus;
✅ como aplicar input em game­play;
✅ quais erros evi­tar.


🏁 Conclusão: input é a ponte entre jogador e mundo do jogo

Entra­da do jogador é muito mais do que detec­tar tecla aper­ta­da.

É a ponte entre a intenção humana e o mun­do vir­tu­al.

Quan­do o jogador aper­ta uma tecla, cli­ca com o mouse ou move um analógi­co, ele espera que o jogo respon­da de for­ma clara, ráp­i­da e jus­ta. Se essa respos­ta fal­ha, a exper­iên­cia inteira perde força.

No MonoGame, o input é dire­to e poderoso. Você lê o esta­do do tecla­do com KeyboardState, do mouse com MouseState e do con­t­role com GamePadState. A par­tir dis­so, cria ações, movi­men­tos, menus, cliques, con­fir­mações, ataques, pulos e inter­ações.

Mas o salto profis­sion­al acon­tece quan­do você deixa de espal­har teclas pelo códi­go e começa a pen­sar em ações:

mover, pular, atacar, pausar, con­fir­mar, can­ce­lar.

Essa men­tal­i­dade trans­for­ma input em arquite­tu­ra.

A par­tir daqui, seu jogo não ape­nas aparece na tela. Ele responde.

No próx­i­mo capí­tu­lo, essa respos­ta gan­hará con­se­quên­cia físi­ca: col­isão, movi­men­tação, lim­ites, gravi­dade sim­ples e inter­ação entre obje­tos.

Tecla­do, mouse e con­t­role são os instru­men­tos. O Input­Man­ag­er é a par­ti­tu­ra. O jogador é quem dá vida ao jogo.


❓ FAQ — Entrada do Jogador no MonoGame

1. Como ler teclado no MonoGame?

Use Keyboard.GetState() para obter um KeyboardState. Essa estru­tu­ra man­tém o esta­do das teclas do tecla­do no momen­to da leitu­ra.

2. Como saber se uma tecla está pressionada?

Use:

KeyboardState keyboard = Keyboard.GetState();

if (keyboard.IsKeyDown(Keys.Space))
{
// Espaço pressionado
}

3. Qual a diferença entre tecla pressionada e tecla recém-pressionada?

Tecla pres­sion­a­da fica ver­dadeira enquan­to o jogador segu­ra a tecla. Tecla recém-pres­sion­a­da exige com­parar o esta­do atu­al com o esta­do ante­ri­or para dis­parar ape­nas uma vez.

4. Como ler mouse no MonoGame?

Use Mouse.GetState() para obter um MouseState, que rep­re­sen­ta posição do cur­sor e esta­do dos botões do mouse.

5. Como detectar clique único do mouse?

Com­pare o esta­do atu­al e ante­ri­or:

_currentMouse.LeftButton == ButtonState.Pressed &&
_previousMouse.LeftButton == ButtonState.Released

6. Como ler controle no MonoGame?

Use GamePad.GetState(PlayerIndex.One) para obter um GamePadState, que rep­re­sen­ta botões, analógi­cos e esta­do do con­t­role.

7. O que é dead zone?

Dead zone é uma área mor­ta do analógi­co usa­da para igno­rar pequenos movi­men­tos invol­un­tários. A API de GamePad.GetState pos­sui sobre­car­gas rela­cionadas a mod­os de dead zone.

8. Por que meu personagem anda mais rápido na diagonal?

Porque o vetor diag­o­nal com­bi­na dois eixos. Para cor­ri­gir, nor­mal­ize o vetor de movi­men­to antes de aplicar veloci­dade.

9. Preciso criar um InputManager?

Não é obri­gatório no começo, mas é alta­mente recomen­da­do quan­do o pro­je­to cresce. Ele cen­tral­iza tecla­do, mouse, con­t­role e ações do jogador.

10. Qual frase resume este capítulo?

Input trans­for­ma intenção em ação.

Capí­tu­lo 1 — O que é MonoGame e por que usar para cri­ar jogos

Capí­tu­lo 2 — Preparan­do o Ambi­ente de Desen­volvi­men­to

Capí­tu­lo 3 — Fun­da­men­tos do Game Loop: Update e Draw

Capí­tu­lo 4 — Sprites, Tex­turas e Con­tent Pipeline

Capí­tu­lo 5 — Entra­da do Jogador: Tecla­do, Mouse e Con­t­role

Capí­tu­lo 6 — Col­isão, Físi­ca Sim­ples e Movi­men­tação

Capí­tu­lo 7 — Cenas, Menus e Arquite­tu­ra do Jogo

Capí­tu­lo 8 — Áudio, Partícu­las, Ani­mações e Poli­men­to

Capí­tu­lo 9 — Shaders, Câmera, Mapas e Per­for­mance

Capí­tu­lo 10 — Pub­li­cação, Mon­e­ti­za­ção e Pro­je­to Final no MonoGame

Posts Similares

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *