Documentación: Guía de usuario (Manual de Div Games Studio)
La información de esta guía se ha sacado del manual de Div Games Studio, por lo que todo lo que se expone aquí es compatible, no solo con Div GO sino también con otros Div-like como Gemix Studio, BennuGD o CDiv
Todos los programas deben comenzar con la palabra reservada PROGRAM seguida del nombre del programa y un símbolo ; (punto y coma). Esta cabecera es obligatoria en todos los programas.
En los nombres y las palabras reservadas no se diferencia entre mayúsculas y minúsculas, por lo que son válidas PROGRAM, program, Program, ...
Ejemplo:
Definición de comentarios:
Un comentario es una nota aclaratoria sobre el programa. Los comentarios no son necesarios para el correcto funcionamiento del programa.
Hay dos tipos de comentarios:
- De una sola línea, comienzan con el símbolo // y terminan al final de la línea en la que se definen.
- De varias líneas, comienzan con el símbolo /* y terminan con el símbolo */.
Ejemplo:
Declaración de datos globales:
GLOBAL
<declaración de dato>;
...
Esta sección de los programas es opcional; es donde se declaran los datos de ámbito global, es decir, los datos que pueden utilizarse desde cualquier punto del programa.
La sección debe comenzar obligatoriamente con la palabra reservada GLOBAL seguida de una serie de declaraciones de datos terminadas con un símbolo ; (punto y coma).
En general, se declaran como datos globales todos aquellos que establecen condiciones generales del juego que afecten a varios procesos; un ejemplo puede ser los puntos obtenidos por el jugador, que podrían almacenarse en la variable global puntuación, de modo que cualquier proceso del juego pudiera incrementarla cuando fuera necesario.
Una declaración de dato global definirá un único dato que podrá ser utilizado por todos los procesos del programa; en cambio una declaración de dato local definirá un dato de ese tipo y con ese nombre, para cada uno de los procesos del programa.
Ejemplo:
Declaración de datos locales:
LOCAL
<declaración de dato>;
...
Esta sección de los programas es opcional, ya que es donde se declaran los datos de ámbito local, es decir, los datos que tendrán todos los procesos del programa, cada uno con sus propios valores (como las variables locales predefinidas x e y determinan las coordenadas de todos los procesos).
La sección debe comenzar obligatoriamente con la palabra reservada LOCAL seguida de una serie de declaraciones de datos terminadas con un símbolo ; (punto y coma).
En general, se declaran como datos locales todos aquellos que se consideren informaciones importantes de los procesos, o sea, aquellos que pueda interesar consultar o modificar desde otros procesos.
Un ejemplo puede ser la energía que le queda a un proceso (puede ser una nave, un disparo, el protagonista, etc.); esta información podría almacenarse en la variable local energía de modo que cualquier proceso pudiera acceder o modificar la energía de los demás (por ejemplo, cuando colisionara con ellos les podría quitar energía).
Ejemplo:
Declaración de datos privados:
PRIVATE
<declaración de dato>;
...
Estas secciones de los programas son opcionales; en ellas se pueden declarar datos de ámbito privado, es decir, datos que van a ser utilizados exclusivamente dentro de un proceso.
Dicha sección se define justo antes del BEGIN del proceso que va a utilizar esos datos y debe comenzar, obligatoriamente, con la palabra reservada PRIVATE seguida de una serie de declaraciones de datos terminadas con un símbolo ; (punto y coma).
El programa principal también se considera como un proceso, pudiendo tener su declaración de datos privados justo antes del BEGIN del mismo.
En general, se declaran como datos privados todos aquellos que vayan a contener información necesaria únicamente para un proceso e, igualmente, que no van a poder ser accedidos desde ningún otro proceso.
Típicamente se definen como datos privados aquellas variables que van a ser utilizadas como contadores en un bucle, las variables para contener ángulos o códigos identificadores secundarios, etc.
Ejemplo:
Si un dato declarado como privado necesita consultarse o modificarse desde otro proceso (identificador.dato), entonces se deberá declarar dicho dato como local (dentro de la sección LOCAL del programa); de esta forma, todos los procesos poseerán el dato, pudiendo acceder cada uno a su valor o al valor que tenga dicho dato en otro proceso.
Código principal:
BEGIN
<sentencia>;
... END
El código principal de un programa comienza con la palabra reservada BEGIN, tras la cual puede aparecer cualquier número de sentencias, y finaliza con la palabra reservada END.
Este código controla el proceso principal del programa, que es el encargado de inicializar el programa, controlar los bucles de menú y de juego, y finalizar el programa.
Ejemplo:
Que finalice la ejecución del código principal no implica que finalice la ejecución del programa, pues ésta continuará si quedan procesos vivos; si se quiere forzar la terminación del programa cuando finalice este código, se puede utilizar, por ejemplo, la función let_me_alone() justo antes del END que marca el final del código principal, para eliminar al resto de procesos que puedan quedar vivos.
También se puede finalizar en cualquier punto del programa su ejecución mediante la función exit() que automáticamente eliminará todos los procesos.
Bloques PROCESS:
Existen dos tipos de bloques de código (además del código principal): los bloques PROCESS (que se detallan a continuación), y los bloques FUNCTION.
PROGRAM <nombre>;
<declaración de datos privados>; BEGIN
<sentencia>;
... END
Un proceso debe comenzar con la palabra reservada PROCESS seguida de su nombre y sus parámetros de llamada entre paréntesis. Los parámetros son una lista de datos en los que el proceso va a recibir diferentes valores. Los paréntesis son obligatorios incluso cuando el proceso no tenga parámetros.
Tras esta cabecera puede venir, de forma opcional, una sección PRIVATE donde se declaren datos que va a utilizar exclusivamente el proceso.
Y, por último, se especificará el código para el proceso, que es una secuencia de sentencias entre las palabras reservadas BEGIN y END.
Un proceso se corresponde, normalmente, con un tipo de objeto del juego, como puede ser una nave, una explosion, un disparo, etc., y dentro del código del proceso se suele implementar un bucle dentro del cual se fijarán todos los valores necesarios de visualización de dicho objeto (gráfico, coordenadas, etc.) y después, mediante la sentencia FRAME, se dará la orden para visualizar el objeto con los atributos establecidos.
Ejemplo:
Como se puede observar en este ejemplo, cuando se llama a un proceso éste devuelve su código identificador (que en el ejemplo se guarda en la variable PRIVATE del programa principal id2); si se quiere implementar un proceso al estilo de las funciones de otros lenguajes, que devuelva un resultado numérico, entonces se debe utilizar la sentencia RETURN(valor) y no utilizar la sentencia FRAME dentro del proceso, pues ésta retorna al proceso padre (llamante), devolviendo el código identificador del proceso como valor de retorno.
Bloques FUNCTION:
Los bloques FUNCTION se comportan de forma análoga a las funciones de otros lenguajes de programación, se ejecutan de forma secuencial (y no en paralelo como los bloques PROCESS), no retornando hasta que no han terminado.
FUNCTION <nombre>;
<declaración de datos privados>; BEGIN
<sentencia>;
... END
Estos bloques seguirán funcionando de forma muy similar a los procesos normales, pero con una importante diferencia: detendrán al proceso llamador hasta finalizar, es decir, que estas funciones dormirán al proceso que las ha llamado, hasta que estas funciones retornen o su proceso finalice.
Si la función no utiliza sentencias FRAME, se comportará igual que un proceso normal, pero si una función ejecuta la sentencia FRAME, no volverá al bloque que la llamó (como lo haría un proceso normal).
Por lo tanto, una función siempre puede devolver un valor con RETURN(<expresión>), incluso después de haber dado uno o varios FRAME.
Programación secuencial.
No se recomienda programar sólo con funciones y de forma secuencial, pero el conocer cómo se puede hacer facilitará el entendimiento de la programación DIV a programadores de otros lenguajes.
Es posible hacer un programa al estilo de la programación tradicional utilizando exclusivamente los bloques FUNCTION, de esta forma únicamente habrá un proceso en ejecución en cada momento.
Al programar de esta forma, la sentencia FRAME se convierte en la orden explícita de volcado a vídeo. Logicamente, si sólo hay un proceso ejecutándose, cuando este ejecute esta orden el sistema mostrará la siguiente imagen del programa.
Pero, programando asi, ¿se podrían mostrar varios gráficos en pantalla?.
La respuesta es sí, ya que se podrían crear una especie de mini-procesos que funcionaran como una instrucción del estilo "pinta un gráfico para la siguiente imagen" (a diferencia de las funciones como put(), que pintan un gráfico para siempre).
Para mostrar un gráfico en la siguiente imagen se debe construir un proceso que reciba los parámetros visuales necesarios y simplemente ejecute una única sentencia FRAME, por ejemplo:
PROCESS pinta_gráfico(x,y,graph)
BEGIN
FRAME;
END
Al llamar a este proceso se crearía un proceso temporal que se pintaría en la siguiente imagen y entonces desaparecería. Podrían contemplarse otros parámetros (además de x, y, z), como file, size, angle, z, ... (ver los datos locales predefinidos).
Claro que, al programar de esta forma, se debería crear (normalmente en una estructura global) una tabla de sprites de forma que el programa pudiera gestionar todos los gráficos. Esto, que puede parecer complicado, es la forma natural de programar los juegos en cualquier otro lenguaje que no sea DIV.
Aplicaciones en el programa principal.
Las sentencias que aparecen entre las palabras BEGIN y END del programa principal (tras las declaraciones de datos), controlan el proceso principal del programa. Este es el encargado de inicializar el programa, realizar las presentaciones, controlar los bucles de menú, los bucles de juego (creando los procesos necesarios), y finalizar el programa.
En el programa principal, puede ser muy útil llamar a bloques FUNCTION. Ya que de esta forma será detenido el programa principal mientras se ejecuta la parte que controla dicha función.
Por ejemplo, la secuencia de presentación podría hacerse en una función, el menú de opciones en otra, etc. Además, se recuerda que las funciones pueden al finalizar, devolver siempre un valor con RETURN(<expresión>), lo cual puede ser también útil para que, por ejemplo el menú, devuelva el número de opción que ha sido seleccionada.
Nota: Que finalice la ejecución del código principal no implica que finalice la ejecución del programa, pues ésta continuará si quedan procesos vivos; si se quiere forzar la terminación del programa cuando finalice este código, se puede utilizar, por ejemplo, la función let_me_alone() justo antes del END del código principal, o bien la función exit() (en cualquier punto del programa).
Sentencia CLONE:
CLONE
<sentencia>;
... END
Esta sentencia crea un nuevo proceso idéntico al actual, con la salvedad de que las sentencias entre las palabras reservadas CLONE y END se ejecutarán únicamente en el nuevo proceso y no en el actual.
Por ejemplo, si cualquier proceso del programa, con unas coordenadas (x, y) determinadas y un gráfico (graph) concreto, ejecuta la siguiente sentencia:
CLONE
x=x+100; END
Se creará un nuevo proceso identico a él, con el mismo gráfico y los mismos valores en todas sus variables, a excepción de la coordenada x, que el nuevo proceso tendrá 100 puntos más a la derecha.
Esta sentencia se utiliza para crear réplicas de un proceso, dividirlo en dos procesos (casi) iguales.
Ejemplo:
En este ejemplo, las 2 sentencias CLONE crearán 3 copias del proceso principal (y no 2, como podría haberse esperado).
Al ejecutarse la primera sentencia CLONE se creará un nuevo proceso, con lo que habrá 2: uno en (x=0, y=0) y otro en (x=10, y=0). Y estos dos procesos ejecutarán la segunda sentencia CLONE, el primero (el original) creando con ello un nuevo proceso en (x=0, y=10), y el segundo creará el nuevo proceso en (x=10, y=10).
Para crearse únicamente 2 copias del proceso original se podría haber construido el programa, por ejemplo, de la siguiente forma:
Ejemplo:
El proceso original (x=0, y=0) creará uno en (x=10, y=0) y éste, a su vez, otro en (x=10, y=10), creandose únicamente dos copias del original.
Se debe, por tanto, tener mucho cuidado con el uso de la sentencia CLONE de forma secuencial o dentro de un bucle, pues se debe contar con que los primeros 'clones' pueden crear, a su vez, a nuevos 'clones'.
Esta sentencia permite usarse sin poner sentencias entre las palabras CLONE y END. Pero, al menos en un principio, no parece tener mucho sentido el querer tener dos procesos idénticos, con las mismas coordenadas, el mismo gráfico y ejecutando el mismo código.