Jump to content
Yamix

Bug no buffer do teclado após uso do delay

Recommended Posts

Yamix

Olá,

Estava desenvolvendo um jogo no estilo, "Reaction Time Test".

Quando, me deparei com o seguinte problema:

- Se o jogador apertasse alguma tecla durante o delay, então, após a saída do delay, imediatamente era contado como se o jogador tivesse pressionado uma tecla. Ou seja, seu tempo de reação era de 0.000 segundos, burlando o jogo.

Nesse momento, meu código estava assim:

Program ReactionTimeTest;
 Uses Crt;
 
 Const
       Sec = 600000;
 
 Var 
     Tempo: Double;
     Contador: LongInt;
 
Begin
	   Repeat
	          Tempo := 0;	  	
	          Contador := 0;
	
	          Delay(Random(3000 - 1500) + 1500);	  
	          WriteLn('VAI!');
	  
	          While (KeyPressed = False) Do
	          Begin 
	  	            Contador := Contador + 1;
	          End;
	  	      
	          Tempo := Contador / Sec;	  
	          WriteLn('TEMPO: ', Tempo:0:3, 's.');
      Until (False);
End.

Então pensei, isso é simples de se resolver, e cheguei nisso:

Program ReactionTimeTest;
 Uses Crt;
 
 Const
       Sec = 600000;
 
 Var 
     Tempo: Double;
     Contador: LongInt;
 
Begin
	  Repeat
	         Tempo := 0;	  	
	         Contador := 0;
	
	         Delay(Random(3000 - 1500) + 1500);	  
	         WriteLn('VAI!');
	  
	         If (KeyPressed = False) Then
	         Begin		
	               While (KeyPressed = False) Do
	               Begin 
	  	               Contador := Contador + 1;
	               End;
	  	      
	               Tempo := Contador / Sec;	  
	               WriteLn('TEMPO: ', Tempo:0:3, 's.');
	         End
	             Else
	                  ReadKey();
	  Until (False);
End.

Agora vai dar tudo certo!

- SÓ QUE NÃO.. 

O bug ainda existia só que pior, o programa ficava repetindo o delay, até o número de vezes que apertei alguma tecla..

Depois de algum tempo tentando cheguei nessa solução,

Repeat
	   Erro := False;
	                               
	   If (KeyPressed = True) Then
	   Begin
	         ReadKey();
	         Erro := True;	                               	  	                               	  
	   End;
	                               
	   Delay(10);	                               	                               	                               	                               
Until (Erro = False);

SOLUÇÃO:  Ler todas as teclas pressionadas até esvaziar o buffer do teclado.

A criação deste tópico, foi apenas para compartilhar a minha solução(não sei se existe outra) de como resolver o bug do delay. 

Edited by Yamix

Share this post


Link to post
Share on other sites
BHAMF

Não entendi bem a solução, podes explicar melhor? Sempre tive essa dúvida também


Brenio Hallison A.M. Filho

 

Share this post


Link to post
Share on other sites
Yamix

Beleza!

O que acontece é que quando você usa o Delay, por um determinado tempo, o programa "congela" . Entretanto, mesmo com o programa "congelado", o teclado ainda fica ativo.

Bem, isso não é exatamente um problema, a menos que você queira usar a função KeyPressed().

Quando você aperta um monte de tecla durante o Delay, fará com que KeyPressed seja TRUE, exatamente o número de teclas apertadas!

- Boom!

Ao notar isso, ficou fácil saber o que deveria ser feito. 

Dando um exemplo,

Lembrando que: Para cada KeyPressed é necessário haver um ReadKey, para resetar o KeyPressed de volta ao padrão.

Program Teste;
 Uses Crt;
 
 Var Cont: Byte;
 
Begin
	  Cont := 0;
	  
	  WriteLn('GO!');
      
      // Suponha que durante o Delay, eu tenha apertado 3 teclas qualquer	  
      Delay(2000); 
      
      // Apesar de ser apenas um KeyPressed, seria como se o programa criasse
      // varios outros KeyPressed's fantasmas.
      // Entao, para cada KeyPressed deve haver obrigatoriamente um ReadKey. 
      // Ou seja,
      
      If (KeyPressed = True) Then
      Begin      
             Repeat
                    Inc(Cont);
                    
                    ReadKey(); // Reseta cada KeyPressed                
             Until (KeyPressed = False);
      End;
                
      WriteLn('TECLAS APERTADAS DURANTE O DELAY: ', Cont);	
End.

Espero que tenha entendido :D:D

