Nuevo concursos BASIC y El Hobbit Bytemaniacos

Noticias relacionadas con el mundo del Spectrum en general y este foro en particular. Presentación de nuevos usuarios.

Moderador: Sir Cilve Sinclair

Avatar de Usuario
Hark0
Freddy Hardest
Mensajes: 545
Registrado: Mar Nov 13, 2012 12:42 pm
Ubicación: Cornella de Llobregat - Barcelona
Contactar:

Re: Nuevo concursos BASIC y El Hobbit Bytemaniacos

Mensaje por Hark0 » Mié Ene 16, 2013 1:44 pm

na_th_an escribió:
sromero escribió:
na_th_an escribió:Ahora la churrera se ha convertido más en pelearse con el lenguaje de scripting para que el motor haga lo que tú quieres :lol:


¿En qué scriptáis?

¿LUA? ¿Python? ¿algo propio?

Quiero decir ... ¿generáis código a partir de los scripts o es un intérprete en tiempo real?


Un lenguaje propio basado en cláusulas. Cada cláusula tiene un montón de comprobaciones sobre valores de objetos del motor que se van comprobando hasta que falla alguna (AND). Si llegamos al fin de las comprobaciones, ejecutámos código que modifican los valores de los objetos, o cosas en la pantalla.

Este lenguaje se "compila" en un bytecode muy fácil de interpretar. El intérprete se genera en código C para que sólo se genere código que interprete las comprobaciones y las acciones que se han empleado.

Dicho intérprete se lanza en momentos específicos (al entrar en una pantalla, al pulsar la tecla de interacción, al matar un enemigo, al coger un objeto) y sirve para definir la lógica del juego.

Puedes verlo en acción en el código del hobbit. En la carpeta "script" está el archivo .SPT con los fuentes del script. En dev/msc.h está el intérprete y el bytecode compilado.



:shock: no-entiendo-na-da
litiopixel.blogspot.com - Desarrollo videojuegos Indie · Pixel-Art · Retroinformática · Electrónica

Avatar de Usuario
na_th_an
Nonamed
Mensajes: 1889
Registrado: Lun May 07, 2007 10:16 am
Ubicación: Andalucía

Re: Nuevo concursos BASIC y El Hobbit Bytemaniacos

Mensaje por na_th_an » Mié Ene 16, 2013 2:08 pm

En una videoaventura, al final te encuentras que tienes un montón de IFs comprobando cosas y luego un montón de acciones: Si tienes la llave y pulsas el botón en la pantalla 4 cuando no hay enemigos, entonces aumentar los puntos, borrar el tile 4,7, escribir el texto "BIEN HECHO" y que suene BIP. Y así un montón.

Esto significa que cada juego tiene un montón de código específico que, además, ocupa un huevo.

Ahí entra el scripting. Mediante un script, codificas todas esas comprobaciones y acciones de motor en un bytecode. El bytecode y el intérprete que lo ejecuta ocupan mucho menos que una ristra de IFs. Además, esto te permite seguir teniendo tu motor "limpio" de cosas específicas de un juego.

Hay ciertos momentos en los que se ejecutan los scripts:
- Al empezar el juego. Esto nos permite configurar un poco algunas cosas o inicializar los flags.
- Cuando entramos en una pantalla, para modificar el escenario, por ejemplo.
- Cuando pulsamos la tecla de interactuar, para examinar o usar un objeto.
- Cuando matamos a un enemigo, por si hay que contar cuantos van o hacer cualquier otra cosa.
...

En la churrera (nuestro engine) hemos optado por incluir scripting para definir el gameplay. Así, el motor se queda limpio. El juego de El Hobbit, por ejemplo, tiene el mismo motor de siempre, pero un script diferente que define donde están los objetos, donde se usan, qué pasa cuando se coge algo, comprueba que lo hayamos hecho todo... en definitiva, el script define el gameplay.

Hemos diseñado nuestro lenguaje de scripting de forma clausal. El programa se divide en secciones, y cada sección contiene una serie de clausulas. Una cláusula no es más que un montón de comprobaciones y una lista de comandos asociados. Si se cumplen todas las comprobaciones, se ejecutan los comandos. Hemos usado este modelo porque es suficiente para lo que necesitamos y porque es tremendamente sencillo de interpretar.

Está en los fuentes, pero este es el script de El Hobbit:

Código: Seleccionar todo

# El Hobbit script file
# Copyleft 2011 by The Mojon Twins.
# Churrera 4.5

# flags:
# 1 = talked to gandalf
# 2 = show dwarves
# 3 = dwarves gotten
# 5 = open door
# 6 = tiene anillo

ENTERING GAME
   IF TRUE
   THEN
      SET FLAG 1 = 0
      SET FLAG 2 = 0
      SET FLAG 3 = 0
      SET FLAG 4 = 0
      SET FLAG 5 = 0
      SET FLAG 6 = 0
   END
END

# General actions

ENTERING ANY
   IF FLAG 3 = 13
   IF FLAG 5 = 0
   THEN
      SET FLAG 5 = 1
      TEXT ___LA_CUEVA_ESTA_ABIERTA____
   END   
   
   IF FLAG 1 = 0
   THEN
      TEXT ______BUSCA_AL_GANDALF______
   END
END

PRESS_FIRE AT ANY
   IF FLAG 6 = 1
   IF NPANT_NOT 5
   THEN
      TEXT _____TE_PONES_EL_ANILLO_____
      SHOW
      FLICKER
      DIZZY
      SOUND 6
   END
   
   IF FLAG 6 = 1
   IF NPANT 5
   THEN
      TEXT __AQUI_EL_ANILLO_NO_SIRVE___
      SHOW
      SOUND 4
   END
   
   # Para que not pite
   IF TRUE
   THEN
   END
