Autor Tema: GML  (Leído 1297 veces)

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

Desconectado empardopo

  • Admin
  • *
  • Mensajes: 21739
  • Gracias 761
  • Espero mejorar al KungFu Master!
    • Mi canal de Youtube
  • Ciudad: Norte de África
  • Pais: Escoña
  • Iniciales nick: EPP
GML
« en: Agosto 05, 2018, 04:45:17 pm »
Advertisement
¿Qué es GML?
Son las siglas de GameMaker Language o dicho en español, el lenguaje de programación de GameMaker. Como comentaba en otro post, GameMaker permite hacer juegos con el sistema Drag and Drop, es decir, arrastrar y soltar unas cajitas que luego podemos configurar pero usándolas no obtenemos la mejor potencia de GameMaker la cual podremos conseguir usando GML.

GML or GameMaker Language es una gran herramienta que expande aún más la variedad de herramientas suministradas por GameMaker. Los scripts de GML permiten a los programadores escribir su propio código, creando un código más organizado y que será más fácil de modificar e incluso de buscar errores que usando la funcionalidad de D&D.
Antes de explorar el uso de GML creando juegos, vamos a ver los componentes básicos del lenguaje:

• Syntax and formatting (sintaxis y formato)
• Variables (variables)
• Functions (funciones)
• Statements (Sentencias)
• Arrays (Arreglos)

Lo primero es tener claro dónde podremos crear los scripts de GML en GameMaker.
Creando scripts de GML dentro de un evento
Dentro de un objeto, cada uno de los eventos añadidos podrán contener un script o una llamada a uno. Para añadir un script a un evento dentro del objeto, iremos a la pestaña control del menú de las propiedades del objeto que está siendo editado.
Bajo la etiqueda Code, los primeros 2 iconos se refieren a los scripts.
En el siguiente pantallazo, el icono más a la izquierda, el cual parece como un trozo de papel, creará un script; el icono central (el que está a la derecha del anterior), el cual parece como un trozo de papel con una flecha verde, nos permitirá seleccionar un script para luego ser ejecutado durante el evento.
Creando scripts dentro de eventos es más útil cuando los scripts dentro de estos eventos ejecutan acciones que son muy específicas a las instancias de los objetos que están lanzando el evento.

Necesitas estar registrado en el foro y llevar 400 posts para poder ver links.

Creando scripts como recursos
Si nos vamos en la parte izquierda de GameMaker a Resources - Create Script o usando el atajo de teclado Ctrl + Shift + C crearemos un script. Una vez creado, un nuevo script debería aparecer bajo la carpeta de Scripts en el lado izquierdo de nuestro proyecto donde están colocados los recursos.
Crear un script como un recurso es los más útil en las siguientes condiciones:

• Cuando muchos objetos diferentes utilizan esta funcionalidad
• Cuando una función requiere múltiples valores o argumentos
• Cuando acciones globales tales como salvar o cargar son usadas
• Cuando implementan una lógica compleja y algoritmos

Creamos el creation code de una room
Los recursos room son recursos específicos donde los objetos son colocados y el juego discurre. Los recursos room pueden ser creados en Resources - Create Room o usando el atajo Ctrl + Shift + R.
Las rooms pueden tambien contener scripts. Cuando editando una room, nos vamos a la pestaña settings dentro del panel de propiedades de la room, se puede ver un botón llamado Creation code como podemos ver en el siguiente pantallazo.

Necesitas estar registrado en el foro y llevar 400 posts para poder ver links.

Cuando clicamos en él, esto abrirá un script en blanco. Este script será ejecutado tan pronto como la room sea cargada, antes incluso de que ninguno de los objetos lanzen sus propios eventos. Usar el Creation code es esencialmente lo mismo como tener un script en el evento Create de un objeto.

Comprendiendo las partes de los scripts de GML
Los scripts de GML están compuestos de muchas y diferentes partes. Vamos a ver estas partes incluyendo su uso.

Programas
Un programa es un conjunto de instrucciones que están seguidas en un orden específico. Una forma de pensar, es que todo script escrito en GML es esencialmente un programa.
Los programas en GML son normalmente encerrados dentro de llaves, { }, como mostramos en el siguiente ejemplo.
Código: [Seleccionar]
{
// Defines an instanced string variable.
str_text = "Hello Word";
// Every frame, 10 units are added to x, a built-in variable.
x += 10;
// If x is greater than 200 units, the string changes.
if (x > 200)
{
str_text = "Hello Mars";
}
}
El ejemplo de código anterior contiene dos expresiones de asignación seguidas por una sentencia condicional, seguida por otra expresión de asignación.
Realmente, las primeras llaves que encierran todo el script no serían estrictamente necesarias.
Podemos ver que cada línea de código termina con un punto y coma (;). Esto no es requerido y sería suficiente con un retorno de carro, pero el punto y como es usado en otro lenguajes de programación para indicar el final de una instrucción y usarlo es un buen hábito para mejorar la mejor lectura de nuestro código.

Examinando un poquito el código anterior podemos apreciar un par de detalles más que viene bien ir ya conociendo:

Las líneas que empiezan por // son consideradas como comentarios.
Otro detalle es que estamos usando lo denominado snake_case y no es otra cosa que como una especie de convenio para que cuando definamos variables lo hagamos sin usar mayúsculas y separando las palabras del nombre que definen el nombre de la variable con guiones bajos como podemos ver en la definición de la variable str_text

Variables
Las variables son las principales unidades de trabajo en los scripts de GML, las cuales son usadas para representar valores. Las variables en GML no son estrictamente tipadas, lo cual quiere decir que no tienen que representar a una específica estrucutura de datos. Por el contrario, las variables pueden representar cualquiera de los siguientes tipos:

• Un número también conocido como real, tales como 100 or 2.057. Los enteros pueden también corresponder a una instancia particular de un objeto, una room, un script o cualquier otro tipo de recurso.
• Una cadena que representa una colección de caracteres alfanuméricos normalmente usados para mostrar texto los cuales podrán ir dentro de comillas simples o dobles, como por ejemplo "Hello World".

