Este tutorial está destinado a programadores iniciados en Lingo. La intención es llegar a conocer los principios de la programación con objetos. La POO es algo difícil de describir y esto hace que muchos programadores piensen que esté reservada a expertos en programación. Realmente, es fácil y una vez se entienden los conceptos básicos nos resultará muy útil para casos concretos. El curso está escrito de la manera más práctica que he sabido, planteando ejemplos de todo lo que voy explicando que, cómo no, te aconsejo vayas practicando al mismo tiempo que haces la lectura. Te aviso que el principio del tutorial puede parecer algo espeso. Como siempre pasa, la teoría es bastante aburrida pero una vez aclarado algún que otro concepto, el resto del curso es bastante práctico y entretenido o, eso pienso al menos :-). Con un poco de paciencia y con la ayuda de los ejemplos comprenderás bastante bien los principios de la POO. ¡Suerte! Parte 1Qué es un objetoUn objeto es una instancia de un script padre que contiene datos (propiedades) y/o instrucciones. A partir de un script padre podemos sacar todos los objetos que queramos y estos tendrán las mismas características que el padre pero sus propias variables (propiedades) que le harán comportarse de forma diferente. Esto quizás se entenderá mejor con algunos ejemplos:Imaginemos un script padre llamado Vehiculo con 2 propiedades: Revisión y Kilómetros. En este script padre se podría añadir la condición de que si la propiedad Kilómetros es mayor de 5000, Revisión tendrá valor TRUE y tenemos que llevar el vehículo al taller. Teniendo esta base, podemos sacar multiples copias, o sea, objetos hijo que responden de la misma forma pero con sus propias variables. Otro caso para utilizar objetos son los juegos arcade porque podemos crear un script padre que defina a un marciano o comecocos con sus propiedades y rutinas de movimiento, disparo, etc y crear tantos objetos como bichos queramos. Este es uno de los ejemplos más claros y donde mejor se justifica el uso de POO. Crear un script padreAhora que ya tenemos una idea de qué es un objeto y un script padre vamos a crear el script padre mínimo y conoceremos así su estructura.Abrimos la ventana script desde el menú Window/Script, después pulsamos el botón I (cast member properties) y seleccionamos el tipo Parent. Le damos nombre al script desde la ventana cast y ya solo falta escribir el código de nuestro script padre. Ej. de script padre mínimo: |
La estructura mínima de un objeto la forma el handler o función new (en Director 4 o anterior se usa la función birth, alumbrar en inglés ) seguido del parámetro me que es un puntero o número de identificación ( en adelante ID ) del objeto. Cada objeto que creemos tiene un número de ID único que, normalmente, se guarda en una variable o en una lista para cuando queramos referenciar al objeto. Para alumbrar el objeto hacemos una llamada a la función new que devuelve un valor de retorno ( el ID ) y éste lo guardamos en una variable: |
set mivar = new (script "nombrescriptpadre") |
Con esto ya hemos creado un objeto. Si queremos crear otro objeto del mismo script padre repetimos la operación pero con otra variable: |
set miotravar = new (script "nombrescriptpadre") |
Cuando queramos crear un número grande o indeterminado de objetos, a partir del mismo script padre, lo más cómodo es utilizar una lista. Cada elemento de la lista contendrá un objeto, es decir el ID. Si queremos crear 100 objetos el script a utilizar podría ser este: |
set milista=[] repeat with n=1 to 100 add milista,new (script "nombrescriptpadre") end repeat |
Para utilizar un objeto en concreto utilizamos la función getat que devuelve el valor de una posición de la lista. Te recuerdo la sintaxis: getat (lista,posición).Propiedades de un objeto y parámetros inicialesVamos a aplicar lo dicho hasta ahora en un caso más práctico (encontrarás el listado completo en el archivo Poo1.dir). Volviendo al ejemplo del script padre Vehículo creamos su script y lo preparamos para recibir valores iniciales. Te recuerdo que tiene 2 propiedades Revisión y Kilómetros y, además, si Kilómetros es mayor de 5000 cambiaremos el estado de la propiedad Revisión. Esto último se consigue a través de la función Taller que está dentro del propio script padre: |
-- Parent Script Vehiculo property Revision property Kilometroson new me, tRevision, tKilometros set Revision = tRevision set Kilometros = tKilometros return me end on Taller me if Kilometros > 5000 then set Revision = TRUE end -- Fin de Parent Script Vehiculo |
Para crear objetos con unos valores iniciales le mandamos a la función new los parámetros: |
set coche1 = new (script "Vehiculo", FALSE, 0 ) |
Como ya habrás deducido, después de ejecutar esta instrucción, coche1 guarda el valor de ID de este objeto, Revisión se inicializa a False y Kilómetros a 0. |
set coche2 = new (script "Vehiculo", FALSE, 1245 ) |
Para comprobar si tenemos que llevar algún coche al mecánico llamamos a la función Taller seguida del ID del objeto que nos interese: |
Taller coche1 Taller coche2 |
Cómo cambiar los datos del objetoPara que esta simulación de coche sea más real, durante la ejecución del programa incrementamos a voluntad la propiedad Kilómetros. (Atencián al artículo the antes de la propiedad). |
set the kilometros of coche1 = (the kilometros of coche1)+1 |
Del mismo modo, si queremos consultar alguna propiedad del objeto: |
put the Kilometros of coche1 put the Revision of coche1 |
Eliminar un objeto y los contadores de referenciaCuando terminamos de usar un objeto, se debe liberar para recuperar la memoria que ocupa. Para ello, igualamos a 0 cualquier variable que contenga el ID.Lingo tiene un contador interno de las variables que apuntan a un objeto. Si imprimimos en la ventana Message el valor de coche2 obtentremos algo así: |
-- put coche2 <offspring "Vehiculo" 2 27a9262> |
- offspring "Vehiculo" indica que es un hijo de Vehículo
- 2 indica que hay 2 variables que apuntan a Vehículo, una es el propio objeto en sí y otra la variable coche2. Si copiamos coche2 a otra variable valdrá 3, del mismo modo si igualamos a 0 esta variable se decrementa en 1. El objeto sólo será liberado cuando coche2 valga 1, que es cuando ninguna variable apunta al objeto excepto el objeto en sí, de ahí el valor 1.
- 27a9262 es una dirección de memoria en hexadecimal.
En este ejemplo si queremos borrar el objeto coche2 hacemos: |
Consulta Poo1.dir donde está el programa completo.Parte 2The actorList y stepFrameSi creamos una lista de objetos denominada the actorList, cuando se entre en un frame cada uno de los objetos recibirá un mensaje stepFrame. De esta forma, si hemos puesto en el script padre una función on stepFrame, se ejecutará el contenido de ésta.Para que se entienda mejor, pondré un ejemplo. El programa completo está en Poo2.dir. Vamos a crear un objeto que simule el comportamiento de una pelota botando: |
-- Parent Script Pelota property dir property numSpr on new me,tdir,tnumSpr set dir = tdir set numSpr = tnumSpr puppetsprite numSpr,true return me endon stepFrame cambiarDir Mover end on cambiarDir if the locV of sprite numSpr < 50 then set dir = 5 else if the locV of sprite numSpr > 240 then set dir = -5 end if end on Mover set the locV of sprite numSpr = ( the locV of sprite numSpr ) + dir end -- Fin de Parent Script Pelota |
Para crear un objeto dentro de la actorList: |
add the actorList,new (script "pelota", -5,1) |
Para acabar el programa en la celdilla 1 del Score, pegamos el dibujo de una pelota en las coordenadas 320,240, en el script de frame del frame 1 ponemos un go to the frame, en el script startMovie creamos el objeto tal como ya hemos visto y, por último, en el script stopMovie vaciamos el contenido de la actorlist ( set the actorList=[] ). No te preocupes por todo esto, en el archivo Poo2.dir lo tienes hecho. Al hacer Play la pelota botará hasta que hagamos Stop. Cada vez que entramos en el frame 1, se ejecuta la función stepFrame que hace botar el sprite 1 en la dirección que indica la variable dir. Inicialmente, dir vale -5 para que la pelota empiece el movimiento de abajo a arriba. Parte 3Hijos, padres y abuelosUna posibilidad, que no hemos tratado todavía, es la herencia de los objetos. Gracias a esto, podemos crear un nuevo tipo de objeto a partir de otro ya existente. Este nuevo objeto, hijo del anterior, hereda todas las carectísticas de su padre y, además, tendrá las suyas propias. No hay límite para el número de generaciones. Cada hijo puede tener, a su vez, otro hijo.El ejemplo típico para utilizar ancestros sería el de un juego matamarcianos, donde tenemos un tipo de marcianos con unas caractistícas y acciones definidas como por ejemplo, disparar, cambiar de color, moverse, etc. Pero además, para este juego diseñamos un segundo tipo de marciano, hijo del anterior, con todas sus características heredadas, más alguna propia que será única. Por poner un ejemplo, es más rápido y su disparo más efectivo. Una de las ventajas de usar ancestros está en el ahorro de reescribir el código y en la disminución de la posibilidad de errores. Seguramente, al desarrollar cualquier aplicación encontraremos una manera de evitar el uso de ancestros. Personalmente, nunca he tenido necesidad de usar más de un hijo de un objeto y, cuando lo he hecho, ha sido más por prácticar estos temas que porque fuera necesario, ya que me resulta más claro trabajar sin herencias. De todas formas, ya que existe esta opción, vamos a tratarla un poco aprovechando para ello el objeto Pelota que ya tenemos creado en el capítulo anterior. Quizás no sea un caso muy real y se podría hacer de una forma más directa, pero como ejercicio didáctico ya sirve. Crear un hijoPara crear un objeto hijo en su script padre, hay que definir la propiedad ancestor y después guardar aquí el ID del script padre de este objeto . En el siguiente ejemplo se crea el script mínimo ancestro de otro que, como ya hemos dicho, hereda todas las propiedades y funciones del scriptpadre. |
-- script hijo property ancestor on new me set ancestor = new (script "scriptpadre") return me end |
El padre de este script, al que pondremos una propiedad llamada Nombre, podría ser el siguiente: |
-- script padre property Nombre on new me set Nombre="Pedro" return me end |
La herencia de las propiedadesLa propiedad Nombre, aunque solo está definida en el script padre, también existirá en los objetos hijo. Al arrancar el programa, padre e hijo comparten el valor de la propiedad Nombre pero se puede cambiar de forma independiente. Para hacer esto, es imprescindible conocer el ID de cada objeto. Si se quiere cambiar el valor de una propiedad, desde fuera del script, se hace como ya hemos visto: |
set the Nombre of hijo = "Otronombre" set the Nombre of padre = "Sinnombre" |
siendo hijo y padre las variables que contienen el ID. Para inicializar Nombre al crear el objeto, modificamos el script hijo como sigue: |
property ancestor on new me set ancestor = new (script "padre") set the Nombre of me="Tunombre" return me end |
Esto funciona porque me contiene el ID de sí mismo y, al crear el objeto, se modifica el valor de Nombre. El fichero que ilustra esta parte está sin acabar. Te propongo que abras Poo3.dir y desde la ventana Message crees tú mismo los objetos y practiques las herencias de propiedades. Parte 4Compartir FuncionesEn el capítulo anterior, creamos el objeto Pelota que contenía un sprite que se mueve en el eje vertical. Ahora, a partir de éste, vamos a crear Pelota2 que se mueve en los dos ejes, vertical y horizontal, haciendo un irreal bote en diagonal. Ya que tenemos las funciones Mover y cambiarDir de Pelota, para añadir al hijo el movimiento horizontal, solo tenemos que programar la función Diagonal porque el resto lo heredamos. (El programa completo está en Poo4.dir)Aquí tienes el script de Pelota2: |
-- Parent Script Pelota2 property ancestoron new me set ancestor = new (script "pelota",-5,2) return me end on stepFrame cambiarDir (ancestor) Mover (ancestor) Diagonal end on Diagonal set the locH of sprite 2 = (the locH of sprite 2) + (the dir of ancestor) end -- Fin de Parent Script Pelota2 |
Las funciones cambiarDir y Mover no están definidas aquí pero las usamos como si fueran propias. Para que Lingo pueda encontrarlas, hay que decirle el ID del objeto que las contiene y, para ello, nos valemos de la propiedad ancestor. Para hacer el incremento positivo y negativo de la coordenada horizontal, nos aprovechamos de la propiedad dir. En este caso, usamos el valor del objeto padre haciendo una lectura directa. Pulsa aquí para bajar el Tutorial de POO + Ejemplos ©1998 Pedro Agriarte e-mail:[email protected] URL:http://www.geocities.com/yosemite/rapids/6716 |