From the monthly archives:

August 2009

En este post se va a tratar el movimiento de los jugadores usando BASIC para experimentar la velocidad y ver si se continua con este lenguaje o bien se hace la programación en ensamblador.

El programa en BASIC

Se corre el juego sin ningún problema en alta velocidad:

10 POKE 65495,0

Se inicializa la interfaz en serie, como se vio en el post anterior:

50 REM CONFIGURACION INICIAL DE LA CONEXION EN SERIE
60 POKE 65387,30
70 POKE 65386,11

Además programamos dos subrutinas para el envio y recepción de datos:

790 REM LECTURA DEL PUERTO SERIE
800 A=PEEK(65385)
810 B=A AND 8
820 IF B=0 THEN 800
830 D$=CHR$(PEEK(65384))
840 PRINT "RECIBE: " + D$
850 RETURN
860 REM ESCRITURA DEL PUERTO SERIE
870 A=PEEK(65385)
880 B=A AND 16
890 IF B=0 THEN 870
900 POKE 65384,ASC(A$)
910 PRINT "ENVIA: " + A$
920 RETURN

Para sincronizar el inicio de la comunicación entre las dos computadoras, cada una de ellas manda un mensaje con el caracter "N" y al mismo tiempo lo espera recibir. Esto nos permite correr el juego de manera asíncrona y no importa que computadora empiece primero:

40 CLS
80 REM MANDA LA SEÑAL DE SINCRONIZACION
90 A$="N":GOSUB 870
100 REM ESPERA LA SEÑAL DE SINCRONIZACION
110 GOSUB 800
120 IF D$<>"N" THEN 90

Como nuestro juego es "punto a punto" y cualquiera de las dos computadoras puede correr primero su programa; hacemos un sorteo para elegir que jugador va usar cada uno de ellos:

130 REM REALIZA EL SORTEO
140 A$=CHR$(RND(10)+47)
150 PRINT "RESULTADO: " + A$
155 REM ENVIA NUESTRO NUMERO ALEATORIO
160 GOSUB 870
165 REM ESPERA RECIBIR EL NUMERO ALEATORIO DE NUESTRO CONTRINCANTE
170 GOSUB 800
175 REM SI EMPATARON, VUELVE A HACER EL SORTEO
180 IF A$=D$ THEN 140

280 IF ( A$>D$) THEN 320
290 FX=0:FY=100
300 GX=0:GY=50
310 GOTO 340
320 FX=0:FY=50
330 GX=0:GY=100

Ahora nos vamos a ocupar de las animaciones de nuestros jugadores. Me basé en una técnica que aprendí del libro "Gráficos y sonidos para el Dragón" de K y S Brain ; Justamente cuando era niño. Consiste en primero dibujar a los jugadores y obtener una copia de la representación en memoria de sus movimientos por medio de la orden GET para después durante el juego copiar esa memoria durante el juego con la orden PUT.

El código que dibuja los movimientos de los jugadores y los guarda en memoria es el siguiente:

20 DIM F1(50):DIM F2(50):DIM F0(50)
30 DIM G1(50):DIM G2(50):DIM G0(50)

190 PMODE 3,1
200 SCREEN 1,0
210 PCLS 1
220 GOSUB 710
230 GET(10,0)-(26,15),F1,G
240 GET(10,20)-(26,35),G1,G
250 GET(30,0)-(46,15),F2,G
260 GET(30,20)-(46,35),G2,G

710 REM DIBUJA LOS MOVIMIENTOS DE LOS JUGADORES
720 FOR N=1 TO 40
730 READ X,Y:PSET(X+10,Y): PSET(X+10,Y+20,3)
740 NEXT N
750 FOR N=1 TO 48
760 READ X,Y:PSET(X+30,Y): PSET(X+30,Y+20,3)
770 NEXT N
780 RETURN

925 REM MOVIMIENTO CON PIERNAS JUNTAS
930 DATA 6,0,8,0,10,0
940 DATA 6,1,8,1,10,1
950 DATA 6,2,8,2,10,2
960 DATA 8,3
970 DATA 6,4,8,4,10,4
980 DATA 6,5,8,5,10,5
990 DATA 6,6,8,6,10,6,16,6
1000 DATA 6,7,8,7,10,7,7,12,7,14,7,16,7
1010 DATA 6,8,10,8
1020 DATA 6,9,10,9
1030 DATA 6,10,10,10
1040 DATA 6,11,8,11,10,11
1050 DATA 8,12
1060 DATA 8,13
1070 DATA 8,14
1080 DATA 8,15,10,15