En definitiva lo que queremos decir es que en GML no hace falta como en otros lenguajes definir un tipo para una variable sino que cualquier variable la podremos usar para definir cualquier tipo de datos aunque claro está, si nos equivocamos luego del dato a meter lo mismo es más complicado encontrar el error donde está que en otro lenguaje de programación donde el propio IDE podría avisarnos...

Prefijos de las variables
Como mencionamos antes, a la misma variable le puede ser asignado cualquier tipo de valor, lo cual puede causar problemas. Para intentar combatir esto, los prefijos en los nombres de las variables ayudan a recordar/identificar el tipo de dato almacenado en dicha variable. Los siguientes son los prefijos mas comunes:

• str: String
• spr: Sprites
• snd: Sounds
• bg: Backgrounds
• pth: Paths
• scr: Scripts
• fnt: Fonts
• tml: Timeline
• obj: Object
• rm: Room
• ps: Particle System
• pe: Particle Emitter
• pt: Particle Type
• ev: Event

Los nombres de las variables no pueden comenzar con números ni otros carácteres no alfanuméricos, por lo que lo mejor es usar letras normales.

Variable scope o ámbito o alcance de las variables
Dentro de los scripts de GML, las variables tienen diferentes alcances. Esto quire decir que la forma en la que los valores de las variables son colocados y accedidos varia. Los siguientes son los diferentes alcances:

• Instance o instancia: Estas variables son únicas para las instancias o copias de cada objeto. Ellas pueden ser accedidas o configuradas por ellas mismas o por otros objetos del juego y son las variables más comunes en GML.

• Local o locales: Las variables locales son esas que existen sólo dentro de una función o script. Ellas son declaradas usando la palabra clave var y pueden ser accedidas sólo dentro de los scripts en los que ellas han sido creadas.

• Global o globales: Una variable que es global puede ser accedida por cualquier objeto a traves de scripts. Pertenece al juego y no a una instancia de objeto individual. No puede haber más de una variable global con el mismo nombre.

• Constants o constantes: Las constantes son variables de las que sus valores sólo pueden ser leídos y no cambiados. Ellas podrán ser variables de instancias o globales. Constantes instanciadas son por ejemplo, object_index or sprite_width. Las variables true y false son ejemplos de constantes globales. Adicionalmente, cualquier recurso creado se podría pensar como una contante global representando su ID y deshabilitando la posibilidad de asignarle un nuevo valor.

Los siguientes ejemplos muestran la asignación de diferentes tipos de variables:

Código: [Seleccionar]
// Local variable assignment.
var a = 1;
// Global variable declaration and assignment.
globalvar b;
b = 2;
// Alternate global variable declaration and assignment.
global.c = 10;
// Instanced variable assignment through the use of "self".
self.x = 10;
/* Instanced variable assignment without the use of "self". Works
identically to using "self". */
y = 10;

Variables incorporadas en Gamemaker
Algunas variables tanto globales como instanciadas ya vienen suministradas en GameMaker Studio para cada juego u objeto. Variables tales como, x, sprite_index e image_speed son ejemplos de variables instanciadas que ya vienen "predefinidas" en GM. Mientras tanto, también hay variables globales tales como health, score y lives. El uso de estas en un juego es cuestión de preferencia personal, pero sus apropiados nombres hacen más fácil recordarlas.
Cuando cualquiera de estas variables ya incorporadas es usada en un script, aparecerán en un color diferente, siendo por defecto un color rosado. Todas estas variables están documentadas en la ayuda de Gamemaker.

Creando constantes personalizadas
Las constantes personalizadas pueden ser definidas yendo a Resources - Define Constants o presionando Ctrl + Shift + N. En la pantalla que aparecerá, en la primera columna se soloca el nombre de la variable y en la segunda se coloca el valor. Por defecto, las constantes aparecerán en el código GML en el mismo color rosado comentado anteriormente. Dejo a continuación un pantallazo con algunas constantes de ejemplo:

Necesitas estar registrado en el foro y llevar 400 posts para poder ver links.

Funciones y acceso a recursos de script
Una función es una sentencia que ejecuta un programa; están tanto integradas en GML como creadas como un recurso script. Las funciones pueden tanto ejecutar una acción como cambiar la alineación de un font durante un evento Draw, devolver un valor o hacer ambas.
Las funciones tienen que ser seguidas por paréntesis —( )— para ejecutarse propiamente. Otro importante aspecto de las funciones son los argumentos. Estos se separan por comas y pueden ser cadanas, enteros, objetos, etc siendo accesibles a las funciones cuando se ejecutan. Si no hay argumentos los parénteis se colocan igualmente pero vacíos.
Los siguientes son ejemplos de funciones con y sin argumentos:

Código: [Seleccionar]
// Executes an action, in this case, drawing the instance.
draw_self();
/* Executes an action which requires arguments, in this case, drawing an arrow. */
draw_arrow(0,0,100,100,2);
// Obtains a random value between two provided values.
random_value = random(10, 23);

GameMaker: Studio suministra una amplia variedad de funciones que podremos encontrar en la ayuda.

Los scripts creados como recursos pueden ser accedidos usando dos métodos. Ya sea referenciando el nombre del script creado y usado como si fuera una función de las incorporadas en GML o bien usando la función script_execute como mostramos en el siguiente ejemplo de código:

Código: [Seleccionar]
// Executes the script directly like a built-in function.
scr_script_resource("argument", obj_button, 0.12, false);
/* Executes the same script as the previous line but through the use of "script_execute". */
script_execute(scr_script_resource, "argument", obj_button, 0.12,false);

La ventaja del uso de script_execute es que permite la asignación de un script a una variable para ser usada como se puede ver en el siguiente código:

Código: [Seleccionar]
// Assigns an instanced variable with the script resource's index.
self.script = scr_script_resource;
// Executes the assigned script.
script_execute(self.script, "argument", obj_button, 0.12, false);

La función script_execute puede sólo ser usada en scripts creados como recursos;adicionalmente, variables no pueden ser asignadas a funciones incorporadas. El siguiente código muestra esta problemática:

Código: [Seleccionar]
// Assigns an instanced variable with a script resource ID.
self.script = scr_script_resource;
// Calling the instanced variable will cause a compile error.
self.script("argument", obj_button, 0.12, false);

