Problema con un getch() indisciplinado

Iniciado por SCUMM, 27 Enero 2014, 19:38 PM

0 Miembros y 1 Visitante están viendo este tema.

SCUMM

Buenas, resulta que he hecho un pequeño videojuego para clase de programación
y parece que no quiere funcionar, el videojuego es muy simple, aparece una pantalla con dos vaqueros y cuando suena la campana cada jugador pulsa la tecla de la acción que quiere realizar.
En base a lo que haya hecho cada uno el resultado es diferente.
He aquí la parte conflictiva de mi código:

    do
    {
        system("cls");
        bool fin=false;
        char accionpri;
        char accionse;
        unsigned tiempo=0;
        ImprimirDuelo(vaqueroa,vaquerob);
        tiempo=rand() % 5;
        Sleep(tiempo*1000);
        Beep(440, 900);
        fflush(stdin);
        fflush(stdout);
        accionpri=getch();
        accionse=getch();
        victoria=ResolverDuelo(accionpri,accionse);
        Sleep(3000);
    }while(victoria==0);

El problema es que los getch deberían capturar las acciones del primer y segundo jugador después de que suene la campana, sin embargo se puede introducir accionpri y accionse antes.
¿Alguna idea de como solucionarlo?Muchas gracias.

vangodp

#1
No se si funciona por que el código esta a medias.
Pero no deberías declarar variables en un bucle creo. Estarías declarando varias variables con el mismo nombre lo que no puede ser, lo que si puedes hacer es declarar antes y cambiar el valor tantas veces como quieras dentro.
Sobre el getch no puedo decirte si funciona o no(código incompleto), pero creo que el problema puede ser el de arriba.
Código (cpp) [Seleccionar]

#include <iostream>
using namespace std;

int main () {
   //declarar las variables fuera del bucle.
   bool fin=false;
   char accionpri;
   char accionse;
   unsigned tiempo=0;
   int tiempo = 0;
   
   do {
       system("cls");
       // Aqui las vuelve a asignar los valores necesarios a las varibles si te hace falta
       fin=false;
       tiempo=0;
       ImprimirDuelo(vaqueroa,vaquerob);
       tiempo=rand() % 5;
       Sleep(tiempo*1000);
       Beep(440, 900);
       fflush(stdin);
       fflush(stdout);
       accionpri=getch();
       accionse=getch();
       victoria=ResolverDuelo(accionpri,accionse);
       Sleep(3000);
   } while(victoria==0);

   cin.ignore();
   return 0;
}

SCUMM

la verdad es que moví un par de cosas para no poner todo el tocho de código en el post y no caí en que estaba metiendo la declaración de variables dentro del bucle
(a mas de uno le ha tenido que dar un ictus).

El problema es que el getch() no se activa despues de que suene el Beep sino que recibe el imput que se le haya estado metiendo antes (si hay algun tramposo que no respete el Beep) Me ha dicho un amigo que tengo que hacerlo con un evento pero la verdad es que no se como implementarlo (aparte de que la solución ideal sería la mas simple).
¡Por cierto!¡Muchas gracias por responder!

vangodp

#3
hice este a ver si te sirve.
Juegas con la a y la l, lo cambias si no te gusta :D
Tiene partes de cpp pero lo puedes cambiar para c sin problemas.

Código (cpp) [Seleccionar]

#include <iostream>
#include <stdio.h>
#include <conio.h>
#include <windows.h>
using namespace std;

int main () {
   char victory = '0';
   char play = '0';
   int fin = 0;
   do {
       system ("cls");
       play    = '0';
       victory = '0';     //ponemos a 0 para no haber trampas
       fflush(stdin);
       fflush(stdout);
       // teclas para jugar a y b minusculas =D, a = jugador 1 : b = jugador 2
       // aqui el beep        
       victory = getch();
       Sleep (50);
       switch (victory) {
           case 'a':
               cout << "player 1 vence!" << endl; // llamar funcion para player uno vencedor
               break;
           case 'l':
               cout << "player 2 vence!" << endl; // llamar funcion para player dos vencedor
               break;
           default:
               cout << "tecla no correcta!";
               break;
       }//FIN SWITCH

       cout << "Terminar? s/n" << endl;  // Seguir jugando n = salir cualquier otra tecla continua ;)
       scanf ("%c", &play );
       fin = (( play == 'n' ) ? 1 : 0  );
   } while( !fin );


   cin.ignore();
   return 0;
}



SCUMM

Aquí explico la mecánica del juego:
Código (cpp) [Seleccionar]

void Instrucciones()
{   
    system("cls");
    cout<<"Bang es un juego de duelos de vaqueros en el viejo oeste para dos jugadores."<<endl<<endl;
    cout<<"Cuando empieza la partida un jugador tomara el control de el               "<<endl;
    cout<<"primer vaquero controlado con los botones a,s,d, el otro controlara con los"<<endl;
    cout<<"botones b,n,m al segundo vaquero, El objetivo es matar al otro en un duelo!"<<endl<<endl;
    cout<<"              |Vaquero 1|Vaquero 2|                                        "<<endl;
    cout<<"    Disparar  |    a    |    b    |                                        "<<endl;
    cout<<"    Recargar  |    s    |    n    |                                        "<<endl;
    cout<<"    Esquivar  |    d    |    m    |                                        "<<endl<<endl;
    cout<<"Cuando suena la campana cada vaquero hace su accion, disparar, recargar    "<<endl;
    cout<<" (hasta un maximo de tres balas) o esquivar(esta accion te puede salvar    "<<endl;
    cout<<"de la muerte) En caso de que los dos vaqueros disparen a la vez, el mas    "<<endl;
    cout<<"rapido de los gana.                                                        "<<endl<<endl<<endl<<endl<<endl;
    system("pause");
}