END

# Initial screen, show text

ENTERING SCREEN 28
   IF TRUE
   THEN
      TEXT ___UN_BUEN_DIA_EN_HOBBITON__
   END
END

# Gandalf

ENTERING SCREEN 0
   IF TRUE
   THEN
      SET TILE (2, 2) = 19
   END
END

PRESS_FIRE AT SCREEN 0   
   IF FLAG 1 <> 1
   IF PLAYER_TOUCHES 2, 2
   THEN
      TEXT _____REUNE_A_LOS_ENANOS!____
      SHOW
      SOUND 7
      SET FLAG 1 = 1
      SET FLAG 2 = 1
   END
END

# Entrada cueva

ENTERING SCREEN 31
   IF FLAG 5 = 0
   THEN
      SET TILE (9, 0) = 15
   END
END

ENTERING SCREEN 24
   IF TRUE
   THEN
      TEXT _BUSCA_EL_TESORO_DEL_DRAGON_
   END
END

# Moto seminueva

ENTERING SCREEN 1
   IF TRUE
   THEN
      SET TILE (10, 1) = 24
      SET TILE (11, 1) = 25
   END
END

PRESS_FIRE AT SCREEN 1
   IF PLAYER_IN_Y 16, 33
   IF PLAYER_IN_X 145, 192
   THEN
      TEXT ____VENDO_MOTO_SEMINUEVA____
      SHOW
      SOUND 7
   END
END

# Anillo

ENTERING SCREEN 4
   IF FLAG 6 = 0
   THEN
      SET TILE (5, 4) = 18
      TEXT __OTIA...
   END
END

PRESS_FIRE AT SCREEN 4
   IF FLAG 6 <> 1
   IF PLAYER_TOUCHES 5, 4
   THEN
      SET TILE (5, 4) = 0
      SOUND 8
      TEXT ____ES_EL_ANILLO_UNICO_!____
      SHOW
      SOUND 7
      SET FLAG 6 = 1
      PRINT_TILE_AT (2, 22) = 18
   END
END

ENTERING SCREEN 3
   IF FLAG 6 = 1
   THEN
      TEXT FIRE_PARA_PONERSE_EL_ANILLO_
   END
END

ENTERING SCREEN 10
   IF FLAG 6 = 1
   THEN
      TEXT ____PERO_EL_ANILLO_MAREA____
   END
END

# Gollum

ENTERING SCREEN 12
   IF TRUE
   THEN
      TEXT POR_AQUI_ANDA_GOLLUM_CABREAO
   END
END

# Si te ve

ENTERING SCREEN 6
   IF TRUE
   THEN
      TEXT CUIDAO_QUE_SI_TE_VE_TE_MATA!
   END
END

# Dragon

ENTERING SCREEN 5
   IF TRUE
   THEN
      SET TILE (6, 4) = 20
      SET TILE (7, 4) = 21
      SET TILE (6, 3) = 22
      SET TILE (7, 3) = 23
      SET TILE (5, 1) = 26
      SET TILE (6, 1) = 27
      SET TILE (7, 1) = 28
      SET TILE (8, 1) = 29
      SET_FIRE_ZONE 0, 64, 255, 79
      TEXT _____EL_TERRIBLE_SMAUG______
   END   
END

PRESS_FIRE AT SCREEN 5
   IF PLAYER_IN_Y 64, 79
   IF PLAYER_IN_X 128, 255
   THEN
      TEXT ________SMAUG_TE_VE_________
      SHOW
      SOUND 7
      SOUND 4
      SOUND 8
      SOUND 4
      GAME OVER
   END
   
   IF PLAYER_IN_Y 64, 79
   IF PLAYER_IN_X 0, 127
   THEN
      SET_FIRE_ZONE 0, 16, 255, 31
   END
   
   IF PLAYER_IN_Y 16, 31
   THEN
      TEXT _____EL_TESORO_ES_TUYO______
      SHOW
      SOUND 7
      SOUND 6
      SOUND 8
      SOUND 6
      WIN GAME
   END
END


Para poder usar esto, hemos creado un compilador que hace dos cosas:

1.- Compila el código en un bytecode fácil de interpretar. Es parecido a una especie de lenguaje de ensamblador, para entendernos.
2.- Genera el código C con el intérprete del bytecode. De este modo, sólo se genera código que interprete las órdenes y comprobaciones que hay en el bytecode, ahorrando espacio.

El motor principal llama al intérprete diciéndole qué sección del código contiene las comprobaciones pertinentes, y el intérprete hace su labor.

Este es el código compilado. Arriba hay una ristra de bytes con el script compilado, y luego está el intérprete que se genera para interpretar ese script.

Código: Seleccionar todo

// msc.h
// Generado por Mojon Script Compiler de la Churrera
// Copyleft 2011 The Mojon Twins
 
// Script data & pointers
extern unsigned char mscce_0 [];
extern unsigned char mscce_1 [];
extern unsigned char mscce_2 [];
extern unsigned char mscce_3 [];
extern unsigned char mscce_4 [];
extern unsigned char mscce_5 [];
extern unsigned char mscce_6 [];
extern unsigned char mscce_7 [];
extern unsigned char mscce_8 [];
extern unsigned char mscce_9 [];
extern unsigned char mscce_10 [];
extern unsigned char mscce_11 [];
extern unsigned char mscce_12 [];
extern unsigned char msccf_0 [];
extern unsigned char msccf_1 [];
extern unsigned char msccf_2 [];
extern unsigned char msccf_3 [];
extern unsigned char msccf_4 [];
 