Argumentos
Como mencionamos anteriormente, algunas funciones requieren argumentos. Cuando creamos un script, estos argumentos pueden ser accedidos dentro del script usando las palabras clave argument0 hasta argument15, permitiendo hasta 16 valores diferentes si fuera necesario.

Expresiones
Las expresiones representan valores normalmente almacenados en variables o evaluados por una sentencia condicional, la caul será explicada más tarde. Ellas pueden ser números reales tales como 3.4; números hexadecimales comenzando con el signo $, tal como $00FFCC (normalmente usado para representar un color en RGB); y cadenas las cuales están creadas encerrándolas con comillas simples o dobles, por ejemplo 'hello' o "hello".

Símbolos de expresión
Las expresiones pueden ser manipuladas y evaluadas usando diferentes símbolos. El signo de giual u operador de asignación = asigna el valor de una variable como es mostrado en el siguiente código:

Código: [Seleccionar]
// Assigning a variable with a value.
a = 10;
/* Assigning a different variable with an expression, in this case,
the sum of the previously declared variable and 7.5. */
b = (a + 7.5);

Las expresiones pueden también ser combinadas con operaciones básicas de matemáticas como se ve en el siguiente código:

Código: [Seleccionar]
// Addition and subtraction, + and -
val = a + 20 - b;
// Multiplication and division, * and /
val = a * 20 / b;
/* Expressions encased in parenthesis, ( and ), will be evaluated
first. */
val = (a + 20) * (b - 40);
// + can also be used to concatenate, or link, strings together.
str = "hello " + "world";

Las operaciones matemáticas pueden ser combinadas con = para crear un operador de asignación compuesto y ejecutar una suma, resta, multiplicación o división relativa como se aprecia en el siguiente código:

Código: [Seleccionar]
// Relative addition, +=
x += y; // equivalent to x = x + y;
// Relative subtraction, -=
x -= y; // equivalent to x = x – y;
// Relative multiplication, *=
x *= y; // equivalent to x = x * y;
// Relative division, /=
x /= y; // equivalent to x = x / y;

La principal ventaja de este código es su extreme simplicidad. En los ejemplos previos, x es una simple variable a escribir, pero si el nombre de la variable fuera más largo, el código anterior se acorta no teniendo que reescribir de forma innecesaria el nombre de la variable a ambos lados del operador de asignación.
Las variables pueden tambien ser incrementedas por un valor como se ve en el siguiente código:

Código: [Seleccionar]
var a, b, c, d, str_a, str_b, str_c, str_d;
a = 1;
b = 1;
c = 1;
d = 1;
// The return string will be "1" but a's value is now 2.
str_a = string(a++);
// The return string will be "2" and b's value is 2.
str_b = string(++b);
// The return string will be "1" but c's value is 0;
str_c = string(c--);
// The return string will be "0" and d's value is 0;
str_d = string(--d);

En resumen, si ++ o -- es incluido después de la variable, primero se devuelve el valor actual de la variable y luego es incrementada. Si ++ o -- es colocado antes de la variable, primero se incrementa el valor actual de la variable y luego el nuevo valor es devuelto.

Comparaciones booleanas, como se muestran en el siguiente código, comparan expresiones y devuelven los valores true o false, las cuales son constantes GML igual a 1 y 0 respectivamente:

Código: [Seleccionar]
// Less than, <
if (a < 20) { instance_create(a, 20, obj_ball); }
// Less than or equals to, <=
if (a <= 20) { instance_create(a, 20, obj_ball); }
// Equals to, ==
if (a == 20) { instance_create(a, 20, obj_ball); }
// Not equals to, !=
if (a != 20) { instance_create(a, 20, obj_ball); }
// Greater than, >
if (a > 20) { instance_create(a, 20, obj_ball); }
// Greater than or equals to, >=
if (a >= 20) { instance_create(a, 20, obj_ball); }

Los booleanos pueden ser también combinados para evaluación como se puede apreciar en el siguiente código:

Código: [Seleccionar]
// And, &&, will return true if both booleans are also true.
if (a == 20 && b == 40) { val = "and"; }
/* Or, ||, will return true if at least one of the booleans is true.
*/
if (a == 20 || b == 40) { val = "or"; }
/* xor, ^^, will return true if one booleans is true and the other
false. */
if (a == 20 ^^ b == 40) { val = "xor"; }

Sentencias condicionales
Las declaraciones condicionales utilizan una expresión booleana dentro del programa correspondiente. Si el valor devuelto es true, el programa ejecutará la sentencia que sigue a la condición; en caso contrario será saltada. Hay varios tipos de declaraciones condicionales en GML y cada una de las cuales tiene su propio uso.

if, else, y switch
La declaración if es probablemente la declaración condicional más común y que usaremos bastante haciendo juegos. La declaración if fue introducida cuando vimos anteriormente los booleanos; el siguiente códido ilustra el uso de una simple declaración if:

Código: [Seleccionar]
/* If the value of a is greater than the value of b, a is returned;
otherwise, b is returned. */
if (a > b)
{
return a;
}
else
{
return b;
}

En el ejemplo anterior, asumimos que tanto a como b son números reales; si el valor de a es mayor que el de b, a es devuelto; en caso contrario devolverá b. Una cosa que deberíamos ver aquí es que el valor b será devuelto si b es menor o igual que a, ya que es lo contrario de mayor que... (creo que esto se ve claro, no?)

Y qué hacemos si una variable necesita ser comparada con muchos diferentes valores?
Podríamos hacer como en el siguiente código:

Código: [Seleccionar]
/* Assigns the temperature of an object based on a color with multiple
if-else-statements. */
if (color == c_green || color == c_purple || color == c_blue)
{
temperature = "cool";
}
else if (color == c_red || color == c_orange || c == c_yellow)
{
temperature ="warm";
}
else if (color == c_black || color == c_gray || color == c_white)
{
temperature ="neutral";
}
else
{
temperature ="other";
}


Cuando necesitamos como en el caso anterior realizar demasiadas comparaciones, el programa a realizar puede volverse bastante tedioso y confuso. En vez de usar tantas declaraciones if-else, podríamos usar una declaración switch.
Una declaración switch es creada con las palabras clave switch, case, break y default, como podemos ver en el siguiente código:

Código: [Seleccionar]
/* Assigns the temperature of an object based on a color with a switch statement. */
switch (color)
{
    case c_red:
    case c_orange:
    case c_yellow:
          temperature = "warm";
          break;
    case c_green:
    case c_blue:
    case c_purple:
         temperature ="cool";
         break;
    case c_black:
    case c_white:
    case c_gray:
        temperature = "neutral";
        break;
    default:
       temperature = "other";
       break;
}

Esta declaración switch es idéntica a la declaración if-ese que creamos justo antes. Cada declaración case está esencialmente testeando si ese valor es igual o no al de la variable suministrada al switch. Si los valores son iguales, el programa se ejecuta. Cada case o grupo de case terminará con un break para que en el caso de que se ejecute dicho case, sepa donde parar.
Además, si no se cumpliera la condición con ningún case, pondremos un default que precisamente indica lo que habría que hacer en caso de que la variable no tomara ninguno de los valores comprobados con los case.

repeat, while, do, and for
Las declaraciones repeat, while, do, y for son todas ejemplos de sentencias que ejecutan una parte del código múltiples veces y esto es frecuentemente conocido como un loop o bucle en castellano.
La declaración repeat es usada para ejecutar el mismo trozo de programa un número especificado de veces:

Código: [Seleccionar]
// Creates 10 buttons at random positions between 0 and 100.
repeat (10)
{
instance_create(random(100), random(100), obj_button)
}

El código anterior creará 10 instancias del obj_button en posiciones aleatorias.
Código: [Seleccionar]
x = 0
repeat(3)
{
  x +=1;
}

El repeat sólo repetirá lo que haya entre las llaves así que en el código anterior la variable x empieza teniendo el valor 0; el bucle consiste en sumar 1 a x cada vez que se repite lo cual hará tres veces por lo que al final del bucle, el valor de x será 3, seguro? A qué esperáis para comprobarlo por ustedes mismo? :-)

La declaración while ejecutará el código mientras la condición se cumpla:

Código: [Seleccionar]
// Reduces x by 10 until it is no longer greater than 100.
while (x > 100)
{
x -= 10;
}

En el código anterior, el valor de x será reducido en 10 cada vez hasta que x llegue a ser inferior a 100.

La declaración do es muy similar a while, excepto que requieren una adicional palabra clave denominada until (sería el equivalente a lo que en otros lenguajes de programación sería el repeat-until):

Código: [Seleccionar]
/* Initially reduces x by 10 but continues until x is less than or equal to 100. */
do
{
x -= 10;
}
until (x <= 100);

La diferencia entre do y while es sutil. En una sentencia do, el código es ejecutado primero y luego es chequeada la condición mientras que en una sentencia while, la condición es chequeda antes de la ejecución del código. Es decir, en el primer caso al menos y siempre se ejecutará una vez mientras que en el while dependerá si inicialmente se cumplía la condición o no.

Las sentencias for o bucles for tienen condiciones incorporadas como vemos en el siguiente código:

Código: [Seleccionar]
// Declares a local variable.
var i;
/* 10 buttons are created, evenly spaced apart horizontally by 100 units with an initial offset of 25. */
for (i = 0; i < 10; i++)
{
    instance_create(i * 100 + 25, 25, obj_button)
}

La primera declaración despues de la palabra clave for, coloca la variable i al valor de 0. Luego, viene la condición de si el valor de i es inferior a 10 y si lo es, el bloque de código dentro del bucle será ejecutado.El valor de la variable i es luego incrementado y se chequea de nuevo dentro de la sentencia condicional, ejecutando de nuevo el código si es todavía válido, es decir, si el valor de i sigue siendo inferior a 10. La diferencia importante es que i es incrementado por la declaración, haciendo esto una buena forma para recorrer los valores de un array de una o dos dimensiones, lo cual veremos más adelante. El siguiente código ilustra esta funcionalidad con un array bidimensional:

Código: [Seleccionar]
// Creates two local variables.
var i,j;
/* This is an example of a nested for loop in which a 10 by 10 grid
with values ranging from 0 to 99 will be created. */
for (i = 0; i < 10; i++)
{
   for (j = 0; j < 10; j++)
   {
       grid[i,j] = i + j * 10;
   }
}

El siguiente código muestra la misma funcionalidad que el anterior pero usando declaraciones repeat:

Código: [Seleccionar]
// Creates local variable and then assigns their values to 0.
var i, j;
i = 0;
j = 0;
/* Repeat functionality is performed 10 times and 10 more times within
each repeat-statement. */
repeat (10)
{
   repeat(10)
  {
     // assign the grid value
     grid[i,j] = i + j * 10;
     // increment after each inner repeat.
     j++;
   }
   // increment after each outer repeat.
   i++;
}

Como demostramos, una declaración for es mucho más clara que una declaración repeat en casos como estos.

Antes de pasar a lo siguiente, debemos ser conscientes que las declaraciones repeat, while, do y for pueden crear una situación conocida como "bucle infinito". Los bucles infinitos son muy peligrosos y causan que un juego o programa se bloquee o congele, ignorando las entradas del usuario y forzándolo a quitar/cerrar el programa. Los siguientes son algunos ejemplos de declaraciones que pueden causar esto; no las uses en tus códigos porque son ejemplos de lo que no habría que hacer:

Código: [Seleccionar]
/* Since the condition in the while-statement is always true, it will never terminate. */
while (true)
{
   x += 1;
}
// Declares a local variable.
var i;
/* This for-statement will never end since i will never be less than 0. */
for (i = 0; i >= 0; i++)
{
   x += i;
}

Break, continue, y return
Como mencionamos anteriormente, las declaraciones de bucles pueden a veces causar una situación en la que ellos no terminan. Hay dos formas de resolver este problema. Una es conocida como break, la cual fue ya mostrada en la declaración switch para terminar cada declaración case, pero también puede ser usada para romper o terminar un bucle. El siguiente es un ejemplo de declaración break:
Código: [Seleccionar]
// local variable used in the for loop
var i;
/* Iterates through 1000 enemies. At the first undefined enemy, the
loop is exited, otherwise, the enemy moves by a random value between 1
and 10 horizontally. */
for (i = 0; i < 1000; i++)
{
   if (enemies[i] == noone)
   {
      break;
   }
   enemies[i].x += random_range(1,10);
}