Con el primer vistazo me pareció un juego muy simple de hacer, pero los problemas con el ghosting y el getch() disparandose antes del Beep la cosa se complica bastante

SCUMM

#5
Por cierto el tema del ghosting y el blocking es muy interesante ahora que lo mencionas, ya que la rapidez de cada jugador influye mucho en quien gana, tal vez se podría hacer que uno de los jugadores disparara con el ratón o con un joystick, así nos quitaríamos el problema de la disposición de las teclas en serie en la circuitería del teclado.
Esta solución tengo que admitir que es muy cutre pero, todo sea por quitarme este maldito trabajo de encim.

BlackM4ster

Si no he entendido mal, realmente tiene que esperar a la pulsacion de 2 teclas (1 para cada jugador) y procesarlas, para saber quien ha ganado, no?
- Pásate por mi web -
https://codeisc.com

vangodp

Si! así es black master.
La cosa es que incito a que haga unas pruebas con tu teclado.
Veras que cuando pulsas ambas al mismo tiempo y no hay que ser muy exacto siempre sale el mismo resultado eso es así por que imagine que tienes un cable con dos polos, positivo y negativo.
Bien ahora en ese cable añades interruptores.
Cual crees que va funcionar?El primer siempre.
Ya que para que funcione el segundo, el primer debe estar sin pulsar.
Eso es así por que los teclados fueron concebidos para eso(Una tecla a la vez), y funciona muy bien para su fin(No nos quejamos ¿No?).
Pero la cosa cambia con lo que el quiere hacer.
Como el juego que el quiere necesita respuestas muy altas y precisas, por mas que quieras nunca podemos pulsar 2 teclas a la vez, siempre tendría una diferencia de milésimas o ínfimas, pero casi imposible pulsar las 2 juntas(no somos maquinas :D).
Lo que comenta el no es mala idea: usar 2 dispositivos.
O uno que sea especifico para eso, dicen no lo se, que el puerto de serie/paralelo que antes se usaba para las impresoras no tiene este problema, pero desconozco si es correcto por que nunca lo probé.
Existen dispositivos como este que solucionan el problema:

Estan echos para construir algo como eso:

http://www.dndw.com/arcadeaddiction/controlpanel4.htm
El problema que tiene aparte de el que comentas(programacion).
Es también la respuesta del dispositivo.
Teclado no es un dispositivo para juego, por eso su problema.
Para una sola persona el teclado funciona muy bien, pero cuando se junta 2 o mas la cosa cambia.
¿Has intentado pulsar 6 o mas teclas juntas? Haz un programa que capture strings, y pulsa varias teclas juntas, si logra capturar todas veras que el orden se va repetir muchas veces.
Si pulsas 2 juntas te va salir siempre una primero.
En fin, no es que sea un problema del teclado ya que para eso lo crearon, es que no le va a ir bien ni que hagas el mejor programa.
Tiene que hacer pruebas por que cada teclado lo diseñan de una manera, o usar 2 dispositivos como 2 teclados o un teclado y un mando, o destripar su teclado a ver que botones van en diferentes lineas si es que lo hacen, y si al pulsar va funcionar de manera correcta.
Todo una serie de problemas resolver.
Estuve un tiempo pensando en hacerme una recreativa de estas. ^^
Sueño de infancia.  :xD
La cosa es que no creo que el amigo quiera gastar dinero ya que es un trabajo de sus estudios o yo que se. Pero todos tenemos un par de teclados viejos al cual le podemos dar uso para cosillas como esta.
Suerte!

BlackM4ster

Si, tienes toda la razón, la limitación aqui es el hardware del teclado, pero como bien has dicho, no somos máquinas y, por lo tanto, nunca podremos apretar dos teclas a la vez, con lo cual, yo no veo problemas a la hora de crear el programa.

Con un código que detecte dos teclas, no debería haber problemas. Un ejemplo que he usado para hacer pruebas xD

Código (cpp) [Seleccionar]
#include <iostream>
#include <conio.h>

int main(){

int A, B;

A = getch();
B = getch();

std::cout << A << ", " << B;

getch();
}
- Pásate por mi web -
https://codeisc.com

SCUMM

El problema era que el programa hacía sonar una campana para avisar a los jugadores de pulsar un botón (Como un preparados, listos, ya) sin embargo si uno de los jugadores pulsaba su boton antes de la campana, el programa lo daba por bueno y, por ejemplo si el jugador uno pulsaba disparar antes de la campana, mataba al otro (haciendo trampas)
Al final lo he solucionado poniendo un game loop que "getchea" todas las acciones de los jugadores antes de la campana y las descarta.
--si considerais que esto es spam borrad el comentario sin problemas, pero quería decir dentro de poco hay una competición para desarolladores de videojuegos, si os interesa pasaos por la sección de Juegos del foro--