unsigned char *e_scripts [] = {
    mscce_3, mscce_6, 0, mscce_8, mscce_7, mscce_12, mscce_11, 0, 0, 0, mscce_9, 0, mscce_10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, mscce_5, 0, 0, 0, mscce_2, 0, 0, mscce_4, 0, 0, 0, mscce_0, mscce_1
};
 
unsigned char *f_scripts [] = {
    msccf_1, msccf_2, 0, 0, msccf_3, msccf_4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, msccf_0
};
 
#asm
._mscce_0
    defb 0x15, 0xF0, 0xFF, 0x01, 0x01, 0x00, 0x01, 0x02, 0x00, 0x01, 0x03, 0x00, 0x01, 0x04, 0x00, 0x01, 0x05, 0x00, 0x01, 0x06, 0x00, 0xFF, 0xFF
._mscce_1
    defb 0x29, 0x10, 0x03, 0x0D, 0x10, 0x05, 0x00, 0xFF, 0x01, 0x05, 0x01, 0xE3, 0x00, 0x00, 0x00, 0x2C, 0x21, 0x00, 0x23, 0x35, 0x25, 0x36, 0x21, 0x00, 0x25, 0x33, 0x34, 0x21, 0x00, 0x21, 0x22, 0x29, 0x25, 0x32, 0x34, 0x21, 0x00, 0x00, 0x00, 0x00, 0xEE, 0xFF, 0x23, 0x10, 0x01, 0x00, 0xFF, 0xE3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x35, 0x33, 0x23, 0x21, 0x00, 0x21, 0x2C, 0x00, 0x27, 0x21, 0x2E, 0x24, 0x21, 0x2C, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEE, 0xFF, 0xFF
._mscce_2
    defb 0x21, 0xF0, 0xFF, 0xE3, 0x00, 0x00, 0x00, 0x35, 0x2E, 0x00, 0x22, 0x35, 0x25, 0x2E, 0x00, 0x24, 0x29, 0x21, 0x00, 0x25, 0x2E, 0x00, 0x28, 0x2F, 0x22, 0x22, 0x29, 0x34, 0x2F, 0x2E, 0x00, 0x00, 0xEE, 0xFF, 0xFF
._mscce_3
    defb 0x07, 0xF0, 0xFF, 0x20, 0x02, 0x02, 0x13, 0xFF, 0xFF
._mscce_4
    defb 0x09, 0x10, 0x05, 0x00, 0xFF, 0x20, 0x09, 0x00, 0x0F, 0xFF, 0xFF
._mscce_5
    defb 0x21, 0xF0, 0xFF, 0xE3, 0x00, 0x22, 0x35, 0x33, 0x23, 0x21, 0x00, 0x25, 0x2C, 0x00, 0x34, 0x25, 0x33, 0x2F, 0x32, 0x2F, 0x00, 0x24, 0x25, 0x2C, 0x00, 0x24, 0x32, 0x21, 0x27, 0x2F, 0x2E, 0x00, 0xEE, 0xFF, 0xFF
._mscce_6
    defb 0x0B, 0xF0, 0xFF, 0x20, 0x0A, 0x01, 0x18, 0x20, 0x0B, 0x01, 0x19, 0xFF, 0xFF
._mscce_7
    defb 0x11, 0x10, 0x06, 0x00, 0xFF, 0x20, 0x05, 0x04, 0x12, 0xE3, 0x00, 0x00, 0x2F, 0x34, 0x29, 0x21, 0xEE, 0xFF, 0xFF
._mscce_8
    defb 0x23, 0x10, 0x06, 0x01, 0xFF, 0xE3, 0x26, 0x29, 0x32, 0x25, 0x00, 0x30, 0x21, 0x32, 0x21, 0x00, 0x30, 0x2F, 0x2E, 0x25, 0x32, 0x33, 0x25, 0x00, 0x25, 0x2C, 0x00, 0x21, 0x2E, 0x29, 0x2C, 0x2C, 0x2F, 0x00, 0xEE, 0xFF, 0xFF
._mscce_9
    defb 0x23, 0x10, 0x06, 0x01, 0xFF, 0xE3, 0x00, 0x00, 0x00, 0x00, 0x30, 0x25, 0x32, 0x2F, 0x00, 0x25, 0x2C, 0x00, 0x21, 0x2E, 0x29, 0x2C, 0x2C, 0x2F, 0x00, 0x2D, 0x21, 0x32, 0x25, 0x21, 0x00, 0x00, 0x00, 0x00, 0xEE, 0xFF, 0xFF
._mscce_10
    defb 0x21, 0xF0, 0xFF, 0xE3, 0x30, 0x2F, 0x32, 0x00, 0x21, 0x31, 0x35, 0x29, 0x00, 0x21, 0x2E, 0x24, 0x21, 0x00, 0x27, 0x2F, 0x2C, 0x2C, 0x35, 0x2D, 0x00, 0x23, 0x21, 0x22, 0x32, 0x25, 0x21, 0x2F, 0xEE, 0xFF, 0xFF
._mscce_11
    defb 0x20, 0xF0, 0xFF, 0xE3, 0x23, 0x35, 0x29, 0x24, 0x21, 0x2F, 0x00, 0x31, 0x35, 0x25, 0x00, 0x33, 0x29, 0x00, 0x34, 0x25, 0x00, 0x36, 0x25, 0x00, 0x34, 0x25, 0x00, 0x2D, 0x21, 0x34, 0x21, 0xEE, 0xFF, 0xFF