En el código de ejemplo anterior, la declaración for es terminada y no continua ejecutándose una vez que la condición interna es encontrada. Supongamos que el break fuera reemplazado por continue, como mostramos en el siguiente código:

Código: [Seleccionar]
// local variable for for loop
var i;
/* Iterates through 1000 enemies. If an undefined enemy is
encountered, the remaining enemies are still checked; otherwise, the
enemy is moved by a random value between 1 and 10 horizontally. */
for (i = 0; i < 1000; i++)
{
   if (enemies[i] == noone)
   {
      continue;
   }
      enemies[i].x += random_range(1,10);
}

La declaración for procedería a comprobar todos los enemigos incluso si todos ellos estuvieran "indefinidos". Las declaraciones break y continue, sin embargo son muy útiles porque en ambos ejemplos, un enemigo indefinido va a ser encontrado y el juego se bloqueará al intentar agregar el valor generado por rango_aleatorio a su valor x. Las declaraciones return son usadas muy frecuentemente en los scripts GML que son creados como recursos. La declaración return no sólo finaliza cualquier script en su totalidad sino que también devuelve el valor que le sigue como podemos ver en el siguiente código:
Código: [Seleccionar]
// This script will simply add and multiply two arguments
var result;
result = (argument0 + argument1) * (argument0 * argument1);
return result;

Si quieres obtener un valor usando la función mostrada anteriormente, puede ser accedida a traves del siguiente código, asumiendo que la función scr_add_multipy es un recurdo script:

Código: [Seleccionar]
// Execute the method and assign it to x.
x = scr_add_multiply(1, 2);
« Última modificación: Agosto 16, 2018, 02:06:52 pm por empardopo »



Desconectado empardopo

  • Admin
  • *
  • Mensajes: 21739
  • Gracias 761
  • Espero mejorar al KungFu Master!
    • Mi canal de Youtube
  • Ciudad: Norte de África
  • Pais: Escoña
  • Iniciales nick: EPP
Re:GML
« Respuesta #1 en: Agosto 05, 2018, 04:45:28 pm »
< reservado >

Desconectado empardopo

  • Admin
  • *
  • Mensajes: 21739
  • Gracias 761
  • Espero mejorar al KungFu Master!
    • Mi canal de Youtube
  • Ciudad: Norte de África
  • Pais: Escoña
  • Iniciales nick: EPP
Re:GML
« Respuesta #2 en: Agosto 05, 2018, 04:45:39 pm »
< reservado >

Desconectado empardopo

  • Admin
  • *
  • Mensajes: 21739
  • Gracias 761
  • Espero mejorar al KungFu Master!
    • Mi canal de Youtube
  • Ciudad: Norte de África
  • Pais: Escoña
  • Iniciales nick: EPP
Re:GML
« Respuesta #3 en: Agosto 07, 2018, 01:58:32 pm »
Seguimos un poquitín con el tuto de GML...

Creando constantes personalizadas
Las constantes personalizadas pueden ser definidas yendo a Resources - Define Constants o presionando Ctrl + Shift + N. En la pantalla que aparecerá, en la primera columna se soloca el nombre de la variable y en la segunda se coloca el valor. Por defecto, las constantes aparecerán en el código GML en el mismo color rosado comentado anteriormente. Dejo a continuación un pantallazo con algunas constantes de ejemplo:

Necesitas estar registrado en el foro y llevar 400 posts para poder ver links.

Desconectado empardopo

  • Admin
  • *
  • Mensajes: 21739
  • Gracias 761
  • Espero mejorar al KungFu Master!
    • Mi canal de Youtube
  • Ciudad: Norte de África
  • Pais: Escoña
  • Iniciales nick: EPP
Re:GML
« Respuesta #4 en: Agosto 07, 2018, 06:49:04 pm »
Funciones y acceso a recursos de script
Una función es una sentencia que ejecuta un programa; están tanto integradas en GML como creadas como un recurso script. Las funciones pueden tanto ejecutar una acción como cambiar la alineación de un font durante un evento Draw, devolver un valor o hacer ambas.
Las funciones tienen que ser seguidas por paréntesis —( )— para ejecutarse propiamente. Otro importante aspecto de las funciones son los argumentos. Estos se separan por comas y pueden ser cadanas, enteros, objetos, etc siendo accesibles a las funciones cuando se ejecutan. Si no hay argumentos los parénteis se colocan igualmente pero vacíos.
Los siguientes son ejemplos de funciones con y sin argumentos:

Código: [Seleccionar]
// Executes an action, in this case, drawing the instance.
draw_self();
/* Executes an action which requires arguments, in this case, drawing an arrow. */
draw_arrow(0,0,100,100,2);
// Obtains a random value between two provided values.
random_value = random(10, 23);

GameMaker: Studio suministra una amplia variedad de funciones que podremos encontrar en la ayuda.

Los scripts creados como recursos pueden ser accedidos usando dos métodos. Ya sea referenciando el nombre del script creado y usado como si fuera una función de las incorporadas en GML o bien usando la función script_execute como mostramos en el siguiente ejemplo de código:

Código: [Seleccionar]
// Executes the script directly like a built-in function.
scr_script_resource("argument", obj_button, 0.12, false);
/* Executes the same script as the previous line but through the use of "script_execute". */
script_execute(scr_script_resource, "argument", obj_button, 0.12,false);

La ventaja del uso de script_execute es que permite la asignación de un script a una variable para ser usada como se puede ver en el siguiente código:

Código: [Seleccionar]
// Assigns an instanced variable with the script resource's index.
self.script = scr_script_resource;
// Executes the assigned script.
script_execute(self.script, "argument", obj_button, 0.12, false);

La función script_execute puede sólo ser usada en scripts creados como recursos;adicionalmente, variables no pueden ser asignadas a funciones incorporadas. El siguiente código muestra esta problemática:

Código: [Seleccionar]
// Assigns an instanced variable with a script resource ID.
self.script = scr_script_resource;
// Calling the instanced variable will cause a compile error.
self.script("argument", obj_button, 0.12, false);

Argumentos
Como mencionamos anteriormente, algunas funciones requieren argumentos. Cuando creamos un script, estos argumentos pueden ser accedidos dentro del script usando las palabras clave argument0 hasta argument15, permitiendo hasta 16 valores diferentes si fuera necesario.
« Última modificación: Agosto 07, 2018, 07:01:56 pm por empardopo »