Edited by Yamix

Share this post


Link to post
Share on other sites
thoga31

Esta questão é interessante e essa é uma das formas de limpar o buffer.

Só queria, no entanto, apontar para o facto de isto não ser um bug do buffer. É precisamente o comportamento esperado e com o qual temos de lidar em casos como este.

Cumprimentos.


Knowledge is free!

Share this post


Link to post
Share on other sites
passarito

@Yamix a tua solução está correta, mas por vezes menos é mais, por isso vou deixar-te aqui a minha visão de uma optimização da tua solução.

Onde tens:

If (KeyPressed = True) Then
	Begin      
    	Repeat
			Inc(Cont);
		    ReadKey(); // Reseta cada KeyPressed                
		Until (KeyPressed = False);
	End;

eu optava por:

While KeyPressed do begin
	Inc(Cont);
	ReadKey();
end;

Faz a mesma coisa mas é mais perceptível.

Mas claro, isto é só uma sugestão.

Edited by passarito

Share this post


Link to post
Share on other sites
Yamix

Hahah, não tinha notado.. falha minha, obrigado @passarito.

Optimizações são sempre bem vindas! 

(Parando para pensar, estou fazendo isso toda hora. Estou viciado no "repeat..until".. :P:P)

Edit: Para quem se interessa, fiz um vídeo simples, mostrando a construção do jogo, dito lá em cima. Na descrição do vídeo, possui um link com o código já indentado e bem explicado, é só dar CTRL + C CTRL + V.

 

 

Edited by Yamix

Share this post


Link to post
Share on other sites
passarito

Há pessoas viciadas no Repeat...Until (eu já fui uma delas) e há pessoas viciadas no While.

Essencialmente, tens de pensar onde é que necessitas de fazer o primeiro teste, se antes ou depois do ciclo. Se necessitas antes usas o While, se necessitas depois usas o Repeat.

Mais fácil de veres isto é olhares para o teu código. Se necessitares de fazer um If antes do Repeat então a melhor opção é usar o While ;)

Share this post


Link to post
Share on other sites
BHAMF

Estou testando aqui tal método...

Edited by BHAMF

Brenio Hallison A.M. Filho

 

Share this post


Link to post
Share on other sites
BHAMF

Então, tenho um programa que usa muito Delay. Praticamente há mais de 50 no programa inteiro. Então, resolvi fazer isto: 

procedure endBuff;
var
 Count : integer;
begin
 if (keypressed = true) then begin
 repeat
  inc(Count);
  readkey();
  until(keypressed = false);
 end;
end;
procedure delay(tempo:integer);
begin
  delay(tempo);
  endBuff;
end;

porém, ao iniciar o programa (que há um delay, aliás), o programa simplesmente fecha. Explicações?


Brenio Hallison A.M. Filho

 

Share this post


Link to post
Share on other sites
BHAMF
5 minutos atrás, BHAMF disse:

Então, tenho um programa que usa muito Delay. Praticamente há mais de 50 no programa inteiro. Então, resolvi fazer isto: 


procedure endBuff;
var
 Count : integer;
begin
 if (keypressed = true) then begin
 repeat
  inc(Count);
  readkey();
  until(keypressed = false);
 end;
end;
procedure delay(tempo:integer);
begin
  delay(tempo);
  endBuff;
end;

porém, ao iniciar o programa (que há um delay, aliás), o programa simplesmente fecha. Explicações?

Resolvi o erro pondo o delay original, mas com o endBuff embaixo, sem chamar dentro da procedure delay(tempo:integer);

procedure endBuff;
var
 Count : integer;
begin
 if (keypressed = true) then begin
 repeat
  inc(Count);
  readkey();
  until(keypressed = false);
 end;
end;

[...]
 delay(100);
 endBuff;
[...]

//isto resolveu o problema, mas não entendo porquê colocar os dois numa procedure só, não funciona... Explicações?

 

Edited by BHAMF

Brenio Hallison A.M. Filho

 

Share this post


Link to post
Share on other sites
Yamix

O método é só: 

While (KeyPressed) Do ReadKey();

Então, deveria ficar assim:

Program Teste;
 Uses Crt;
 
 Procedure Delay(Tempo: Integer);  
 Begin
 	  Crt.Delay(Tempo);
       While (KeyPressed) Do ReadKey(); // seu Endbuff
 End;
 
Begin
 [...]

Conserta aí :P

Edited by Yamix

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×
×
  • Create New...

Important Information

By using this site you accept our Terms of Use and Privacy Policy. We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.