._mscce_12
    defb 0x46, 0xF0, 0xFF, 0x20, 0x06, 0x04, 0x14, 0x20, 0x07, 0x04, 0x15, 0x20, 0x06, 0x03, 0x16, 0x20, 0x07, 0x03, 0x17, 0x20, 0x05, 0x01, 0x1A, 0x20, 0x06, 0x01, 0x1B, 0x20, 0x07, 0x01, 0x1C, 0x20, 0x08, 0x01, 0x1D, 0x51, 0x00, 0x40, 0xFF, 0x4F, 0xE3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x2C, 0x00, 0x34, 0x25, 0x32, 0x32, 0x29, 0x22, 0x2C, 0x25, 0x00, 0x33, 0x2D, 0x21, 0x35, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEE, 0xFF, 0xFF
._msccf_0
    defb 0x2A, 0x10, 0x06, 0x01, 0x51, 0x05, 0xFF, 0xE3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x25, 0x00, 0x30, 0x2F, 0x2E, 0x25, 0x33, 0x00, 0x25, 0x2C, 0x00, 0x21, 0x2E, 0x29, 0x2C, 0x2C, 0x2F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEE, 0xE1, 0x32, 0x33, 0xE0, 0x06, 0xFF, 0x28, 0x10, 0x06, 0x01, 0x50, 0x05, 0xFF, 0xE3, 0x00, 0x00, 0x21, 0x31, 0x35, 0x29, 0x00, 0x25, 0x2C, 0x00, 0x21, 0x2E, 0x29, 0x2C, 0x2C, 0x2F, 0x00, 0x2E, 0x2F, 0x00, 0x33, 0x29, 0x32, 0x36, 0x25, 0x00, 0x00, 0x00, 0xEE, 0xE1, 0xE0, 0x04, 0xFF, 0x03, 0xF0, 0xFF, 0xFF, 0xFF
._msccf_1
    defb 0x2A, 0x13, 0x01, 0x01, 0x20, 0x02, 0x02, 0xFF, 0xE3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x25, 0x35, 0x2E, 0x25, 0x00, 0x21, 0x00, 0x2C, 0x2F, 0x33, 0x00, 0x25, 0x2E, 0x21, 0x2E, 0x2F, 0x33, 0xEE, 0xE1, 0xE0, 0x07, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0xFF, 0xFF
._msccf_2
    defb 0x29, 0x22, 0x10, 0x21, 0x21, 0x91, 0xC0, 0xFF, 0xE3, 0x00, 0x00, 0x00, 0x00, 0x36, 0x25, 0x2E, 0x24, 0x2F, 0x00, 0x2D, 0x2F, 0x34, 0x2F, 0x00, 0x33, 0x25, 0x2D, 0x29, 0x2E, 0x35, 0x25, 0x36, 0x21, 0x00, 0x00, 0x00, 0x00, 0xEE, 0xE1, 0xE0, 0x07, 0xFF, 0xFF
._msccf_3
    defb 0x31, 0x13, 0x06, 0x01, 0x20, 0x05, 0x04, 0xFF, 0x20, 0x05, 0x04, 0x00, 0xE0, 0x08, 0xE3, 0x00, 0x00, 0x00, 0x00, 0x25, 0x33, 0x00, 0x25, 0x2C, 0x00, 0x21, 0x2E, 0x29, 0x2C, 0x2C, 0x2F, 0x00, 0x35, 0x2E, 0x29, 0x23, 0x2F, 0x00, 0xEE, 0xE1, 0xE0, 0x07, 0x01, 0x06, 0x01, 0x50, 0x02, 0x16, 0x12, 0xFF, 0xFF
._msccf_4
    defb 0x30, 0x22, 0x40, 0x4F, 0x21, 0x80, 0xFF, 0xFF, 0xE3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x2D, 0x21, 0x35, 0x27, 0x00, 0x34, 0x25, 0x00, 0x36, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEE, 0xE1, 0xE0, 0x07, 0xE0, 0x04, 0xE0, 0x08, 0xE0, 0x04, 0xF0, 0xFF, 0x0D, 0x22, 0x40, 0x4F, 0x21, 0x00, 0x7F, 0xFF, 0x51, 0x00, 0x10, 0xFF, 0x1F, 0xFF, 0x2D, 0x22, 0x10, 0x1F, 0xFF, 0xE3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x2C, 0x00, 0x34, 0x25, 0x33, 0x2F, 0x32, 0x2F, 0x00, 0x25, 0x33, 0x00, 0x34, 0x35, 0x39, 0x2F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEE, 0xE1, 0xE0, 0x07, 0xE0, 0x06, 0xE0, 0x08, 0xE0, 0x06, 0xF1, 0xFF, 0xFF
#endasm
 
unsigned char *script;
 
void msc_init_all () {
    unsigned char i;
    for (i = 0; i < MSC_MAXITEMS; i ++)
        items [i].status = 0;
    for (i = 0; i < MSC_MAXFLAGS; i ++)
        flags [i] = 0;
}
 
unsigned char read_byte () {
    unsigned char c;
    c = script [0];
    script ++;
    return c;
}
 
unsigned char read_vbyte () {
    unsigned char c;
    c = read_byte ();
    if (c & 128) return flags [c & 127];
    return c;
}
 