1085 REM MOVIMIENTO CON PIERNAS SEPARADAS
1090 DATA 6,0,8,0,10,0
1100 DATA 6,1,8,1,10,1,16,1
1110 DATA 6,2,8,2,10,2,16,2
1120 DATA 8,3,14,3
1130 DATA 4,4,6,4,8,4,10,4,12,4
1140 DATA 2,5,6,5,10,5
1150 DATA 0,6,6,6,10,6
1160 DATA 2,7,6,7,10,7
1170 DATA 6,8,10,8
1180 DATA 6,9,8,9,10,9
1190 DATA 6,10,8,10,10,10
1200 DATA 6,11,8,11,10,11
1210 DATA 6,12,10,12
1220 DATA 4,13,12,13
1230 DATA 2,14,14,14
1240 DATA 2,15,4,15,14,15,16,15

grafysonidos
Con los libros de la clon Dragon,
aprendí muchas técnicas de programación

Ya con todas las inicializaciones, podemos dibujar la "cancha" y a los jugadores:

270 PCLS1
340 FOR LI=105 TO 110 STEP 5:LINE(0,LI)-(255,LI-50),PSET:NEXT LI
350 GET(FX,FY)-(FX+16,FY+15),F0,G
360 PUT(FX,FY)-(FX+16,FY+15),F1,OR
370 GET(GX,GY)-(GX+16,GY+15),G0,G
380 PUT(GX,GY)-(GX+16,GY+15),G1,OR

El movimiento del jugador local se a través del teclado:

390 A$=INKEY$
400 IF A$="" THEN 560
410 PUT(FX,FY)-(FX+16,FY+15),F0,PSET
420 IF A$="P" THEN FX=FX+16
430 IF A$="O" THEN FX=FX-16
440 IF A$="Q" THEN FY=FY-16
450 IF A$="A" THEN FY=FY+16

460 REM DIBUJAMOS LA NUEVA POSICION DEL JUGADOR LOCAL
470 GET(FX,FY)-(FX+16,FY+15),F0,G
480 PUT(FX,FY)-(FX+16,FY+15),F2,OR
490 PUT(FX,FY)-(FX+16,FY+15),F0,AND
500 PUT(FX,FY)-(FX+16,FY+15),F1,OR

Para simplificar la programación, en lugar de hacer un sistema de mensajes, simplemente se envia la tecla presionada al otro jugador:

455 GOSUB 870

Se revisa si el jugador remoto presionó alguna tecla y se procesa de la misma forma que para el jugador local:

560 GOSUB 790
610 PUT(GX,GY)-(GX+16,GY+15),G0,PSET
620 IF D$="P" THEN GX=GX+16
630 IF D$="O" THEN GX=GX-16
640 IF D$="Q" THEN GY=GY-16
650 IF D$="A" THEN GY=GY+16

655 REM DIBUJAMOS LA NUEVA POSICION DEL JUGADOR REMOTO
660 GET(GX,GY)-(GX+16,GY+15),G0,G
670 PUT(GX,GY)-(GX+16,GY+15),G2,OR
680 PUT(GX,GY)-(GX+16,GY+15),G0,AND
690 PUT(GX,GY)-(GX+16,GY+15),G1,OR

Finalmente, repetimos el ciclo:

700 GOTO 390

Conclusiones de esta parte

En el siguiente video, podemos apreciar el funcionamiento del programa:

Como podemos ver, aún para ser un programa en BASIC la velocidad es razonable; sobretodo para juegos de turno como los de cartas y ajedrez. En realidad la velocidad esta limitada por la velocidad de las instrucciones gráficas, por lo que un juego en baja resolución funcionaria muy rápido para juegos de acción. Si se va usar alta resolución para un juego de acción, lo conveniente es usar pocos efectos gráficos o bien programarlo en ensamblador.

Muchas Gracias a mi hermano por la interpretación de la música de fondo del video.

{ 0 comments }

Obtener dinámicamente el tipo de una clase en C++

by Jorge Machin on August 14, 2009 · 0 comments

in C/C++

Cuando manejamos herencia, a veces es necesario poder diferenciar entre varias clases heredadas. Una forma ordenada de hacerlo, es declarar una variable tipo que nos identifique con que clase estamos trabajando. Otra opción es realizando un casting dinámico para aprovechar las propiedades RTTI (Run-time type information) de los objetos de C++. Si el casting nos regresa NULL es que no es del tipo que nos interesa.

A continuación presento un ejemplo que ilustra esta técnica:

#include <iostream>

using namespace std;

class Figura {

   public:

     // Es importante que la clase base sea polimorfica agregándole al menos una función virtual:

     virtual ~Figura() { };

};

class Triangulo : public Figura {

};

class Cuadrado : public Figura {

};

