Aunque el VRML da muchos mecanismos para definir interacción y comportamientos, hay cosas que no se pueden hacer diréctamente y entonces se debe utilizar la poténcia de un lenguaje de programación externo. Esto se consigue a través del node Script y los lenguajes que se pueden utilizar son el Java y el JavaScript (o compatible JavaScript).
En este tutorial, tan solo entraremos a ver la utilización del JavaScript dentro del node Script debido a que es mucho más sencillo, directo y común de utilizar.
Nota: Partiremos del supósito que el lector ya cuenta con un
conocimiento previo del JavaScript como lenguaje y que lo sabe utilizar a nivel
básico para realizar pequeñas utilidades en pantallas de HTML.
El concepto básico detrás del node Script es que es un node que permite los siguientes pasos:
Un node Script está formado por dos partes principales: las definiciones de campos y eventos, y el código en el lenguaje que hemos escogido.
Es importante el hecho que en este node podemos definir campos y eventos según nuestras necesidades, en contraste con los otros nodes de VRML que ya tienen predefinidos todos sus componentes.
El sitio donde se pone el código del lenguaje es en el field url. Este field permite escribir todo el código entre comillas dobles (") o bién referenciar un archivo externo donde figure todo el código.
A continuación vemos un esquema de la estructura del node:
|
Esquema: Estructura del node Script.
|
Aquí se pueden observar las dos partes que definíamos arriba.
Primero se encuentran las definiciones de campos y eventos. Estos no requieren
estar ordenados de ningúna forma concreta. En segundo lugar, encontramos
el field url donde, entre comillas, se define el tipo de código
que se utiliza (en nuestro caso javascript:) y a continuación
todas las funciones que configuran nuestros procesos.
Existe una relación directa entre los nombres de los eventIn y los nombres de las funciones del código. Esta relación se establece para que cuando llegue un evento de entrada al node Script en custión, él llame a la función que tiene el mismo nombre que el eventIn referenciadi y así se pueda capturar el valor que se ha recibido y se pueda procesar.
El mecanismo implementado por el node Script hace que toda función de JavaScript asociada a un eventIn tenga dos parámetros por defecto: el valor recibido por el eventIn y el instante de tiempo en que se ha generado aquel evento. De esta forma, la función puede utilizar el valor del evento que ha recibido e incluso discernirlo de otros eventos gracias al hecho de que también se dispone de su sello de tiempo.
A continuación damos un ejemplo donde un ProximitySensor
envía un evento de cambio de posición del punto de vista a un
Script que mira si la coordenada X de este punto de vista
es mayor que 5 (y no hace nada más de momento).
|
Ejemplo1: Definimos un ProximitySensor llamado SensorPuntoVista
que va detectando el movimiento del punto de vista del usuario por dentro
suyo. Este ProximitySensor va generando eventOuts de nombre
position_changed, los cuales son encaminados mediante un ROUTE
al eventIn de nombre nuevaPosicion del Script llamado
SiguePuntoVista.
|
Analicemos este código parte por parte:
(1) Al contrario de en VRML donde no se accede nunca a las
componentes de los datos que pertenecen a tipos no escalares como SFVec3f,
SFRotation, SFColor, SFVec2f y todos
los MFs, cuando hemos de programar puede interesarnos acceder
a estas componentes. En un caso como este, un valor de estos tipos se comporta
como si fuera un array de JavaScript y por lo tanto se accede a las componentes
indexando desde 0 (cero) hasta el número de componentes menos uno. Por
ejemplo: a un field SFColor con nombre miColor, se le podrían
asignar los valores RGB (1, 0.5, 0.3) desde un Script indexando
de la siguiente forma: miColor[0]=1; miColor[1]=0.5; miColor[2]=0.3;
Los eventOut se definen en la primera parte del node Script de forma similar a los eventIn. Para poder generar el evento de salida a través del eventOut que hemos definido, tan solo tenemos que asignarle un valor desde dentro de la función que ha de generar el evento.
Ampliemos nuestro ejemplo anterior. Ahora queremos que suene una alarma cuando
detectemos que el punto de vista ha sobrepasado el límite de 5 unidades
en el eje X. Los elementos necesarios son los siguientes:
|
Ejemplo2: Definición
de unos eventos de salida para activar un sonido de alarma (añadimos
al ejemplo anterior).
|
Los elementos nuevos son los siguientes:
Los field también se definen en la primera parte del node Script de forma similar a los eventIn y a los eventOut. Los field sirven como variables globales para el Script y para guardar valores a lo largo de toda la ejecución del entorno. Con esto podemos comparar valores de eventos nuevos con valores antiguos que hayamos guardado previamente en fields.
De nuevo ampliemos nuestro ejemplo. Lo que haremos ahora es que suene la alarma
solo la primer vez que el usuario pase el límite. Si el usuario vuelve
atrás y después de nuevo sobrepasa el límite, la alarma
ya no deberá sonar. Los elementos necesarios son los siguientes:
|
Ejemplo3: Definición
de un field booleano para saber si el usuario ya había
traspasado el límite préviamente.
|
Solo hemos añadido los elementos siguientes:
Inicialmente hemos dicho que, excepto por el field url, el node Script no tenía ningún otro campo predefinido. Esto lo hemos dicho para simplificar las explicaciones anteriores, pero no es exáctamente cierto. De hecho el node Script dispone de dos campos predefinidos: mustEvaluate y directOutput.
Durante la ejecución de un entorno de VRML, el browser tiene la autorización (por especificación) de gestionar los eventos en el momento que le sea más idóneo. Esto puede provocar que se acumulen una série de eventos durante un lapso de tiempo, para después ser evaluados todos de golpe (evidentemente en el orden en que se han generado).
Esto significa que cuando programemos un Script para gestionar unos eventos, podría pasar que no se nos evalúe el Script cada vez que se genera el evento de entrada que necesitamos. En este caso pasaría que al cabo de un rato se evaluaría nuestro Script tantas veces como eventos de entrada se hayan acumulado.
Para poder evitar o controlar esto, el node Script dispone del campo prodefinido field SFBool mustEvaluate. Por defecto, este campo tiene valor FALSE, cosa que significa que la evaluación del Script puede ser postpuesta. Si queremos que nuestro Script se evalúe cada vez que se reciba un evento de entrada de los que gestionamos, entonces debemos poner el campo mustEvaluate TRUE.
Nota: Es necesario tener en cuenta que poner mustEvaluate TRUE
implica imponer un control más exhaustivo al browser y por lo tanto se
pierde eficiencia. Sólo debe hacerse cuando sea estríctamente
necesario.
A veces es práctico poder acceder diréctamente a los exposedFields,
eventOuts y eventIns de nodes externos
al Script, sin tener que definir todo un conjunto de ROUTEs.
Esto da más control sobre el entorno ya que no se depende de la gestión
de eventos que hace el browser. Así pués, podríamos tener
definido un node de transformación con un cubo como geometría,
del cual queremos saber el valor del campo de traslación desde dentro
del Script sin necesidad de que se genere un evento. Entonces
lo que haríamos sería:
|
Ejemplo4: Definimos un acceso directo a un node externo
a un Script.
|
Miremos paso a paso lo que se ha hecho en este ejemplo:
Con este ejemplo vemos que podemos acceder a información de nodes externos sin tener que establecer ROUTEs que nos encaminen eventos. Pero tal y como está definido, sólo podemos acceder a los exposedFields o a los eventOuts para leer su valor.
Si quisiéramos acceder a los exposedFields o a los eventIns para modificarlos, no podríamos a menos que utilizáramos el campo que subministra el VRML en los Scripts, que es el field SFBool directOutput. Este campo, por defecto tiene el valor FALSE. Así, para poder tener acceso a los campos de nodes externos y poderlos modificar, debemos cambiarlo a TRUE.
Veamoslo en el siguiente ejemplo:
|
Ejemplo5: Definimos un
acceso directo a un node externo a un Script con posibilidad
de modificación.
|
Lo que hace el ejemplo es que cada vez que se entra al Script,
se mueve el cubo una posición en el eje de las X hasta llegar
a 5, momento en el que se devuelve el cubo al origen.
Ejercicos propuestos:
|