// Ejecutamos el script apuntado por *script:
unsigned char run_script () {
    unsigned char res = 0;
    unsigned char terminado = 0;
    unsigned char continuar = 0;
    unsigned char x, y, n, m, c;
    unsigned char *next_script;
 
    if (script == 0)
        return;
 
    script_something_done = 0;
 
    while (1) {
        c = read_byte ();
        if (c == 0xFF) break;
        next_script = script + c;
        terminado = continuar = 0;
        while (!terminado) {
            c = read_byte ();
            switch (c) {
                case 0x10:
                    // IF FLAG x = n
                    // Opcode: 10 x n
                    x = read_vbyte ();
                    n = read_vbyte ();
                    if (flags [x] != n)
                        terminado = 1;
                    break;
                case 0x13:
                    // IF FLAG x <> n
                    // Opcode: 13 x n
                    x = read_vbyte ();
                    n = read_vbyte ();
                    if (flags [x] == n)
                        terminado = 1;
                    break;
                case 0x20:
                    // IF PLAYER_TOUCHES x, y
                    // Opcode: 20 x y
                    x = read_vbyte ();
                    y = read_vbyte ();
                    if (!((player.x >> 6) >= (x << 4) - 15 && (player.x >> 6) <= (x << 4) + 15 && (player.y >> 6) >= (y << 4) - 15 && (player.y >> 6) <= (y << 4) + 15))
                        terminado = 1;
                    break;
                case 0x21:
                    // IF PLAYER_IN_X x1, x2
                    // Opcode: 21 x1 x2
                    x = read_byte ();
                    y = read_byte ();
                    if (!((player.x >> 6) >= x && (player.x >> 6) <= y))
                        terminado = 1;
                    break;
                case 0x22:
                    // IF PLAYER_IN_Y y1, y2
                    // Opcode: 22 y1 y2
                    x = read_byte ();
                    y = read_byte ();
                    if (!((player.y >> 6) >= x && (player.y >> 6) <= y))
                        terminado = 1;
                    break;
                case 0x50:
                     // IF NPANT n
                     // Opcode: 50 n
                     n = read_vbyte ();
                     if (n_pant != n)
                         terminado = 1;
                     break;
                case 0x51:
                     // IF NPANT_NOT n
                     // Opcode: 51 n
                     n = read_vbyte ();
                     if (n_pant == n)
                         terminado = 1;
                     break;
                case 0xF0:
                     // IF TRUE
                     // Opcode: F0
                     break;
                case 0xFF:
                    // THEN
                    // Opcode: FF
                    terminado = 1;
                    continuar = 1;
                    script_something_done = 1;
                    break;
            }
        }
        if (continuar) {
            terminado = 0;
            while (!terminado) {
                c = read_byte ();
                switch (c) {
                    case 0x01:
                        // SET FLAG x = n
                        // Opcode: 01 x n
                        x = read_vbyte ();
                        n = read_vbyte ();
                        flags [x] = n;
                        break;
                    case 0x20:
                        // SET TILE (x, y) = n
                        // Opcode: 20 x y n
                        x = read_vbyte ();
                        y = read_vbyte ();
                        n = read_vbyte ();
                        map_buff [x + (y << 4) - y] = n;
                        map_attr [x + (y << 4) - y] = comportamiento_tiles [n];
                        draw_coloured_tile (VIEWPORT_X + x + x, VIEWPORT_Y + y + y, n);
                        break;
                    case 0x32:
                        // FLICKER
                        // Opcode: 32
                        player.estado |= EST_PARP;
                        player.ct_estado = 32;
                        break;
                    case 0x33:
                        // DIZZY
                        // Opcode: 33
                        player.estado |= EST_DIZZY;
                        player.ct_estado = 32;
                        break;
                    case 0x50:
                        // PRINT_TILE_AT (X, Y) = N
                        // Opcode: 50 x y n
                        x = read_vbyte ();
                        y = read_vbyte ();
                        n = read_vbyte ();
                        draw_coloured_tile (x, y, n);
                        break;
                    case 0x51:
                        // SET_FIRE_ZONE x1, y1, x2, y2
                        // Opcode: 51 x1 y1 x2 y2
                        fzx1 = read_byte ();
                        fzy1 = read_byte ();
                        fzx2 = read_byte ();
                        fzy2 = read_byte ();
                        f_zone_ac = 1;
                        break;
                    case 0xE0:
                        // SOUND n
                        // Opcode: E0 n
                        n = read_vbyte ();
                        peta_el_beeper (n);
                        break;
                    case 0xE1:
                        // SHOW
                        // Opcode: E1
                        sp_UpdateNow ();
                        break;
                    case 0xE3:
                        x = 0;
                        while (1) {
                           n = read_byte ();
                           if (n == 0xEE) break;
                           sp_PrintAtInv (LINE_OF_TEXT, LINE_OF_TEXT_X + x, 71, n);
                           x ++;
                        }
                        break;
                    case 0xF0:
                        script_result = 2;
                        terminado = 1;
                        break;
                    case 0xF1:
                        script_result = 1;
                        terminado = 1;
                        break;
                    case 0xFF:
                        terminado = 1;
                        break;
                }
            }
        }
        script = next_script;
    }
 
    return res;
}

Avatar de Usuario
josepzin
Jack The Nipper
Mensajes: 117
Registrado: Vie Oct 19, 2007 4:27 pm
Ubicación: Carthagonova
Contactar:

Re: Nuevo concursos BASIC y El Hobbit Bytemaniacos

Mensaje por josepzin » Mié Ene 16, 2013 2:14 pm

Buf... a veces dan ganas de pegaros un guantazo por listillos :mrgreen: (pura envida)

La de horas que tiene que tener esa churrera encima!!!

Avatar de Usuario
na_th_an
Nonamed
Mensajes: 1889
Registrado: Lun May 07, 2007 10:16 am
Ubicación: Andalucía

Re: Nuevo concursos BASIC y El Hobbit Bytemaniacos

Mensaje por na_th_an » Mié Ene 16, 2013 2:21 pm