Desconectado empardopo

  • Admin
  • *
  • Mensajes: 21739
  • Gracias 761
  • Espero mejorar al KungFu Master!
    • Mi canal de Youtube
  • Ciudad: Norte de África
  • Pais: Escoña
  • Iniciales nick: EPP
Re:GML
« Respuesta #5 en: Agosto 08, 2018, 04:41:21 pm »
Expresiones
Las expresiones representan valores normalmente almacenados en variables o evaluados por una sentencia condicional, la caul será explicada más tarde. Ellas pueden ser números reales tales como 3.4; números hexadecimales comenzando con el signo $, tal como $00FFCC (normalmente usado para representar un color en RGB); y cadenas las cuales están creadas encerrándolas con comillas simples o dobles, por ejemplo 'hello' o "hello".

Símbolos de expresión
Las expresiones pueden ser manipuladas y evaluadas usando diferentes símbolos. El signo de giual u operador de asignación = asigna el valor de una variable como es mostrado en el siguiente código:

Código: [Seleccionar]
// Assigning a variable with a value.
a = 10;
/* Assigning a different variable with an expression, in this case,
the sum of the previously declared variable and 7.5. */
b = (a + 7.5);

Las expresiones pueden también ser combinadas con operaciones básicas de matemáticas como se ve en el siguiente código:

Código: [Seleccionar]
// Addition and subtraction, + and -
val = a + 20 - b;
// Multiplication and division, * and /
val = a * 20 / b;
/* Expressions encased in parenthesis, ( and ), will be evaluated
first. */
val = (a + 20) * (b - 40);
// + can also be used to concatenate, or link, strings together.
str = "hello " + "world";

Las operaciones matemáticas pueden ser combinadas con = para crear un operador de asignación compuesto y ejecutar una suma, resta, multiplicación o división relativa como se aprecia en el siguiente código:

Código: [Seleccionar]
// Relative addition, +=
x += y; // equivalent to x = x + y;
// Relative subtraction, -=
x -= y; // equivalent to x = x – y;
// Relative multiplication, *=
x *= y; // equivalent to x = x * y;
// Relative division, /=
x /= y; // equivalent to x = x / y;

La principal ventaja de este código es su extreme simplicidad. En los ejemplos previos, x es una simple variable a escribir, pero si el nombre de la variable fuera más largo, el código anterior se acorta no teniendo que reescribir de forma innecesaria el nombre de la variable a ambos lados del operador de asignación.
Las variables pueden tambien ser incrementedas por un valor como se ve en el siguiente código:

Código: [Seleccionar]
var a, b, c, d, str_a, str_b, str_c, str_d;
a = 1;
b = 1;
c = 1;
d = 1;
// The return string will be "1" but a's value is now 2.
str_a = string(a++);
// The return string will be "2" and b's value is 2.
str_b = string(++b);
// The return string will be "1" but c's value is 0;
str_c = string(c--);
// The return string will be "0" and d's value is 0;
str_d = string(--d);

En resumen, si ++ o -- es incluido después de la variable, primero se devuelve el valor actual de la variable y luego es incrementada. Si ++ o -- es colocado antes de la variable, primero se incrementa el valor actual de la variable y luego el nuevo valor es devuelto.

Comparaciones booleanas, como se muestran en el siguiente código, comparan expresiones y devuelven los valores true o false, las cuales son constantes GML igual a 1 y 0 respectivamente:

Código: [Seleccionar]
// Less than, <
if (a < 20) { instance_create(a, 20, obj_ball); }
// Less than or equals to, <=
if (a <= 20) { instance_create(a, 20, obj_ball); }
// Equals to, ==
if (a == 20) { instance_create(a, 20, obj_ball); }
// Not equals to, !=
if (a != 20) { instance_create(a, 20, obj_ball); }
// Greater than, >
if (a > 20) { instance_create(a, 20, obj_ball); }
// Greater than or equals to, >=
if (a >= 20) { instance_create(a, 20, obj_ball); }

Los booleanos pueden ser también combinados para evaluación como se puede apreciar en el siguiente código:

Código: [Seleccionar]
// And, &&, will return true if both booleans are also true.
if (a == 20 && b == 40) { val = "and"; }
/* Or, ||, will return true if at least one of the booleans is true.
*/
if (a == 20 || b == 40) { val = "or"; }
/* xor, ^^, will return true if one booleans is true and the other
false. */
if (a == 20 ^^ b == 40) { val = "xor"; }
« Última modificación: Agosto 08, 2018, 04:47:34 pm por empardopo »

Desconectado empardopo

  • Admin
  • *
  • Mensajes: 21739
  • Gracias 761
  • Espero mejorar al KungFu Master!
    • Mi canal de Youtube
  • Ciudad: Norte de África
  • Pais: Escoña
  • Iniciales nick: EPP
Re:GML
« Respuesta #6 en: Agosto 09, 2018, 01:24:26 pm »
Seguimos con el cachito del día...

Sentencias condicionales
Las declaraciones condicionales utilizan una expresión booleana dentro del programa correspondiente. Si el valor devuelto es true, el programa ejecutará la sentencia que sigue a la condición; en caso contrario será saltada. Hay varios tipos de declaraciones condicionales en GML y cada una de las cuales tiene su propio uso.

if, else, y switch
La declaración if es probablemente la declaración condicional más común y que usaremos bastante haciendo juegos. La declaración if fue introducida cuando vimos anteriormente los booleanos; el siguiente códido ilustra el uso de una simple declaración if:

Código: [Seleccionar]
/* If the value of a is greater than the value of b, a is returned;
otherwise, b is returned. */
if (a > b)
{
return a;
}
else
{
return b;
}

En el ejemplo anterior, asumimos que tanto a como b son números reales; si el valor de a es mayor que el de b, a es devuelto; en caso contrario devolverá b. Una cosa que deberíamos ver aquí es que el valor b será devuelto si b es menor o igual que a, ya que es lo contrario de mayor que... (creo que esto se ve claro, no?)

Y qué hacemos si una variable necesita ser comparada con muchos diferentes valores?
Podríamos hacer como en el siguiente código:

Código: [Seleccionar]
/* Assigns the temperature of an object based on a color with multiple
if-else-statements. */
if (color == c_green || color == c_purple || color == c_blue)
{
temperature = "cool";
}
else if (color == c_red || color == c_orange || c == c_yellow)
{
temperature ="warm";
}
else if (color == c_black || color == c_gray || color == c_white)
{
temperature ="neutral";
}
else
{
temperature ="other";
}


Cuando necesitamos como en el caso anterior realizar demasiadas comparaciones, el programa a realizar puede volverse bastante tedioso y confuso. En vez de usar tantas declaraciones if-else, podríamos usar una declaración switch.
Una declaración switch es creada con las palabras clave switch, case, break y default, como podemos ver en el siguiente código:

Código: [Seleccionar]
/* Assigns the temperature of an object based on a color with a switch statement. */
switch (color)
{
    case c_red:
    case c_orange:
    case c_yellow:
          temperature = "warm";
          break;
    case c_green:
    case c_blue:
    case c_purple:
         temperature ="cool";
         break;
    case c_black:
    case c_white:
    case c_gray:
        temperature = "neutral";
        break;
    default:
       temperature = "other";
       break;
}

Esta declaración switch es idéntica a la declaración if-ese que creamos justo antes. Cada declaración case está esencialmente testeando si ese valor es igual o no al de la variable suministrada al switch. Si los valores son iguales, el programa se ejecuta. Cada case o grupo de case terminará con un break para que en el caso de que se ejecute dicho case, sepa donde parar.
Además, si no se cumpliera la condición con ningún case, pondremos un default que precisamente indica lo que habría que hacer en caso de que la variable no tomara ninguno de los valores comprobados con los case.

repeat, while, do, and for
Las declaraciones repeat, while, do, y for son todas ejemplos de sentencias que ejecutan una parte del código múltiples veces y esto es frecuentemente conocido como un loop o bucle en castellano.
La declaración repeat es usada para ejecutar el mismo trozo de programa un número especificado de veces:

Código: [Seleccionar]
// Creates 10 buttons at random positions between 0 and 100.
repeat (10)
{
instance_create(random(100), random(100), obj_button)
}

El código anterior creará 10 instancias del obj_button en posiciones aleatorias.
Código: [Seleccionar]
x = 0
repeat(3)
{
  x +=1;
}

El repeat sólo repetirá lo que haya entre las llaves así que en el código anterior la variable x empieza teniendo el valor 0; el bucle consiste en sumar 1 a x cada vez que se repite lo cual hará tres veces por lo que al final del bucle, el valor de x será 3, seguro? A qué esperáis para comprobarlo por ustedes mismo? :-)

La declaración while ejecutará el código mientras la condición se cumpla:

Código: [Seleccionar]
// Reduces x by 10 until it is no longer greater than 100.
while (x > 100)
{
x -= 10;
}

En el código anterior, el valor de x será reducido en 10 cada vez hasta que x llegue a ser inferior a 100.

La declaración do es muy similar a while, excepto que requieren una adicional palabra clave denominada until (sería el equivalente a lo que en otros lenguajes de programación sería el repeat-until):

Código: [Seleccionar]
/* Initially reduces x by 10 but continues until x is less than or equal to 100. */
do
{
x -= 10;
}
until (x <= 100);

La diferencia entre do y while es sutil. En una sentencia do, el código es ejecutado primero y luego es chequeada la condición mientras que en una sentencia while, la condición es chequeda antes de la ejecución del código. Es decir, en el primer caso al menos y siempre se ejecutará una vez mientras que en el while dependerá si inicialmente se cumplía la condición o no.

Las sentencias for o bucles for tienen condiciones incorporadas como vemos en el siguiente código:

Código: [Seleccionar]
// Declares a local variable.
var i;
/* 10 buttons are created, evenly spaced apart horizontally by 100 units with an initial offset of 25. */
for (i = 0; i < 10; i++)
{
    instance_create(i * 100 + 25, 25, obj_button)
}

La primera declaración despues de la palabra clave for, coloca la variable i al valor de 0. Luego, viene la condición de si el valor de i es inferior a 10 y si lo es, el bloque de código dentro del bucle será ejecutado.El valor de la variable i es luego incrementado y se chequea de nuevo dentro de la sentencia condicional, ejecutando de nuevo el código si es todavía válido, es decir, si el valor de i sigue siendo inferior a 10. La diferencia importante es que i es incrementado por la declaración, haciendo esto una buena forma para recorrer los valores de un array de una o dos dimensiones, lo cual veremos más adelante. El siguiente código ilustra esta funcionalidad con un array bidimensional:

Código: [Seleccionar]
// Creates two local variables.
var i,j;
/* This is an example of a nested for loop in which a 10 by 10 grid
with values ranging from 0 to 99 will be created. */
for (i = 0; i < 10; i++)
{
   for (j = 0; j < 10; j++)
   {
       grid[i,j] = i + j * 10;
   }
}
« Última modificación: Agosto 09, 2018, 02:13:03 pm por empardopo »

Desconectado empardopo

  • Admin
  • *
  • Mensajes: 21739
  • Gracias 761
  • Espero mejorar al KungFu Master!
    • Mi canal de Youtube
  • Ciudad: Norte de África
  • Pais: Escoña
  • Iniciales nick: EPP
Re:GML
« Respuesta #7 en: Agosto 16, 2018, 01:45:01 pm »
El siguiente código muestra la misma funcionalidad que el anterior pero usando declaraciones repeat:

Código: [Seleccionar]
// Creates local variable and then assigns their values to 0.
var i, j;
i = 0;
j = 0;
/* Repeat functionality is performed 10 times and 10 more times within
each repeat-statement. */
repeat (10)
{
   repeat(10)
  {
     // assign the grid value
     grid[i,j] = i + j * 10;
     // increment after each inner repeat.
     j++;
   }
   // increment after each outer repeat.
   i++;
}

Como demostramos, una declaración for es mucho más clara que una declaración repeat en casos como estos.