main() {

   Figura *figura1 = new Cuadrado;
   Figura *figura2 = new Triangulo;

   if ( dynamic_cast<Cuadrado *>( figura1 ) )

      cout <<"La figura1 es un Cuadrado" <<endl;

   else if ( dynamic_cast<Triangulo *>( figura1 ) )

      cout <<"La figura1 es un Triangulo" <<endl;

   if ( dynamic_cast<Cuadrado *>( figura2 ) )

      cout <<"La figura2 es un Cuadrado" <<endl;

   else if ( dynamic_cast<Triangulo *>( figura2 ) )

      cout <<"La figura2 es un Triangulo" <<endl;

   return 0;

}

Aquí lo puedes ver en acción: http://www.ideone.com/xAmv72e5

{ 0 comments }

Cataratas del Niágara

by Jorge Machin on August 9, 2009 · 0 comments

in Personal, Viajes, videos

Un video tomado durante mis vacaciones a Canadá

Algunas fotos las podemos ver aquí.

{ 0 comments }

Ahora que hemos comprobado el correcto funcionamiento de la Interface RS-232, el siguiente paso es establecer la comunicación entre las dos computadoras por medio del lenguaje BASIC.

La configuración de la interface RS-232 se hace a través de dos registros del circuito integrado 6551, los cuales son accesibles en las direcciones de memoria 65386 y 65387. El primero se conoce como el registro de control, el cual se utiliza para establecer la velocidad de transmisión en baudios, la fuente de frecuencia, el tamaño de la palabra y el número de bits de parada.

El segundo es el registro de comandos, que controlada diferentes modos y funciones como el modo de echo y comunicación con paridad.

controlregister
Tabla 1 Configuración del registro de control
según el manual del usuario

commandregister
Tabla 2 Configuración del registro de comando
según el manual del usuario

La programación de los registros se hace por medio de dos pokes:

5 REM ESTABLECEMOS EL REGISTRO DE CONTROL
10 POKE 65387,30
15 REM ESTABLECEMOS EL REGISTRO DE COMANDOS
20 POKE 65386,11

En este programa de prueba, guardamos si hay una tecla presionada para posteriormente mandarla:

30 I$=INKEY$

Para saber si hemos recibido información de la otra conexión, se debe consultar el registro de estado del circuito integrado 6551. Este es acceble desde la dirección de memoria 65385.

statusregister
Tabla 3 Configuración del registro de estado
según el manual del usuario

Si el bit 3 esta a uno, es que hay información por leer.

35 REM LEEMOS EL REGISTRO DE ESTADO
40 A=PEEK(65385)
50 B=A AND 8
60 IF B=0 THEN 90

La información en el registro de entrada la podemos recuperar leyendo la dirección de memoria 65384:

70 D=PEEK(65384)
80 PRINT CHR$(D)

Si presionó alguna tecla, la transmitiremos; de lo contrario regresaremos al inicio al ciclo. De manera similar, para transmitir consultamos el bit 4 del registro de estado para checar si podemos transmitir. Si es así, hacemos un poke a la dirección de memoria con el byte que deseamos enviar.

90 IF I$="" THEN 30
95 REM ESPERAMOS A QUE PODAMOS TRANSMITIR
100 A=PEEK(65385)
110 B=A AND 16
120 IF B=0 THEN 100
130 POKE 65384,ASC(I$)
140 GOTO 30

Una vez que emparejamos ambas computadoras y ejecutamos nuestro programa en BASIC, la tecla que apretamos en cada una de ellas se transmite a la otra.

Con esto, ya tenemos garantizado la mínima comunicación necesaria para programar nuestro juego.

{ 0 comments }

Walk through fire

by Jorge Machin on August 6, 2009 · 0 comments

in Canciones

Una canción de Olivia Newton John:

Darling don't you ride so fast
Don't you want to try to make this thing last
Tell me how can I prove I'd walk through fire

I know you've had a very hard time
No I don't know the facts but I've seen it in your eyes
And this much is true, I'd walk through fire for you

chorus:

We both have reason to be afraid, but a choice has been made
No love is written in stone, but I'll walk through fire, through fire
Oh - I'll walk through fire for you, through fire
'Cos I know you'd do the same for me

Oh baby let's run away, let's break up some other day
Write love songs and lullabies, make love while the skies go by
I want to prove, I'll walk through fire for you

chorus

Flame destroy a love, flame make it stronger
Forge a blade of love, and satisfy my hunger
So we're afraid of love, I can't hide any longer
We'll find the courage as we go

Let the little boys pretend that there's some kind of supermen
With tough talk and alibis and flags to defend
Things too young for us to do, but I'll walk through fire for you

We both have reason to be afraid, but a choice has been made
No love is written in stone, but I'll walk through fire, through fire
Oh - I'll walk through fire for you, through fire
Maybe someday we'll walk through fire, through fire
Oh I'll walk through fire for you, through fire
'Cos I know you'd do the same for me

{ 0 comments }