Supuestamente la hicimos para que pudiésemos hacer varios juegos dedicándonos solo al diseño, pero al final lo que pasa es que para cada juego que hacemos la ampliamos un montón con cosas nuevas :lol:

El primer juego con script fue Trabajo Basura (el scripting se usa para controlar todo el tema de coger los discos y meterlos en los terminales, y contar el número de becarios que pisamos), pero de ahí a El Hobbit o a los que estamos haciendo ahora hemos empepinado el sistema un montón.

sromero
Nonamed
Mensajes: 1221
Registrado: Mar Abr 17, 2007 12:35 pm
Ubicación: Valencia
Contactar:

Re: Nuevo concursos BASIC y El Hobbit Bytemaniacos

Mensaje por sromero » Mié Ene 16, 2013 2:52 pm

AVISO TOCHO:

Hark0 escribió: :shock: no-entiendo-na-da


Una de las cosas más interesantes a la hora de programar un juego es separar la lógica del juego totalmente del motor.

Por poner un ejemplo. Supongamos que quieres hacer un juego de aventuras tipo Zelda y tienen que pasar ciertas cosas al entrar en ciertas habitaciones, o cuando accionas un interruptor si llevas cierto objeto, etc.

En ese caso, la aproximación tradicional sería ponerse a programar las cosas dentro de lo que es el motor de juego, es decir, que dentro del código (por ejemplo en C o en ASM) describes y declaras todo lo que sucede en el juego:

Código: Seleccionar todo