Antes de pasar a lo siguiente, debemos ser conscientes que las declaraciones repeat, while, do y for pueden crear una situación conocida como "bucle infinito". Los bucles infinitos son muy peligrosos y causan que un juego o programa se bloquee o congele, ignorando las entradas del usuario y forzándolo a quitar/cerrar el programa. Los siguientes son algunos ejemplos de declaraciones que pueden causar esto; no las uses en tus códigos porque son ejemplos de lo que no habría que hacer:

Código: [Seleccionar]
/* Since the condition in the while-statement is always true, it will never terminate. */
while (true)
{
   x += 1;
}
// Declares a local variable.
var i;
/* This for-statement will never end since i will never be less than 0. */
for (i = 0; i >= 0; i++)
{
   x += i;
}

Break, continue, y return
Como mencionamos anteriormente, las declaraciones de bucles pueden a veces causar una situación en la que ellos no terminan. Hay dos formas de resolver este problema. Una es conocida como break, la cual fue ya mostrada en la declaración switch para terminar cada declaración case, pero también puede ser usada para romper o terminar un bucle. El siguiente es un ejemplo de declaración break:
Código: [Seleccionar]
// local variable used in the for loop
var i;
/* Iterates through 1000 enemies. At the first undefined enemy, the
loop is exited, otherwise, the enemy moves by a random value between 1
and 10 horizontally. */
for (i = 0; i < 1000; i++)
{
   if (enemies[i] == noone)
   {
      break;
   }
   enemies[i].x += random_range(1,10);
}

En el código de ejemplo anterior, la declaración for es terminada y no continua ejecutándose una vez que la condición interna es encontrada. Supongamos que el break fuera reemplazado por continue, como mostramos en el siguiente código:

Código: [Seleccionar]
// local variable for for loop
var i;
/* Iterates through 1000 enemies. If an undefined enemy is
encountered, the remaining enemies are still checked; otherwise, the
enemy is moved by a random value between 1 and 10 horizontally. */
for (i = 0; i < 1000; i++)
{
   if (enemies[i] == noone)
   {
      continue;
   }
      enemies[i].x += random_range(1,10);
}

La declaración for procedería a comprobar todos los enemigos incluso si todos ellos estuvieran "indefinidos". Las declaraciones break y continue, sin embargo son muy útiles porque en ambos ejemplos, un enemigo indefinido va a ser encontrado y el juego se bloqueará al intentar agregar el valor generado por rango_aleatorio a su valor x. Las declaraciones return son usadas muy frecuentemente en los scripts GML que son creados como recursos. La declaración return no sólo finaliza cualquier script en su totalidad sino que también devuelve el valor que le sigue como podemos ver en el siguiente código:
Código: [Seleccionar]
// This script will simply add and multiply two arguments
var result;
result = (argument0 + argument1) * (argument0 * argument1);
return result;

Si quieres obtener un valor usando la función mostrada anteriormente, puede ser accedida a traves del siguiente código, asumiendo que la función scr_add_multipy es un recurdo script:

Código: [Seleccionar]
// Execute the method and assign it to x.
x = scr_add_multiply(1, 2);
« Última modificación: Agosto 16, 2018, 02:06:35 pm por empardopo »

 


* Salón Recreativo #55 (27-04-2024 / 26-05-2024)  Autor: beaches Foro: Salón Recreativo FaseBonus 14/05/2024 (22:08)
* MPAGD (Multi Platform Arcade Game Designer)  Autor: Zael Foro: Creación de juegos 14/05/2024 (10:53)
* ¿A qué estáis jugando ahora mismo?  Autor: joselopez Foro: Offtopic 13/05/2024 (23:30)
* [N3DS] Red Viper - Emulando Virtual Boy como Dios manda  Autor: sirdrak Foro: Noticias de emuladores 13/05/2024 (00:53)
* El megapost del ZX Spectrum  Autor: Zael Foro: Offtopic 12/05/2024 (20:30)
* La inteligencia artificial ha llegado a la música  Autor: Zael Foro: Offtopic 12/05/2024 (20:24)
* Info sobre MARP  Autor: empardopo Foro: Records y wolfmame 12/05/2024 (20:09)
* Stop the express  Autor: empardopo Foro: ZX Spectrum 12/05/2024 (20:05)
* Retro 320 - Wizard of wor  Autor: empardopo Foro: Competiciones y concursos 12/05/2024 (20:03)
* Retro Portable Maker ArcadeSpain (RPMA)  Autor: empardopo Foro: Otros programas 12/05/2024 (17:37)
* Recopilatorio Retos: Desde el 1 hasta .....  Autor: montypepa Foro: Competiciones y concursos 05/05/2024 (21:30)
* iojukebox Theme, un JukeBox para Attract-Mode  Autor: gucaza Foro: Themes AM 04/05/2024 (02:47)
* Nuevo miniPc para mi vieja recre y juegos Windows compatibles formato 4:3  Autor: jmpuk Foro: Offtopic 02/05/2024 (23:31)
* Homenaje a Locomalito  Autor: beaches Foro: Otros programas 02/05/2024 (23:03)
* [Recomendación] Cine para los findes en casa (bueno, bonito y barato)  Autor: arquillos Foro: Offtopic 02/05/2024 (09:39)
* [Recomendacion] Series para ver  Autor: jmpuk Foro: Offtopic 01/05/2024 (21:54)
* Etpa8: El Reino Subterráneo  Autor: jmpuk Foro: ZX Spectrum 01/05/2024 (21:49)
* Amiga Games + 1.9.2  Autor: empardopo Foro: Emuladores 01/05/2024 (20:58)
* West Bank para ZX Spectrum  Autor: empardopo Foro: ZX Spectrum 01/05/2024 (20:07)
* Patrocinador para el foro ArcadeSpain  Autor: empardopo Foro: Noticias 29/04/2024 (19:37)
* Aprende a hacerte un PORTABLE de tu juego arcade favorito  Autor: empardopo Foro: Records y wolfmame 29/04/2024 (19:27)
* Screenshot de empardopo  Autor: empardopo Foro: Otros programas 24/04/2024 (19:42)
* Concurso Bytemaniacos 2025  Autor: empardopo Foro: Creación de juegos 23/04/2024 (21:46)
* Van dos y se cae el del medio - Hilo de cachondeo general  Autor: empardopo Foro: Offtopic 21/04/2024 (18:47)

Countdown
Buscaunchollo.click