void Entro_En_Habitacion()
{

   if ( juego.habitacion == HABITACION_SECRETA )
       sonar_musica()

   if ( juego.habitacion == FINAL_BOSS )
   {
       Cerrar_puertas( juego.habitacion )
       Mostrar_Cartel("El enemigo te quita todo lo que llevas y debes luchar con tus manos desnudas")
       jugador.inventario = ""
       jugador.x = habitacion.ancho / 2;
       jugador.y = habitacion.alto / 2;
       (etc...)
   }

   if (etc)...


Y así más y más código dentro de los fuentes del juego.

Eso implica que la lógica del juego está distribuída dentro de los ficheros fuente, y cada vez que quieres cambiar el comportamiento del juego tienes que editar tu programa y recompilar. Además, la lógica del juego se distribuye entre todos los ficheros fuente que tengas, de forma que tendrás la lógica de movimiento de los enemigos metida dentro del código de los enemigos, la de cambio de pantallas metida en otro fichero, etc etc.

A la hora de hacer cambios o de modificar lo que se hace en el juego, acabas yendo de un fichero a otro a cambiar muchas cosas, buscando por dónde de entre las líneas de código tienes cada cosa.

En lugar de esto, lo que se hace ahora es programar el motor del juego por un lado, y la lógica del juego por otro, escribiendo esta lógica en algún tipo de lenguaje de scripting, y luego el motor del juego lee esos ficheros de scripting y los interpreta. Yo voy a explicarlo un poco por encima para "PCs modernos" y luego comento cómo se puede hacer en Spectrum por limitaciones de memoria.

Lo que se haría es:

- Programar el motor del juego con las funciones BASICAS del mismo: dibujar sprite, dibujar texto, reproducir música, leer un fichero con el mapeado, mapear una pantalla, calcular colisión entre 2 objetos, cambiar la posición de un sprite, animaciones, añadir y quitar cosas a listas o clases, etc etc. No se debe programar en él NADA específico del juego.

- Diseñar un lenguaje de scripting sencillo que podamos interpretar desde nuestro programa. En el Spectrum se usaban lenguajes "binarios" por ahorrar memoria y hoy en día se utiliza LUA o PYTHON directamente.

- Programar un intérprete de esos scripts dentro de nuestro programa (o usar uno integrado si lo permite nuestro lenguaje, como Java que permite programar en python con jython y puede ejecutarlo). El intérprete tiene que desgranar el código "scriptado": es decir, parsearlo, ejecutarlo, y proporcionarle funciones y primitivas que permitan hacer cosas desde el código.

- Ubicar toda la lógica del juego en ese lenguaje de scripting en ficheros separados del motor. Por ejemplo, ubicaríamos toda la parte de lógica de "Entrada en habitaciones" a un fichero entrada_en_habitaciones.scp (o la extensión que queramos), en nuestro lenguaje elegido:


Código: Seleccionar todo

IF habitacion == HABITACION_SECRETA:
   Music(OFF);

IF habitacion == FINAL_BOSS:
   EVENTO(CERRAR_PUERTAS)
   PRINT("El enemigo blahblah")
   PLAYER.MOVE(CENTER)


Después, en el código del juego en sí, harías:

Código: Seleccionar todo

void Entro_En_Habitacion()
{
    Interpretar_Script("entro_en_habitaciones.scp");
}



La pregunta es ...

¿para qué sirve tanto follón?

Pues muy sencillo:

1.- El motor del juego, una vez programado, no es necesario recompilarlo. Puedes hacer cambios en el juego modificando los .scp sin recompilar. Para juegos pequeños puede parecer una chorrada pero para proyectos grandes o hechos entre varias personas, recompilar cada vez es costoso.

2.- Puedes hacer cambios en la lógica del juego EN CALIENTE sin relanzar el juego: supongamos que estás en una habitación programando lo que tiene que pasar cuando se hace una cosa determinada. Imaginate: llegar a la habitación, ver lo que quieres que pase, salir del juego, programarlo, recompilar, volver a llegar (cambiando todas las variables para hacerlo, claro), reprobar, etc. En cambio, con este sistema podrías asignar una tecla en el juego a RECARGAR el script de lógica, salir de la habitación, volver a entrar, y voila, estás jugando con la nueva lógica, no sólo sin recompilar sino sin salir del juego compilado...

3.- Las introducciones de los juegos y las cutscenes se hacen facilisimas así. Imagina una aventura gráfica donde cuando entras a ciertas habitaciones tienen que pasar ciertas cosas, imagina programarlo a mano cuando puedes hacer esto:

Código: Seleccionar todo

entro-en-templo.scp:

   ANDAR(jugador, 100,100)
   MIRAR(jugador, izquierda)
   DECIR(jugador, "nada por aqui", ROJO)
   MIRAR(jugador, derecha)
   DECIR(jugador, "nada por alli", ROJO)
   MIRAR(pantalla)
   ANIMACION(jugador, levantar_los_hombros)
   DECIR(jugador, "no parece haber nadie")
   ESPERAR(3)
   INSERTAR_PERSONAJE( enemigo, 0, 0 )
   ANDAR( enemigo, 100, 100)
   DECIR(enemigo, "AHA, te pille!", AZUL )
   (...)


4.- El motor del juego te sirve para hacer nuevos juegos, mientras lo vas ampliando. Un famoso motor de scripting es el SCUMM de las aventuras gráficas (scumm = script utility for maniac mansion), que es precisamente el motor de scripting que diseñó Lucasarts para Maniac Mansion y que fue siendo ampliado para los siguientes juegos. Con el mismo motor puedes hacer diferentes aventuras cambiando sólo la lógica del juego.


Ahora llega la parte 2, la de implementarlo en un Spectrum:

Como en los lenguajes de programación modernos (Java, C++) puedes "ejecutar" (interpretar) código en Python o LUA (lenguajes de scripting) con ciertas librerías, normalmente se programa la lógica de los juegos con esto, y no se inventan nuevos lenguajes. pero en el caso del Spectrum no es así, sino que por limitaciones de memoria se suele "compilar" el script en "código binario".

En "La Abadía del Crimen", Paco Menéndez hizo esto mismo para "codificar" en scripts qué tenía que hacer cada monje o el abad mismo, en cada momento, rollo:

Código: Seleccionar todo

SI ES LA UNA:
   Andar hacia altar

SI EN LA HABITACION ACTUAL ESTA GUILLERMO Y ES DE NOCHE:
   Perseguir guillermo

SI celdax, celday del abad == celdax, celday de guillermo Y ES DE NOCHE:
   fin del juego

(etc...)


Pero en lugar de "texto", se compilaba en bytecodes rollo:


Código: Seleccionar todo

00 01    <- 00 = comprobar hora,  01 = parametro (la 1)
  02 A0  <- 02 = andar hacia, A0 = el altar

etc...


Y esto añade la siguiente ventaja:

5.- Reducir brutalmente lo que ocupa el código, ya que cambias "montones de líneas de código" por bytecode que ocupa infinitamente menos (hay que sumar el código del intérprete y de las funciones de apoyo que has hecho).


Así que esto es lo que hace más o menos na_th_an, tener un lenguaje "en texto" que luego "compilan" a bytecode y que su motor de juego es capaz de interpretar para que cuando se acciona una palanca, ocurre un evento, se entra en una pantalla, etc, todo lo que haya que hacer venga descrito por el "lenguaje de lógica" y no por código en C o ASM metido a mano, que luego es inmantenible. De esta forma, la churrera puede ser aún más churrera porque ya no tendrán que modificar el código para hacer nuevos juegos, salvo para ampliar lo que permite hacer o corregir bugs.

Por último, os quiero dejar un enlace de cómo aplican esto en un juego "moderno":

http://www.grimrock.net/2012/07/25/maki ... ogramming/

Un saludo y disculpad por el tocho.
NoP / Compiler

sromero
Nonamed
Mensajes: 1221
Registrado: Mar Abr 17, 2007 12:35 pm
Ubicación: Valencia
Contactar:

Re: Nuevo concursos BASIC y El Hobbit Bytemaniacos

Mensaje por sromero » Mié Ene 16, 2013 2:59 pm

Vaya, mientras componía una respuesta se me ha adelantado na_th_an XD

Seguro que tiene una churrera para respuestas en el foro XD
NoP / Compiler

Avatar de Usuario
na_th_an
Nonamed
Mensajes: 1889
Registrado: Lun May 07, 2007 10:16 am
Ubicación: Andalucía

Re: Nuevo concursos BASIC y El Hobbit Bytemaniacos

Mensaje por na_th_an » Mié Ene 16, 2013 4:00 pm

Como bien comentas, esto es super interesante sobre todo en sistemas más potentes que realmente te permiten dejar tu script sin "compilar" y poder hacer pruebas "en caliente".

Por ejemplo, y aunque aún no lo haya enseñado (entre otras cosas, porque en tiempos no lo terminé y porque además he perdido parte del mismo), hice un motor de juegos tipo Phantomas en MSDOS hace años para portar mis viejos juegos hechos en BASIC de Spectrum. En este motor absolutamente todo es un script, es como si fuera un intérprete de un lenguaje para hacer Phantomas :lol: El motor lo hice y lo compilé hace siglos y me olvidé de él. Para hacer juegos nuevos sólo hay que cambiar el script. Algún día lo sacaré del baúl.

sromero
Nonamed
Mensajes: 1221
Registrado: Mar Abr 17, 2007 12:35 pm
Ubicación: Valencia
Contactar:

Re: Nuevo concursos BASIC y El Hobbit Bytemaniacos

Mensaje por sromero » Mié Ene 16, 2013 5:19 pm

Se me olvidaba añadir que scriptar la lógica del juego facilita la portabilidad a otros sistemas. En lugar de portar 1000000 líneas de código (el juego entero) sólo tienes que portar las 10000 del motor, y los mismos scripts te valen para las otras versiones. Incluso te puedes permitir cosas en un sistema que no en el otro en el motor, mientras que la lógica no tienes ni que tocarla.

Y encima cuando acabas el motor para otro sistema (Amstrad, MSX ... Android, iOS), puedes reutilizar ese motor en el futuro para otros juegos cambiando la lógica y ampliando sólo el motor :P
NoP / Compiler

Avatar de Usuario
radastan
Phantomas
Mensajes: 2232
Registrado: Lun May 07, 2007 5:34 pm
Contactar:

Re: Nuevo concursos BASIC y El Hobbit Bytemaniacos

Mensaje por radastan » Mié Ene 16, 2013 11:01 pm

Un pequeño inciso con el resultado del concurso "El Hobbit" proporcionado por la asociación Retroacción:

1º) JBGV - El Hobbit
2º) Alejandro Valero - El Hobbit
3º) Mojon Twins - El Hobbit (Vah-ka's Cut)

¡Enhorabuena a todos!
_________________________________________
Hay otras páginas.... pero no son Bytemaniacos
http://www.bytemaniacos.com
Orgullo de 8 bits
_________________________________________

Avatar de Usuario
wilco2009
Freddy Hardest
Mensajes: 543
Registrado: Lun Sep 17, 2012 9:40 am
Ubicación: Valencia

Re: Nuevo concursos BASIC y El Hobbit Bytemaniacos

Mensaje por wilco2009 » Mié Ene 16, 2013 11:32 pm

radastan escribió:Un pequeño inciso con el resultado del concurso "El Hobbit" proporcionado por la asociación Retroacción:

1º) JBGV - El Hobbit
2º) Alejandro Valero - El Hobbit
3º) Mojon Twins - El Hobbit (Vah-ka's Cut)

¡Enhorabuena a todos!

Enhorabuena a JBGV por su merecida victoria. Un excelente juego. :D
Por lo que me toca, gracias a la asociación retroaccion por ese segundo puesto. Parecerá tonto pero me hace mucha ilusión. Al fin y al cabo, es mi primer juego de Spectrum desde hace 30 años. :lol:
Enhorabuena tambien para ese magnífico juego de los mojones, que afortunadamente para los demás participantes han tenido que hacer en tan poco tiempo :wink: . Me quito el sombrero ante estos maestros.

anjuel
Manic Miner
Mensajes: 297
Registrado: Mar May 08, 2007 9:14 am
Ubicación: Torreznoslandia
Contactar:

Re: Nuevo concursos BASIC y El Hobbit Bytemaniacos

Mensaje por anjuel » Jue Ene 17, 2013 9:12 am

Enhorabuena a los premiados! :)
(_\_) (_|_) (_/_) (_|_) ILLO KE HEHEHEHEHEHEEEHEHEHEHE!!
http://www.mojontwins.com

Avatar de Usuario
JBGV
Manic Miner
Mensajes: 279
Registrado: Vie Feb 11, 2011 9:16 am

Re: Nuevo concursos BASIC y El Hobbit Bytemaniacos

Mensaje por JBGV » Jue Ene 17, 2013 9:28 am

¡¡¡ Muchas gracias !!! :D

Esto me hace mucha ilusión, y eso que al final no envié los jamones (de Teruel, por supuesto) a la Asociación Retroacción :mrgreen:

La verdad es que no me lo esperaba con el juego de Wilco y el juego de los maestros en el ajo (de los que tanto estoy aprendiendo). Creo que despues del concurso de Christmas del año 1977 que gané en el cole este es el segundo premio que recibo (en aquella ocasion me regalaron un boli bic azul y una bolsa de caramelos solano de los quita-empastes), así que mi curriculum es impresionante ya.

En serio, muchas gracias, cuando hace dos años empecé a "programar" (ejem !) juegos otra vez, fue al descubrir los concursos de Bytemaniacos y pensé en hacer uno para presentarlo si es que Radastan convocaba otro (y quitarme la espina clavada desde hacía 20 años por no haber enviado ningún programa a la revista MH :oops: )

Un saludo a todos!.

Avatar de Usuario
na_th_an
Nonamed
Mensajes: 1889
Registrado: Lun May 07, 2007 10:16 am
Ubicación: Andalucía

Re: Nuevo concursos BASIC y El Hobbit Bytemaniacos

Mensaje por na_th_an » Jue Ene 17, 2013 10:44 am

Ha ganado el más mejor :D

sromero
Nonamed
Mensajes: 1221
Registrado: Mar Abr 17, 2007 12:35 pm
Ubicación: Valencia
Contactar:

Re: Nuevo concursos BASIC y El Hobbit Bytemaniacos

Mensaje por sromero » Jue Ene 17, 2013 10:50 am

na_th_an escribió:Ha ganado el más mejor :D


Y además la humanidad no estaba preparada para encontrarse una moto en la Tierra Media :mrgreen: .
NoP / Compiler

Avatar de Usuario
na_th_an
Nonamed
Mensajes: 1889
Registrado: Lun May 07, 2007 10:16 am
Ubicación: Andalucía

Re: Nuevo concursos BASIC y El Hobbit Bytemaniacos

Mensaje por na_th_an » Jue Ene 17, 2013 10:51 am

¡Qué poca imaginación tiene la humanidad! :P

Responder

¿Quién está conectado?

Usuarios navegando por este Foro: Google [Bot] y 41 invitados