Está en la página 1de 267

Recopilado de:

unityscripts.blogspot.com

Contenido

PRELIMINARES Y ALGUNOS PRESUPUESTOS................................................................................... 4 ALGUNAS PECULIARIDADES DE UNITY ............................................................................................ 6 DONDE VAN LOS SCRIPTS? ............................................................................................................ 8 1. CLASE OBJECT ............................................................................................................................ 13 2. ESTRUCTURA VECTOR3 ............................................................................................................. 21 3. CLASE TRANSFORM ................................................................................................................... 29 4. CLASE RIGIDBODY...................................................................................................................... 44 5. CLASE COLLIDER ........................................................................................................................ 60 6. CLASE MESHCOLLIDER............................................................................................................... 66 7. CLASE CHARACTERCONTROLLER ............................................................................................... 68 8. CLASE RENDERER....................................................................................................................... 74 9. CLASE MESHFILTER .................................................................................................................... 77 10. CLASE JOINT............................................................................................................................. 78 11. CLASE HINGEJOINT .................................................................................................................. 82 12. CLASE SPRINGJOINT ................................................................................................................ 86 13. CLASE CHARACTERJOINT ......................................................................................................... 88 14. CLASE BEHAVIOUR .................................................................................................................. 90 15. CLASE MONOBEHAVIOUR ....................................................................................................... 91 16. CLASE CAMERA ...................................................................................................................... 107 17. CLASE LIGHT .......................................................................................................................... 118 18. CLASE MATERIAL ................................................................................................................... 125 19. CLASE CUBEMAP ................................................................................................................... 131 20. CLASE RENDERTEXTURE ........................................................................................................ 133 21. CLASE PARTICLEEMITTER ...................................................................................................... 138 22. CLASE MESH .......................................................................................................................... 145 23. CLASE GAMEOBJECT .............................................................................................................. 149 24. CLASE SHADER ....................................................................................................................... 159 25. CLASE PHYSICMATERIAL ........................................................................................................ 160

26. CLASE COMPONENT .............................................................................................................. 164 27. CLASE GUIELEMENT .............................................................................................................. 165 28. CLASE GUITEXT ...................................................................................................................... 166 29. CLASE GUITEXTURE ............................................................................................................... 170 30. CLASE GUI .............................................................................................................................. 172 31. CLASE GUILAYOUT ................................................................................................................. 188 32. CLASE TEXTURE ..................................................................................................................... 196 33. CLASE TEXTURE2D ................................................................................................................. 198 34. CLASE INPUT .......................................................................................................................... 203 35. ESTRUCTURA BOUNDS .......................................................................................................... 214 36. CLASE COLLISION ................................................................................................................... 217 37. CLASE CONTROLLERCOLLIDERHIT ......................................................................................... 220 38. CLASE DEBUG ........................................................................................................................ 222 39. CLASE EVENT ......................................................................................................................... 224 40. CLASE GIZMOS ....................................................................................................................... 229 41. CLASE LIGHTMAPSETTINGS ................................................................................................... 232 42. ESTRUCTURA MATHF ............................................................................................................ 233 43. CLASE PHYSICS....................................................................................................................... 241 44. ESTRUCTURA QUATERNION .................................................................................................. 246 45. CLASE RANDOM .................................................................................................................... 249 46. ESTRUCTURA RAY .................................................................................................................. 251 47. ESTRUCTURA RAYCASTHIT .................................................................................................... 252 48. ESTRUCTURA RECT ................................................................................................................ 254 50. CLASE SCREEN ....................................................................................................................... 259 51. CLASE TIME............................................................................................................................ 262 52. CLASE YIELDINSTRUCTION..................................................................................................... 264

FISICAS: CONCEPTOS BASICOS .................................................................................................... 265

PRELIMINARES Y ALGUNOS PRESUPUESTOS

Bienvenid@s a unityscript. Antes de entrar en materia y para que nadie se lleve a engao, considero honesto advertir a los hipotticos lectores de que el autor de estas lneas no es programador profesional, ni ha creado ninguno de los cien videojuegos ms vendidos de la historia. De hecho, si he de ser totalmente sincero, hace menos de tres aos este que os est escribiendo no haba escrito ni una sola lnea de cdigo. Puede parecer por lo tanto un atrevimiento -y de hecho lo es- que un tipo como yo, un autodidacta sin ninguna base acadmica, se atreva a inaugurar un blog de estas caractersticas, y comprender perfectamente que alguien con conocimientos profundos sobre programacin en general o Unity en particular salga corriendo de este site. Reconozco ya de antemano, por lo expuesto, que muy probablemente algunas de las cosas que os vaya explicando en las lecciones que vendrn a continuacin puedan contener errores, y pido disculpas anticipadas por ello. Huelga decir que agradecer cualquier correccin por parte de personas con ms conocimientos. Me gustara explicaros brevemente las razones por las cuales me he decidido a crear este blog, las razones por las que creo que este blog es necesario: Yo aterric en el universo Unity hace unos cuatro meses. Ms o menos como todos, me di una vuelta por la interfaz grfica, estuve pelendome con las cmaras, encend las luces y puse niebla a la escena, traste con el terrain hasta crear algo parecido a una isla, import algunos modelos de Blender (todava ando buscando las texturas de esos modelos) y cosas parecidas. Luego empec a leerme todos los libros que pill sobre Unity, que no es que sean demasiados. Y cuando me los hube ledo todos, ya dominaba ms o menos decentemente la interfaz del engine, pero segua sin tener ni idea sobre la API de Unity. En los libros que en la actualidad hay sobre la materia la parte relativa a los scripts -que en el fondo es la ms importante- se deja en un segundo trmino. Se incluyen, un poco a boleo, varios scripts, pero de una manera totalmente desordenada y sin ningn inters pedaggico, pareciera que ms para impresionar al respetable o para copiar y pegar en otros proyectos sin saber a ciencia cierta qu se est haciendo, que para realmente explicar de dnde sale cada cosa, cules son las clases principales, su cometido y relacin de herencia entre ellas, qu demonios en un cuaternin, etc. La nica va para hacerse con la API de Unity pasaba pues por ir al manual de referencia de la propia pgina web del engine, la cual presenta un triple inconveniente: 1) Est en ingls. 2) Est escrito ms como manual de consulta que como instrumento de aprendizaje. 3) Sigue un orden alfabtico, no un orden lgico. El primer inconveniente no lo fue tanto, ya que hace cuatro aos (uno antes de empezar a aprender informtica) segu al pie de la letra el consejo de un amigo: - Si quieres aprender a programar, antes aprende ingls. Y como este que os habla suple su falta de talento con una buena dosis de cabezonera, a estudiar ingls que me puse. De esta manera y gracias al consejo de mi amigo -que ruego os apliquis los que no os llevis bien con la lengua de Shakespeare- durante estas ltimas semanas he traducido la casi totalidad de las clases, estructuras y enumeraciones de Unity al castellano. No es que sea una traduccin muy pulida, aviso desde ya, pero para nuestros fines bastar.

De los otros dos inconvenientes nos tendremos que ir ocupando poco a poco, por el viejo procedimiento de prueba y error y usando el sentido comn y la constancia donde el resto falle. Tengo el firme propsito de ir haciendo vuestros los avances que a su ver yo vaya haciendo en mi propio aprendizaje, y aunque ello entrae ir a un ritmo lento y en ocasiones nos implique tener que retroceder para revisitar algn concepto, tambin creo que puede ser interesante para alguien que empieza en esto escuchar las explicaciones y/u opiniones de otro que recin est aprendiendo tambin y que -al contrario que algunos autores con ms conocimientos- no da nada por supuesto. As que no esperis scripts de cuatro pginas (no al menos el primer ao), con todo lo bueno y lo malo que eso pueda conllevar. Y, por supuesto, sera muy positivo que hubiera la suficiente retroalimentacin con todo aqul que est interesado en hacer comn el camino de aprendizaje. Eso s, para no tener que hacer una parada conjunta antes de dar siquiera el primer paso, esto es, para poder seguir este "curso" (por llamarlo de alguna manera) presupongo que quien lea esto tiene una serie de conocimientos de base ya adquiridos, a saber: 1) Algo de programacin en general, y de Javascript en particular. (Variables, funciones, bucles, condicionales, etc.) 2) Conocimientos rudimentarios de POO (Programacin Orientada a Objetos) 3) Haberle dado unas cuantas vueltas a la interfaz de Unity y estar familiarizado con su terminologa (gameobjects, assets, y esas cosas) Si no tenis esos conocimientos previos, ni podris seguir las explicaciones ni podris hacer juego alguno (desde ya les aseguro a los amigos de los atajos que no existe un software mgico que obedeciendo a tus impulsos cerebrales te construya de la nada un juego online multijugador listo para ser distribuido). Y sin ms prembulos, creo que podemos dar la introduccin por acabada y meternos en materia.

Hasta pronto.

Medina Autor de unityscripts.blogspot.com y de este manual de referencia.

ALGUNAS PECULIARIDADES DE UNITY

Antes de adentrarnos en la API de Unity, conviene saber que el engine admite tres lenguajes de programacin para sus scripts: C#, Boo (una variante de Python) y algo muy parecido a Javascript, que es lo que vamos a usar nosotros en este curso. Javascript es de los tres lenguajes indicados el ms sencillo, y si bien algunos programadores con un cierto nivel aseguran que C# les ofrece ms control, para nuestros fines y nivel con Javascript vamos ms que sobrados. Una de las cosas que choca de entrada en Unity para los que tuvieran un conocimiento previo de Javascript es la forma de declarar las variables. A diferencia del Javascript standard, en Unity hemos de declarar el tipo de la variable, un poco a la antigua usanza de C y C++. Por ejemplo, para declarar la variable numero de tipo int haramos: var numero : int; numero = 10; Y si la quisiramos inicializar en la declaracin, sera: var numero : int = 10; Esto es, palabra reservada "var" para indicar que vamos a declarar una nueva variable, el nombre que le demos a sta seguida de dos puntos y el tipo de la variable declarada.

En otro orden de cosas, hemos de decir que la API de Unity est orientada a objetos y se compone de algo ms de un centenar de clases, de las cuales una tercera parte ms o menos estn relacionadas entre s en trminos de herencia y el resto o son conjuntos de funciones auxiliares (clase tiempo, de funciones matemticas, etc.) o bien meramente permiten funcionalidades especiales no contempladas en lo que podramos llamar las clases troncales (clases relativas a la GUI o para conectarse a un servidor, por ejemplo) Entendiendo que las clases que estn vinculadas entre s son a su vez las que nos pueden dar una idea ms precisa del mecanismo de funcionamiento de Unity, son con vuestro permiso -y con alguna excepcin que iremos haciendo- por las que me gustara empezar. Y ya que -salvo error- nadie se ha tomado la molestia de hacer un esquema del sistema de herencia de estas clases, me tom la libertad de hacerlo yo. Est incompleto, ya que una veintena de clases de las que estuve mirando cuando estaba llevando a cabo la traduccin no me parecieron demasiado importantes, o por lo menos no a estas alturas, pero en esencia este sera el arbolito de clases con que nos va a tocar lidiar durante una buena temporada.

Recomiendo imprimir este esquema, ya que lo vamos a usar de referencia para, por ejemplo, saber qu funciones hereda una determinada clase, o qu clase tiene un atributo que es una instancia de otra clase. Por experiencia -poca, pero experiencia al cabo- os digo que o tenis una referencia a mano o todo os acabar sonando igual y al final os quedaris sin el que debiera ser vuestro objetivo, que no es aprenderse todas las funciones de memoria, sino entender por qu la API de Unity est estructurada de una manera y no de otra. Como podris observar, he incluido en el esquema las variables, funciones y funciones de clase (o atributos y mtodos, si prefers la terminologa de la POO) de la clase base (Object), la principal de las que derivan de aqulla (Component) y la que a su vez hereda de sta y es heredada por otro nmero de clases. Esto nos permite, como deca antes, seguir la pista a las variables y funciones heredadas por -pongamos un ejemplo- la clase Camera, que hereda de Behaviour y por tanto tambin de Component y por ltimo de Object. As, podemos presuponer que esto es vlido: var camaraDeSeguridad : Camera; camaraDeSeguridad.name = "Mi camara"; Esto es, nuestro objeto camera debera haber heredado una variable name de la clase Object. Teniendo a mano el esquema nos podemos evitar andar rebuscando por el manual de referencia. Y con esto finalizamos por ahora. Para la prxima nos tocar ya abrir Unity.

DONDE VAN LOS SCRIPTS?

Bueno, tras un par de captulos con los prolegmenos, creo que ya podemos entrar en materia, para lo cual vamos a abrir Unity. Nota: En principio, y salvo que diga lo contrario, todas las caractersticas y scripts que vamos a utilizar sirven para la versin free como para la PRO, as que me da igual la versin que tengis. Vamos a crear un proyecto nuevo, que podis llamar como os d la gana y guardar donde queris, que para eso el ordenador es vuestro. No vamos a importar de momento ningn asset, as que dejamos desmarcadas todas las casillas y creamos el proyecto. Lo nico que nos aparecer en la interfaz, por tanto, ser la cmara principal. La marcamos y en el inspector, la colocamos en las siguientes coordenadas: X=0, Y=1, Z =-5. Ahora vamos a introducir un cubo en la escena. Nos vamos al men superior, Gameobject => Create other => Cube. Al cubo primero lo vamos a castellanizar, y en consecuencia le llamaremos Cubo. Le podemos cambiar el nombre en el inspector, o bien pulsando F2 en la jerarqua con Cube seleccionado. Vamos a ubicar nuestro cubo en las coordenadas 0,0,0. Vamos a salvar la escena. File =>Save Scene. Para no liarnos, recomiendo que le pongis el mismo nombre que yo, esto es, Ejemplo_1. Si todo ha ido bien, debis tener algo parecido a esto:

Ahora, en la vista Project, en un espacio libre debajo de donde est la escena guardada, hacemos click derecho con el ratn, y en el men emergente seleccionamos Create => Folder. A la carpeta que aparecer le llamaremos Mis scripts. Con el puntero del ratn sobre dicha carpeta vamos a hacer de nuevo click derecho, y esta vez seleccionamos Create=>Javascript. Nos aparecer un icono representando al nuevo script con el nombre por defecto "NewBehaviourScript". Lo renombramos, llamndolo MiPrimerScript, y le damos a return para que nos conserve el cambio.

Como podemos observar, en el inspector al seleccionar nuestro script aparece una funcin por defecto, la cual nos ser til en un buen nmero de casos. Sera lo que se conoce como una funcin sobrescribible, que quiere decir que Unity decide cundo se va a llamar (la funcin Update, que es la que sale por defecto, es llamada por Unity cada frame) y nosotros decidimos qu har cuando sea llamada, introduciendo cdigo en su interior. Para poder editar y/o crear nuestros scripts, hemos de acceder al editor que viene con Unity, y la mejor manera para hacerlo es hacer doble click sobre el nombre de nuestro script. Se nos abrir (en windows) esto:

Vamos a aprovechar que tenemos el editor abierto para explicar otra caracterstica de los scripts en Unity. Unity permite asignar/modificar los valores a las variables globales desde la propia interfaz de usuario, y concretamente desde el inspector, bien asignando esos valores "a mano", o bien arrastrando un objeto o componente del tipo de dicha variable global. Para que podamos hacer eso es preciso, como digo, que la variable tenga un mbito global, y para ello es preciso que la misma se declare fuera de cualquier funcin. Lo veremos mejor con un ejemplo: en el editor de scripts, encima de donde pone function Update, escribiremos lo siguiente: var camaraDeSeguridad : Camera; camaraDeSeguridad.name = "Mi camara"; Debug.Log(camaraDeSeguridad.name);

Es un miniscript parecido al que veamos en el captulo anterior. En l declaramos una variable global (est fuera de cualquier funcin) de tipo "Camera", y lo que hacemos a continuacin es -va herencia- asignarle un nombre a la variable, que ser "Mi camara". La tercera declaracin de momento nos basta con saber que muestra en pantalla (imprime) el valor de lo que est entre sus parntesis. Guardamos el script (si no, no funcionar) en el editor de scipts. De vuelta a la interfaz de Unity, si seleccionamos el nombre del script vemos que en el inspector se ha actualizado dicho script con el cdigo que hemos introducido. No obstante, nuestro script an no es funcional, ya que no lo hemos vinculado a ningn objeto de nuestra escena. Pensemos que los scripts por s solos no hacen nada, de la misma forma que cualquier asset que est en la carpeta/vista del proyecto (por ejemplo, una textura) no participar de alguna manera en una escena de nuestro juego si no lo arrastramos a esa escena, convirtindolo en parte de cualquier gameobject. En consecuencia, vamos a vincular nuestro script a uno de los gameobjects de nuestra escena, y en concreto al cubo. Para hacer eso meramente hemos de arrastrar el script desde la vista de proyecto hasta el propio objeto cubo, bien sea sobre su nombre en la jerarqua, bien sobre la propia imagen del cubo en la escena. Tras arrastrar el script, y con el cubo seleccionado en la jerarqua, en el inspector deberamos estar viendo lo siguiente:

Obsrvese que en el inspector aparece ahora el nombre de nuestro script como una parte ms del Cubo que tenemos en la escena. Y daros cuenta de que la variable global queda expuesta en el inspector, de tal forma que no necesitamos ir al editor de scripts para asignarle un valor. Si la variable hubiera sido, por ejemplo, de tipo float, podramos haber introducido o cambiado su valor meramente escribindolo en el inspector. Si en cambio la variable fuera de tipo bool, nos aparecera en el inspector con un checkbox al lado del nombre, bien marcado (true) o sin marcar (false) para que lo cambiramos a conveniencia. Pero como en este caso la variable es de tipo Camera, lo nico que podemos hacer para inicializarla es proveerla de un objeto de ese tipo. Dado que en nuestra escena precisamente tenemos una cmara (la main camera), meramente tendremos que arrastrarla desde la jerarqua hasta el lugar del inspector donde se consigna el valor de la variable, y que ahora mismo pone "none". Tras arrastrar la cmara, el inspector lucir as:

Ya tenemos, por lo tanto, nuestro script asignado a un gameobject (nuestro cubo) y la nica variable global inicializada con otro object (la cmara principal). Procedamos ahora a darle al play y ver qu sucede. Si nos fijamos, debajo de la ventana game nos aparecer impreso el nombre que le asignamos a nuestra cmara.

Antes de acabar me gustara que practicramos un pequeo ejercicio que nos permitir comprender las diferentes maneras (correctas e incorrectas) en que se puede declarar una variable. Borremos todo el contenido de nuestro script MiPrimerScript y tecleemos lo siguiente: var var var var sinTipoNiIni; conTipoSinIni : int; sinTipoConIni = 10; conTipoConIni : int = 10;

var aPlazos : int; aPlazos = 10; private var miSecreto : int; var arrastrame : GameObject; function Update() { var enLaFuncion : int; } Salvamos el script y, con el Cubo seleccionado (recordemos que este script est todava vinculado al cubo que tenemos en la escena) echamos un vistazo al inspector. Podemos de manera emprica llegar a las siguientes conclusiones para cada manera de declarar una variable: La variable sinTipoNiIni, que como su nombre apunta hemos declarado sin indicar ni el tipo de datos que debera contener, ni la hemos inicializado conjuntamente con la declaracin, no aparece en el inspector, porque ste no tiene forma de saber qu tipo de variable estamos declarando. La variable conTipoSinIni s es tenida en cuenta por el inspector, ya que aunque no la hemos inicializado, s que hemos indicado el tipo de dato que queremos almacenar en ella. La variable sinTipoConIni s aparece en el inspector, ya que aunque no hemos declarado el tipo que contendr, al estar inicializada permitimos a Unity deducir en base al valor el tipo de variable apropiado. Fijmonos que adems de aparecer la variable en el inspector, lo hace con el valor inicial que le hemos dado. La variable conTipoConIni aparece obviamente en el inspector. La variable aPlazos aparece en el inspector, pero sin inicializar. En cambio, si pulsamos play observaremos que automticamente le es asignado el valor 10 que le dimos en segunda declaracin. La variable miSecreto no es accesible desde el inspector porque es privada. De hecho, esa variable no podr se accedida desde ningn script distinto del que la contiene. La variable arrastrame es recogida en el inspector, y al ser de un tipo propio de Unity, nos aparecer con una flechita diminuta en la derecha que nos indica que podemos importar del juego cualquier componente de ese tipo para asignar un valor a la misma, bien usando el men que emerge al clickear dicha flecha, bien va arrastrar el objeto o componente desde las carpetas de proyecto o jerarqua. Por ltimo, la variable enLaFuncion no aparece en el inspector, ya que al ser declarada dentro de una funcin no tiene carcter pblico.

Bueno, pues con esto ya debera quedar un poco ms clara la manera en que las variables y los scripts son tratados en Unity. Ahora empezaremos a analizar clase por clase de la API.

1. CLASE OBJECT

Ha llegado el momento de empezar a pelearnos con las clases que componen la API de Unity, y tal como os comentaba considero lo ms conveniente empezar con la clase base. Es sabido que en POO las clases base de las que heredan las dems suelen tener una funcionalidad bastante limitada, cuando no inexistente, siendo su funcin ms la de punto de partida de las que habrn de heredarla que la de instanciar objetos de dicha clase. La clase Object, que es con la que vamos a empezar, no parece ser una excepcin a esta regla.

La clase Object consta de dos variables, dos funciones y nueve funciones de clase (FC). Como sabris, las funciones de clase se diferencian de las funciones standard en que aqullas no precisan ser llamadas por una instancia u objeto de la clase, perteneciendo -como su nombre indica- a la clase y no a las instancias de dicha clase.

VARIABLES: name: var name : String Bueno, esta variable ya la conocamos. Hace referencia al nombre del objeto, y comparten ese nombre tanto el objeto en s como los componentes de dicho objeto. Esta variable nos sirve tanto para cambiar el nombre a nuestro objeto... name = "Cualquier nombre"; ...como para obtener el nombre de un objeto. Probemos esta segunda opcin con un ejemplo muy sencillo. Abrimos Unity y nos vamos a la escena que creamos en la leccin anterior. En la vista del proyecto, hagamos doble click en el script que llamamos miPrimerScript. Una vez se abre el editor, borramos todo el contenido y tecleamos:

function Update(){ Debug.Log(name); } Como vimos en la leccin anterior, Debug.Log nos permite imprimir en pantalla el valor de lo que se halle entre parntesis. Salvamos el script (pero no cerramos el editor, meramente lo minimizamos) Hay una cuestin que no quiero dejar pasar por alto. Lo que hemos modificado y guardado es el script que se halla en la carpeta de proyecto. No obstante, al hacer eso automticamente se modifican todas las copias de este script que tengamos por ah. En el caso que nos ocupa, recordaremos que a nuestro cubo le habamos aadido una copia de este script, que a estas alturas por lo expuesto ya habr sido modificado. Probmoslo. Si le damos al play, observaremos que bajo la ventana game aparece el nombre de nuestro cubo. Todo bien hasta aqu, no obstante, en la definicin del manual de referencia dice que todos los componentes del objeto comparten el mismo nombre. Si echamos un vistazo a nuestro cubo en el inspector, observaremos que entre otros componentes tiene uno llamado transform, as que vamos a hacer la prueba. Sustituimos el "name" que habamos escrito en el editor de scripts entre parntesis por transform.name. O sea: Debug.Log(transform.name); Guardamos el script, le damos al play y....Voil!, el componente transform comparte el nombre "cubo".

hideFlags: var hideFlags : HideFlags Esta variable no parece a priori tener una gran utilidad. Se conseguira con su manipulacin hacer que un determinado objeto desaparezca o bien del inspector, o bien de la jerarqua, o impedir que dicho objeto se pueda editar, o no permitir que un objeto sea salvado con la escena y en consecuencia destruido con la nueva escena que se cargue. Para tal fin esta variable manera las diferentes opciones de una de las muchas enumeraciones que hay en Unity. Esta enumeracin, de nombre HideFlags, tiene las siguientes opciones: HideInHierarchy HideInInspector DontSave NotEditable HideAndDontSave El objeto no aparecer en la jerarqua. El objeto no aparecer en el inspector. El objeto no ser salvado en la escena ni destruido en la nueva que se cargue. El objeto no ser editable en el inspector. Combinacin de HideInHierarchy y DontSave.

As, si por ejemplo quisiramos (no se me ocurre muy bien para qu) que el cubo desapareciera del inspector mientras se desarrolla el juego, le vincularamos un script parecido a este: var meEvaporo: GameObject; meEvaporo.hideFlags = HideFlags.HideInInspector; Este script lo arrastramos a la cmara principal, y con posterioridad arrastramos nuestro cubo en la variable global meEvaporo, que est esperando un gameObject. Observaremos que cuando le demos al play, el cubo desaparece del inspector. Por qu meEvaporo es de tipo GameObject?No debera tratarse de un Object, que es la clase que estamos tratando?. Pues efectivamente, pero sucede que si sustituimos GameObject por Object en nuestro script, comprobaremos que desaparece del inspector la variable meEvaporo, posiblemente por lo que deca al principio de la leccin de que la clase

Object est pensada como clase base para dotar de funcionalidad a las que la heredan, que para ser instanciada ella misma. En cualquier caso, como digo, no parece que hideFlags sea una variable que vayamos a usar mucho.

FUNCIONES:

ToString: function ToString () : String Devuelve un string con el nombre del gameobject que hace la consulta.

GetInstanceID: function GetInstanceID () : int Unity asigna a cada objeto un identificador nico. Esta funcin devuelve ese identificador. Vamos a utilizar estas dos funciones en un mismo ejemplo. En el captulo anterior tenamos vinculado nuestro script a la cmara principal. Abrimos el editor de scripts, borramos todo y tecleamos lo siguiente: var todoSobreMi: GameObject; Debug.Log("El nombre de este objeto es " + todoSobreMi.ToString() + " y su id unica es " + todoSobreMi.GetInstanceID()); El script no merece mucha explicacin. Asegurmonos de arrastrar el cubo a la variable todoSobreMi en el inspector. Al pulsar el play debera mostrarse el nombre e id del cubo, tal como se muestra en la imagen (obviamente, la id no tiene por qu coincidir con la que os aparezca a vosotros).

FUNCIONES DE CLASE

operator bool, == y != Estas tres funciones meramente habilitan la posibilidad de establecer comparaciones de igualdad/desigualdad entre dos objetos o componentes, o (en el caso del operador bool) si existe dicho objeto componente y tiene un valor distinto de null. Por ejemplo:

if (rigidbody) Debug.Log("Este gameobject tiene vinculado un Rigidbody");

Que sera lo mismo que haber escrito if (rigidbody != null) Debug.Log("Este gameobject tiene vinculado un Rigidbody");

Instantiate: static function Instantiate (original : Object, position : Vector3, rotation : Quaternion) : Object Esta funcin lo que hace es clonar el objeto que le pasamos como primer parmetro, y devolver ese clon del objeto original, ubicndolo en posicin y rotacin determinadas. Observamos que el parmetro "position" es de tipo Vector3, que es una clase que no tardaremos mucho en estudiar. De hecho, posiblemente sea la prxima que tratemos, ya que aunque no pertenece a la jerarqua de herencia que hemos tomado como referencia para el orden de estudio, s que va a aparecer el nmero suficiente de veces durante el trnsito por dicha jerarqua como para no ocuparnos de ella de primeras. Un Vector3 es, en pocas palabras, un punto en el espacio tridimensional. Dicho punto viene dado por las coordenadas en el eje X (derecha-izquierda) Y (arriba-abajo) y Z (delante-detrs). Cada unidad se corresponde a una unidad en Unity (valga la redundancia), que a su vez equivale a un metro. Por lo tanto para que un objeto se desplace un metro a la derecha, escribiramos en nuestro Vector3 (1,0,0). Notemos que esto es ni ms ni menos que lo que hace de manera ms visual las tres variables position del transform que aparecen en el inspector. El otro parmetro de la funcin, rotation, es de tipo Quaternion. Quien sepa lo que es, felicidades, yo estuve varios das pelendome con apuntes de matemticas por la red y a lo sumo me hice una idea abstracta de que un cuaternin se compone de tres nmeros reales y uno imaginario, el clculo de los cuales establece la rotacin de un objeto. Si os sirve de consuelo, y eso lo indica el propio manual de referencia oficial de Unity, es muy raro que trabajemos directamente con cuaterniones, sino que lo haremos con funciones que nos simplifiquen el trabajo. Yo personalmente me quedo solamente con la idea de que un cuaternin lo componen cuatro elementos y mide las rotaciones. Con eso es suficiente, creedme. Bueno, pues dicho esto a ver si somos capaces de instanciar/clonar un cubo. Nos vamos a Unity, y le quitamos a la cmara principal el script que le habamos colocado anteriormente. Para hacer eso, con la cmara seleccionada en el inspector colocamos el ratn sobre el nombre del script, botn derecho=>Remove Component. Ahora, para no andar vinculando scripts a gameobjects que nada tienen que ver con l (como hicimos no hace mucho con la cmara), vamos a crear un gameobject vaco cuya nica utilidad sea contener nuestro script. Para ello nos vamos al men superior, y le damos a GameObject=>Create empty. A la carpeta que nos aparecer en la jerarqua la renombramos (F2) como PortaScripts. Vale, ahora doble clic sobre nuestro script en la vista de Proyecto para abrir el editor de scipts, y escribimos: var reproducete : GameObject; Instantiate(reproducete, Vector3(2.0,0,0), Quaternion.identity);

Aqu lo que hemos hecho meramente es dejar una variable global "expuesta" (que pueda ser accesible desde el inspector) y llamar a la funcin instantiate, de tal manera que clonar el Gameobject que le arrastremos y lo situar dos unidades/metros a la derecha del objeto original. Quaternion.identity meramente significa que el objeto clonado tendr rotacin cero, esto es, su transform rotation estar a 0,0,0 (salvo que el objeto clonado dependa a su vez de otro objeto, en cuyo caso tendr la misma rotacin que el objeto padre, pero esto ya lo explicaremos cuando toque. Salvamos el script y lo arrastramos hasta nuestro PortaScripts en la jerarqua. Vemos que en el inspector, con PortaScripts seleccionado, aparece el script y la variable expuesta que llamamos reproducete. Arrastramos el cubo hasta ella y ya podemos darle al play. Debera aparecernos un segundo cubo, tal que as:

Podemos observar alguna cosa ms. En la jerarqua aparece -mientras se est reproduciendo la escena- un segundo cubo, el cual Unity nos indica expresamente que es un clon del original. Si lo seleccionamos, podemos ver en su transform en el inspector que la variable x (el eje derecha/izquierda) no est en el cero, sino en el dos, tal como le habamos indicado. Probemos otra cosa. Detenemos la reproduccin de la escena. Seleccionamos el cubo original, y le damos a los ejes X e Y de transform rotation los valores 25 y 65 respectivamente. El cubo girar sobre dichos ejes. Dmosle al play. Podemos observar que el cubo clonado se muestra alineado con la cuadrcula global, y no con el cubo original. Esto es lo que conseguimos con Quaternion.identity. La funcin instantiate es muy usada para crear proyectiles, partculas en explosiones e incluso AI (inteligencia artificial) para enemigos. Cabe una segunda forma distinta para la funcin Instantiate, que es esta: static function Instantiate (original : Object) : Object Como podemos observar, aqu meramente estamos duplicando el objeto, se tal suerte que el clonado se ubicar en el mismo lugar y con la misma rotacin que el original. Podemos probarlo en nuestro script meramente eliminando el segundo y tercer parmetro. Al darle al play, sabemos que ha aparecido un clon porque as lo indica la jerarqua, pero no podemos distinguirlo porque est justo en el mismo sitio que el original y se estn solapando.

Destroy: static function Destroy (obj : Object, t : float = 0.0F) : void Como su nombre indica, esta funcin borra del juego un gameobject, un componente o un asset. Tiene dos parmetros, siendo el primero el elemento a borrar y el segundo el tiempo en segundos que tardar en borrarlo desde que se llame a la funcin (si no se indica lo contrario, por defecto el parmetro indica cero segundos, esto es, la destruccin del objeto es automtica). Hay una cuestin que igual ahora no se entiende muy bien, pero la dejo apuntada para tratarla ms en profundidad en otro momento: si en el parmetro obt colocamos un Componente, la funcin slo eliminar ese componente, hacindolo desaparecer del Gameobject al que pertenezca. Pero s en cambio lo que le pasamos a la funcin es un gameobject, se destruir tanto el gameobject como todos los hijos de ese gameobject (esto es, todos los objetos y componentes e inclusive otros gameobjects que dependan del eliminado en una relacin de parentesco). Para tener un acercamiento intuitivo a esta relacin de dependencia, pensemos en un gameobject coche que tiene, entre otros, cuatro componentes rueda y un gameobject conductor que hemos vinculado al gameobject coche para que all donde se desplace el coche vaya el conductor. Si un misil destruye un componente rueda usando la funcin destroy, slo se destruir la rueda. Si en cambio lo que destruye es el gameobject coche, se destruir tanto el vehculo como las ruedas como el conductor. Vamos a probar la funcin Destroy. Para empezar devolvamos a nuestro cubo original a su rotacin original (0,0,0). Vamos a rehacer ahora nuestro sufrido script, al que tendremos que vincular el cubo en la variable reproducete como GameObject dentro del inspector. En el editor de scripts modificamos nuestro cdigo as: var reproducete : GameObject; var nacioPaMorir : GameObject; nacioPaMorir = Instantiate(reproducete, Vector3(2.0,0,0), Quaternion.identity); Destroy (nacioPaMorir, 5.0); Creo que es bastante fcil de entender. Lo que hemos hecho es aadir una segunda variable de tipo GameObject, que no vamos a inicializar desde el inspector, porque lo que har ser almacenar el cubo clonado que devuelve la funcin Instantiate. Inmediatamente es llamada la funcin Destroy, que borrar el elemento clonado que hemos almacenado en nacioPaMorir pasados diez segundos. Salvamos, le damos al play, contamos hasta cinco, y adis clon.

DestroyImmediate: static function DestroyImmediate (obj : Object, allowDestroyingAssets : boolean = false) : void Esta funcin destruye inmediatamente un objeto, igual que la funcin anterior. Desde el manual de Unity se nos dice, no obstante, que es preferible usar Destroy en lugar de esta funcin, ya que puede borrar ms de lo que deseamos. Por lo tanto, olvidmonos de DestroyImmediate.

Continuamos con las funciones de clase de la clase Object. Recordemos que las funciones de clase, como su nombre indica, no van vinculadas a objetos o instancias de una clase, sino a la clase en s, esto es, no se utiliza el operador punto entre el nombre del objeto/instancia y el de la funcin, como sucedera en una funcin normal (o mtodo) dentro de una clase. FindObjectOfType static function FindObjectOfType (type : Type) : Object

Esta funcin devuelve el primer objeto activo que Unity encuentre que sea del tipo que le pasamos como parmetro. Vemoslo en un ejemplo. Recuperamos una vez ms nuestro script, borramos todo y tecleamos lo siguiente: var dameAlgo : Object; dameAlgo = FindObjectOfType(Camera); Debug.Log("Deberia haber encontrado 1 " + dameAlgo); Salvamos, le damos al play y observamos que Unity ha encontrado nuestra cmara principal. Nos advierte el manual de referencia que esta funcin puede ser un poco lenta y costosa en trminos de rendimiento, por lo que se recomienda no usarla a su vez como parte de una funcin que se actualice cada frame (como por ejemplo la funcin Update, que estudiaremos a no mucho tardar)

FindObjectsOfType static function FindObjectsOfType (type : Type) : Object[] No hace falta ser muy perspicaz para darse cuenta de que esta funcin es idntica a la anterior, con la diferencia de que aqu lo que se devuelve no es el primer objeto activo de tipo Type, sino que se devuelven en un array todos los objetos activos cuyo tipo coincide con el que solicitamos. Veamos la diferencia rehaciendo nuestro script: var dameAlgo : Object[]; var chivato : String; dameAlgo = FindObjectsOfType(GameObject); chivato = "He encontrado " + dameAlgo.Length + " objetos: "; for(var contador = 0; contador < dameAlgo.Length; contador++) chivato += dameAlgo[contador].name + " "; Debug.Log(chivato); Lo que hemos hecho aqu es lo siguiente: primero hemos reconvertido nuestra variable dameAlgo en un array de Objects. Declaramos despus una variable de tipo string para que vaya recopilando toda la informacin que al final imprimiremos. Inicializamos luego nuestro array con todos los objetos de tipo GameObject que Unity encuentre en nuestra escena. A partir de ah montamos un bucle for para ir aadiendo a nuestro string "chivato" el nombre de todos los objetos encontrados. Finalmente, imprimimos. Si todo ha salido bien, el resultado tendra que ser este al darle al play:

DontDestroyOnLoad static function DontDestroyOnLoad (target : Object) : void Con esta funcin conseguimos que el objeto que colocamos como parmetro no se destruya cuando se cargue una nueva escena. Por defecto, cuando el jugador cambia de escena o nivel, todos los objetos de la escena que abandona se destruyen antes de crear los que corresponden al nuevo nivel. Con esta funcin, conseguimos que los objetos que queramos pervivan al cambio de escena. Dado que an no sabemos cargar escenas nuevas, no vamos a realizar ningn ejemplo. Ya lo haremos cuando expliquemos las oportunas funciones.

Y con esto acabamos el anlisis de nuestra primera clase. Espero que os hayan quedado los conceptos ms o menos claros (al principio cuesta un poquillo, as que no desesperis). Y por supuesto, si hay alguna duda, queja (educada) o correccin que hacer, sentiros libres de comentar en el blog.

2. ESTRUCTURA VECTOR3

Lo primero que cabra decir de Vector3 es que, a diferencia de Object, por ejemplo, no es en s una clase, sino una estructura. En la corta historia de la programacin las estructuras surgieron antes de las clases, en los viejos tiempos de la programacin procedimental, y originalmente eran poco ms que una coleccin de variables que guardaban algn tipo de relacin entre s. Hoy por hoy, no obstante, no hay ninguna diferencia entre una estructura y una clase. Aunque Vector3 no est contenido dentro del esquema de herencia principal de Unity, es una clase imprescindible para la creacin de cualquier juego, ya que precisamente es la que permite que representemos puntos y vectores en el espacio 3D, y por ende la que nos permite trabajar con distancias y desplazamientos. El concepto de punto, siendo sencillo cuando se entiende, a veces provoca en los recin llegados no pocas confusiones. Quizs lo mejor para captar el concepto de punto en 3D previamente tengamos que aprehender el concepto de punto en 2D. Vamos a intentar explicarlo de una manera llana, y ruego me disculpen los que ya tenan claro el concepto: Delante vuestro posiblemente tengis la pantalla de vuestro ordenador o del dispositivo electrnico desde el que estis viendo estas lneas. En algn lugar de la pantalla estar seguramente el cursor del ratn, apuntando a algn punto (valga la redundancia) determinado de sta. Si quisiramos explicarle a alguien que no est viendo la pantalla en qu lugar est el cursor, o si meramente quisiramos dejar por escrito de una manera fiable en qu punto exacto est ahora nuestro cursor, una buena manera de hacerlo sera decir: el cursor est X centmetros (digamos por ejemplo 16) a la derecha del borde izquierdo de la pantalla e Y centmetros por debajo del borde superior de la pantalla (pongamos 20). As, si por ejemplo convenimos que la esquina superior izquierda de la pantalla es el punto 0,0, nuestro cursor en el mundo 2D de la pantalla estar situado en el punto 16,20. Por lo tanto, observamos que para determinar la situacin exacta de un punto necesitamos a su vez otro punto que nos sirva de referencia (Y es importante retener este concepto, sobre el que no tardaremos en volver). As, para saber dnde est el punto al que seala el ratn necesitamos primero compararlo con el punto que tomamos como referencia, y la resta entre ambos puntos es la distancia que los separa, que es este caso ya no sera un punto sino un vector, aunque se represente igual. Lo mismo es aplicable a las tres dimensiones, aunque a nivel intuitivo nos cueste un poco ms de pillarlo. Meramente entendamos que si nuestra pantalla de ordenador no fuera plana, sino por ejemplo un holograma, para localizar el objetivo de nuestro ratn tendramos que aadir un nuevo punto (o eje) Z, para calcular la profundidad con relacin a un punto de origen (que podra ser la esquina superior izquierda ms cercana a nosotros de la pantalla hologrfica en 3d)

La estructura Vector3, pues, nos permite averiguar en qu punto se halla cada gameobject, cambiar su posicin, calcular las distancias entre ellos, etc. Es conveniente advertir que el tipo Vector3 no es la nica clase/estructura que maneja lo relativo a puntos y desplazamientos. Cumplen funcionalidades parecidas (que no iguales) la clase Quaternion y la Matrix4X4. Existen, antes de que nos alarmemos en exceso, funciones que permiten convertir, por ejemplo, un Vector3 en un Quaternion (y viceversa), as que de momento no nos obsesionemos ms de la cuenta con conceptos que nos suenen extraos. Y tras esta extensa introduccin, ahora empezamos con la estructura en s.

CONSTRUCTOR: 1) static function Vector3 (x : float, y : float, z : float) : Vector3 Como sabemos de nuestros conocimientos de programacin orientada a objetos, el constructor es una funcin especial cuyo cometido es crear de manera adecuada las instancias/objetos de una determinada clase o estructura. La funcin constructora se caracteriza por tener el mismo nombre que la clase. Tal como vemos en el prototipo de nuestro constructor, le hemos de pasar al mismo los tres componentes de nuestro punto 3D, referidos al eje horizontal, vertical y de profundidad respectivamente, en formato de punto flotante. As: var miPunto = Vector3(2.0, 5.0, 4.8); Referenciamos un punto que con respecto al origen se desplazar dos unidades a la derecha, cinco hacia arriba y 4,8 hacia el fondo. Vale, pero cul es el origen?, se preguntar alguien. Pues depende, tendremos que responder. Si un objeto no depende de otro, entendemos por origen el punto 0,0,0 de las coordenadas globales (que es donde deberamos tener nuestro cubo) y desde ese punto origen se calcula el desplazamiento, pero si un objeto depende de otro (recordemos el ejemplo de la rueda y el coche) caben para ese objeto dos orgenes o coordenadas diferentes: las globales (distancia de la rueda respecto del eje 0,0,0 del caso anterior) y las locales (referidas al objeto del que depende) 2) static function Vector3 (x : float, y : float) : Vector3 Como vemos, hay una segunda funcin constructora que no toma en cuenta el eje Z (la profundidad) asumiendo que sta es cero. Por tanto, si a la funcin constructora Vector3 slo le pasamos dos parmetros, automticamente ser llamada esta segunda versin del constructor.

VARIABLES: x, y, z: Estas variables se refieren a los componentes X, Y y Z del vector, respectivamente. this: var this[index : int] : float

Esta es otra forma para acceder a los componentes X, Y y Z del vector, siendo los respectivos ndices de cada componente 0, 1 y 2. As, estas dos declaraciones son equivalentes: var miVector : Vector3; miVector.x = 3.0; miVector[0] = 3.0; //Equivale a la anterior

magnitude: var magnitude : float Esta variable devuelve la longitud o tamao de un vector. Habamos hablado previamente de que un vector3 contiene el nmero de unidades que lo separan del origen dado en los ejes X, Y y Z. Obviamente, cuanta mayor es la distancia entre nuestro Vector3 y el punto de origen, mayor la longitud del vector. La longitud del vector equivale a la raz cuadrada de (x*x+y*y+z*z). Soy consciente de que a estas alturas la utilidad de funciones como estas es difcil de apreciar. Con un poco de paciencia, y cuando las combinemos con otras clases, veremos el partido que se le puede sacar a todo esto.

sqrMagnitude: var sqrMagnitude : float Si de lo que se trata es de comparar dos vectores, es preferible usar esta funcin que la precedente, ya que aunque parezca antiintuitivo, Unity calcula con ms rapidez los cuadrados de las magnitudes que las magnitudes en s.

normalized: var normalized : Vector3 Esta variable devuelve un vector con la misma direccin que el original, pero con magnitud 1. Es importante constatar que el vector original permanece inalterado y lo que se devuelve es meramente una copia que conserva la direccin de dicho original, aunque con la longitud alterada. Si en lugar de normalizar una copia quisiramos hacer lo propio con el original, entonces tendramos que usar la funcin Normalize, que veremos en breve. Decir tambin que si el vector es demasiado pequeo para ser normalizado, lo que se devuelve es un vector a cero.

VARIABLES DE CLASE: zero: static var zero : Vector3 Es meramente un atajo para poner un vector a cero.

transform.position = Vector3.zero; // Es lo mismo que escribir transform.position = Vector3(0,0,0);

one, forward, up y right: Son respectivamente atajos para escribir Vector3(1,1,1), Vector3(0,0,1), Vector3(0,1,0) y Vector3(1,0,0).

Vamos a ver algunos de los conceptos de esta leccin en un ejemplo. Abrimos nuestro script favorito y escribimos: var unObjeto : GameObject; var desplazamiento : Vector3; var magnitud : int = 0; desplazamiento = Vector3.right; for(var contador = 0; contador < 3; contador++) { unObjeto.transform.position += desplazamiento; magnitud += desplazamiento.magnitude; Debug.Log("Longitud del Vector del cubo: " + magnitud); } Salvamos, arrastramos nuestro cubo para que se convierta en la variable unObjeto y le damos al play. Nuestro cubo se mueve tres unidades a la derecha y bajo la ventana Game aparece la magnitud de desplazamiento del vector. El script funciona de la siguiente forma: Adems de la variable que sostendr a nuestro cubo, creamos una variable de tipo Vecto3 para poder almacenar a modo de impulsos o maniobras de desplazamiento de una unidad a la derecha. Ese input a la derecha se lo daremos tres veces mediante un bucle for, y cada magnitud individual (que obviamente vale 1 cada vez) se acumula en una variable de tipo int que hemos creado a tal efecto.

FUNCIONES: Scale: function Scale (scale : Vector3) : void Multiplica el Vector3 que llama la funcin por el Vector3 que le pasamos a dicha funcin como parmetro. Lo veremos mejor con un ejemplo. Vamos a darle un meneo de nuevo a nuestro script. Tecleamos: var unObjeto : GameObject; var miVector : Vector3; miVector = unObjeto.transform.position = Vector3(2.0, 1.0, 3.0); Debug.Log("Magnitud inicial del cubo " +miVector.magnitude); miVector.Scale(Vector3(3.0, 1.5, 2.0)); unObjeto.transform.position = miVector; Debug.Log("Magnitud final del cubo " + miVector.magnitude); Antes que nada vamos a explicar lo que pretendemos hacer: dejamos expuesta la variable unObjeto para arrastrar con posterioridad nuestro cubo desde el inspector. Asimismo declaramos una variable para sostener el valor original y modificado para un vector3.

Aunque an no lo hemos estudiado, a nadie sorprender que los diferentes gameobjects que ocupan la escena han de ir ineludiblemente vinculados a un objeto transform, el cual a su vez es el que sirve para fijar en qu punto del espacio 3D se halla el gameobject. As, para obtener o indicar la posicin de un gameobject en el espacio usaramos la sintaxis gameobject.transform.position. Se da la circunstancia que la variable position de la clase transform es de tipo Vector3, por lo que nos sirve para nuestro ejemplo. Hacemos una iniciacin doble, de tal manera que damos unos valores a nuestro Vector3 miVector, que a su vez tendr el mismo valor que le damos a la posicin actual del cubo. Obtenemos la magnitud de dicho vector y la imprimimos. Luego usamos la funcin Scale, y la magnitud del vector modificado es impresa de nuevo, y a la par el cubo se desplaza por segunda vez. Obtendremos al darle al play un resultado como este:

Si nos fijamos en la parte inferior de la ventana Game, slo aparece impresa la magnitud final del vector de nuestro cubo. Para ver tambin el valor inicial, hemos de hacer un click sobre dicho texto impreso, de tal suerte que nos aparecer una ventana emergente con ambos valores, tal como mostramos:

La funcin Scale tiene un segundo prototipo, que es el que sigue static function Scale (a : Vector3, b : Vector3) : Vector3 El fin ltimo es, al igual que en la funcin homnima, multiplicar dos vectores. La diferencia es que aqu pasamos expresamente los dos vectores que queremos multiplicar entre s. Tambin difieren ambas funciones en que la primera no devuelve ningn valor (el cambio resultante de la multiplicacin es directamente asignado al objeto que la llama) y esta en cambio s devuelve un Vector3 con el resultado, que podemos por lo tanto asignar a una variable.

Normalize: function Normalize () : void Esta funcin hace que el Vector3 que la llama pase a tener una magnitude de 1, conservando, eso s, la misma direccin. Como decimos, esta funcin cambia el vector que la llama; si lo que pretendemos es conservar sin cambios el vector corriente y crear un nuevo vector normalizado, hemos de usar -como ya aprendimos en el captulo anterior- la variable normalized.

ToString: function ToString () : String Devuelve nuestro vector convertido en un string y formateado. Para ver cmo funciona, aadamos al final del script que usamos en el ejemplo anterior la siguiente lnea: Debug.Log("Mi vector como string formateado: " + miVector.ToString()); Veremos que nos aparece el vector resultado de la multiplicacin del anterior ejemplo convertido en un string que podemos imprimir.

FUNCIONES DE CLASE: Lerp: static function Lerp (from : Vector3, to : Vector3, t : float) : Vector3 Esta funcin interpola linealmente entre dos vectores, desde from hacia to en el valor t. Vamos a intentar explicarlo de la manera ms clara posible, ya que se trata de una funcin importante: Lerp realiza una lnea imaginaria que va del punto que le pasamos como primer parmetro (from) al punto que le pasamos como segundo parmetro (to). Esa lnea imaginaria es entonces una recta con un origen y un final, y entre ambos extremos tiene muchos puntos intermedios. Pensemos por ejemplo en una regla, para tener ms o menos claro el concepto. Pongamos que al punto de origen (from) le asignamos el valor 0, y al punto final (to) le damos el valor 1. En ese caso, el punto que est en la mitad de nuestra recta imaginaria es evidente que valdr 0,5. Con esto claro planteemos ahora el mismo asunto pero al revs. Tenemos el punto origen y el punto final y queremos saber dnde est la mitad exacta entre esos dos puntos. Lo que haramos es llamar a la funcin Lerp, asignar a los parmetros primero y segundo respectivamente las coordenadas de origen y final y darle al tercer parmetro (que en el prototipo recibe el nombre de "t", y es de tipo float) el valor 0.5. El valor retornado por la funcin se corresponder con el punto situado en el centro de los dos extremos dados.

El parmetro t puede recibir valores entre 0.0 (que coincide con el origen) hasta 1.0 (que coincide con el final). Vamos a practicar. En Unity, le quitamos provisionalmente a nuestro gameobject PortaScripts el script, para que no nos d errores en lo que a continuacin haremos. Acto seguido vamos al men gameobject=> creater other => capsule. Colocamos la cpsula a un valor -3 en el eje x del transform en el inspector. Renombramos a esta cpsula y la llamamos Origen. Creamos luego otra cpsula, y en la coordenada x de su transform la pondremos en 3. La rebautizamos como Fin (Final es una palabra reservada) Es preferible que tengamos la escena enfocada desde la vista superior (lo que conseguimos haciendo click en el eje Y del gizmo) Ahora hacemos doble click en el script (que aunque hemos borrado del Portascripts sigue estando en el Proyecto), y tecleamos: var principio : Transform; var fin : Transform; function Update () { transform.position = Vector3.Lerp(principio.position, fin.position, 0.3); } Salvamos el script y lo arrastramos a nuestro cubo. Acto seguido seleccionamos el cubo y en el inspector nos aparecern nuestras dos variables. Arrastramos origen a principio y destino a fin.

Si todo va bien, nuestro cubo debiera situarse a tres dcimas partes de la lnea hipottica que separa las cpsulas, contando desde la que hemos dado en llamar origen. Lo probamos?

Bien. Parece que funciona, pero podemos ir un poco ms all. Para ello vamos a recurrir a una clase que an no hemos estudiado, que es la clase Time, y concretamente a la variable time de la clase Time. Time.time es una variable que representa los segundos transcurridos desde que el juego se inicia. Por lo tanto, la variable vale cero al iniciarse el juego, 1 un segundo despus, etc. Con esto en mente, vamos a nuestro ltimo script y dentro de la funcin Lerp sustituimos el 0.3 por Time.time, salvamos y le damos al play. Efectivamente, nuestro cubo empieza pegado al origen (el parmetro t, representado por Time.time vale cero) y va desplazndose hacia el fin hasta que t vale 1, o sea, hasta que transcurre un segundo. Sabiendo esto, podemos hacer que el trayecto de nuestro cubo dure por ejemplo diez segundos en lugar de uno. Conseguimos esto meramente multiplicando Time.time * 0.1. Podemos, dndole una vuelta ms de tuerca al asunto, crear una variable expuesta (susceptible de ser accesada desde el inspector) de tipo float, que el usuario pueda modificar, y que al ser multiplicada por Time.time haga que nuestro cubo viaje ms rpido o ms lento.

Slerp: static function Slerp (from : Vector3, to : Vector3, t : float) : Vector3 Esta funcin es similar a la anterior, con la particularidad de que en lugar de interpolar en lnea recta lo hace en forma esfrica. Para probarla no tienes ms que sustituir el trmino "Lerp" del script anterior por "Slerp", y poner el cubo en rbita. Si tienes tiempo y ganas, ubica los gameobjects Origen y Destino en otras posiciones a travs de sus respectivos transforms en el inspector (desplzalos tambin en sus ejes Y y Z).

3. CLASE TRANSFORM

Vamos a dedicar los prximos captulos a estudiar una de las clases ms importantes de la API de Unity. La clase Transform, como vemos en el grfico, hereda de Component, que a su vez deriva de Object, y por lo tanto esta clase tiene como propias las variables y funciones de las dos clases de las que hereda. La pregunta parece obligada: si Transform hereda de Component, por qu no estudiamos la clase Component primero? No lo hacemos porque la clase Component, en el fondo, es poco ms que una recopilacin del resto de clases. Lo veremos mejor si recuperamos el grfico general de clases que vimos en su da:

Si nos fijamos con atencin, observaremos que la mayora de las variables de la Clase component son a su vez instancias (objetos) de un buen nmero de las otras clases, algunas de las cuales incluso -como la propia clase Transform- derivan de sta. Nos veramos pues, caso de estudiar primero la clase Component, obligados a explicar lo que es un transform, un rigidbody, una camera, etc, antes de explicar las clases que los desarrollan. Por lo tanto, para no liarnos en exceso, dejaremos la clase Component para bastante ms adelante. Bien. Qu es un transform?. Posiblemente muchos de los que ya hayan trasteado con la interface de Unity asimilarn esta palabra a la seccin homnima del inspector. Efectivamente, si seleccionamos cualquier gameobject de la escena, automticamente el inspector nos muestra en la seccin transform los valores de posicin, rotacin y escala de dicho gameobject. No puede existir un gameobject en la escena sin su propio transform. Si nos fijamos, hasta nuestro PortaScripts tiene vinculado un transform, pese a que como mero contenedor de scripts no es renderizado en la escena, y por lo tanto es invisible. En consecuencia, todo gameobject en nuestra escena est situado en un lugar determinado de sta (position), con una determinada inclinacin (rotation) y le es aplicada una determinada escala comparativa de tamao (scale). Con esto en mente, empecemos.

VARIABLES: position: var position : Vector3 Esta variable nos indica en qu punto del espacio global se ubica nuestro transform (y por ende el gameobject al que el mismo va vinculado). Recordemos que el espacio global es el que hace referencia a las coordenadas de la escena, y no a las de un determinado objeto. Si quisiramos consultar/indicar el lugar del espacio local de un objeto, utilizaramos la variable localPosition. La variable position es de tipo Vector3, y nos permite tanto obtener los datos de posicin del transform como modificarlos para darle una nueva ubicacin. Por ejemplo, si quisiramos ubicar un objeto en el centro del espacio global, haramos: elObjetoQueSea.transform.position = Vector3(0, 0, 0); Podemos asimismo acceder a uno slo de los ejes de la posicin, tal como sigue: Debug.Log(elObjetoQueSea.transform.position.x); Lo cual nos permitira imprimir la posicin que tiene nuestro transform referida al eje horizontal.

localPosition: var localPosition : Vector3 Como adelantbamos hace un momento, localPosition indica la posicin del transform al que dicha variable pertenece, calculada en trminos relativos al transform del que aqul depende. Parece ms difcil de lo que es en realidad, tal como vamos a demostrar con un ejemplo sencillo: Nos vamos a Unity. Si hemos guardado nuestra ltima sesin, debemos tener en nuestra escena, aparte de nuestro viejo amigo el cubo, dos cpsulas de nombre origen y destino. Eliminamos Destino. Si por lo que sea no hubiramos

conservado las cpsulas, creamos un gameobject capsule nueva. Esa cpsula (u Origen, si guardamos la ltima escena)la ubicamos desde el inspector en la posicin (3, 4, 2) Resumiendo, tenemos en la escena(o debiramos tener) el cubo en las coordenadas de posicin (0,0,0) y una cpsula en la posicin (3,4,2). Ninguno de estos gameobjects es hijo a su vez de otro, por lo que estn y se mueven en coordenadas globales. Abrimos nuestro script y escribimos: transform.position = Vector3(-2,-1,-1); Salvamos y arrastramos el script a nuestro cubo. Al darle al play, vemos que ste se desplaza respecto la posicin que ocupaba en las coordenadas globales (el centro justo) dos unidades a la izquierda, una hacia abajo y una hacia delante. Al darle al pause, nuestro cubo vuelve a su lugar original, en 0,0,0 (es importante retener esto) Vamos ahora a, en la Jerarqua, arrastrar el gameobject cubo y soltarlo dentro de gameobject cpsula (u Origen). Vemos que el cubo mantiene su posicin en la vista de escena, pero si lo seleccionamos (est ahora contenido en la cpsula), sus coordenadas en el transform del inspector son ahora las inversas que las que le dimos al gameobject cpsula. Esto es as porque ahora para el cubo sus coordenadas de posicin no dependen ya del espacio global, sino del local de la cpsula de la cual depende. Para el cubo la coordenada 0,0,0 no es ya el centro de la escena, sino el centro del gameobject capsula, y dado que con respecto a la cpsula el cubo est desplazado tres unidades a la izquierda, cuatro hacia abajo y dos hacia delante, son las que muestra. El hecho de que el cubo dependa de la cpsula o dicho en terminologa Unity, el cubo sea hijo de la cpsula, no implica que no pueda seguir siendo localizado/ubicado en coordenadas globales. De hecho, si le damos al play de nuevo, habida cuenta de que estamos utilizando en nuestro script la variable position (global), el cubo se seguir desplazando al mismo sitio al que lo haca cuando an no dependa de la cpsula. Pero, obviamente, al tener ahora un padre, le podemos aplicar ahora al cubo la variable localPosition, y as podemos modificar el script como sigue: transform.localPosition = Vector3(-2,-1,-1); Vemos ahora que el movimiento del cubo lo es en relacin con la posicin que ocupa pap capsula (o para ser ms precisos el transform de pap cpsula). Probad si no lo veis claro a pasarle un vector (0,0,0) a nuestro script en lugar del que hemos escrito antes. Si le aplicramos esta variable localPosition a un transform sin padre, dicho transform se movera en el espacio global, tal como si le hubiramos aplicado position y no localPosition.

eulerAngles: var eulerAngles : Vector3 Esta variable indica la rotacin del transform en grados. Se corresponde plenamente con los valores que aparecen en el apartado rotation de cada transform en el inspector. Los valores de esta variable vienen dados, al igual que los de position, en formato Vector3. Lo que sucede es que un valor de (90,0,0) referido a la posicin implica que nuestro transform se desplace 90 unidades a la derecha, mientras que los mismos valores relativos a la rotacin implicaran que nuestro transform gire 90 grados (el equivalente a un cuarto de vuelta) sobre el eje X. Al igual que con la variable position, eulerAngles nos permite consultar individualmente la rotacin de nuestro transform sobre un determinado eje. Pero si lo que queremos no es consultar sino cambiar la rotacin, deberemos indicar los tres valores va un Vector3, y Unity los convertir entonces en los valores que l usa internamente. Porque -esto no s si lo he dicho antes- Unity trabaja internamente con Quaterniones, por motivos de rendimiento y

exactitud, mientras que a los humanos nos resulta ms sencillo hacerlo con grados Euler, as que en la prctica esisten unos "atributos de traduccin" que nos permite pasar de quaterniones a grados y viceversa, a fin de que hombres y mquina sigan trabajando con los elementos que mejor se adapten a sus capacidades. Al igual que con position, existe una variable eulerAngles para funcionar con valores globales (la que estamos estudiando) y otra localEulerAngles que trabaja con valores locales (dependientes del padre del transform que rota) A esta variable slo podemos asignarle valores exactos, no de incremento, ya que fallara pasados los 360. Para incrementar una rotacin de esta forma, tenemos que usar la funcin Transform.rotate. Usemos un ejemplo muy simple. Antes arrastremos nuestro cubo en la jerarqua fuera de la cpsula, para desemparentarlo. Y rehacemos por ensima vez nuestro script (que debera continua vinculado al cubo) transform.eulerAngles = Vector3(60,0,0); Podis ver que nuestro cubo ha girado un 60 grados sobre el eje X, entendido ste como un alambre invisible que cruza de manera horizontal la escena (por decirlo de alguna manera) Como colofn, aadir que Unity automticamente convierte los angulos Euler que le pasamos al transform en los valores usados para la rotacin almacenada en Transform.rotation.

localEulerAngles: var localEulerAngles : Vector3 Aqu no deberamos necesitar grandes explicaciones: localEulerAngles se refiere a la rotacin en grados de un transform con relacin a la que tiene el transform del cual depende en una relacin hijo/padre. Al igual que con la variable anterior, Unity automticamente convierte los angulos Euler en los valores usados para la rotacin almacenada en Transform.localRotation.

rotation: var rotation : Quaternion Es la variable que contiene la rotacin del transform en el mundo global almacenada en quaterniones. Como ya hemos dicho, Unity almacena internamente todas las rotaciones en quaterniones, lo cual no quiere decir que nosotros tengamos que trabajar directamente con ellos. Por norma general, o bien trabajaremos con grados Euler que luego se convertirn implcita o explicitamente en quaterniones, o bien a lo sumo usaremos alguna funcin que nos permita encapsular las operaciones con quaterniones.

localRotation: var localRotation : Quaternion Obviamente, esta variable indica la rotacin en quaterniones de un transform relativa a la rotacin de su padre

right, up y forward: var right : Vector3 var up : Vector3 var forward : Vector3 Estas variables hacen referencia respectivamente al eje X(derecha/izquierda), Y (arriba/abajo) y Z(delante/detrs) de las coordenadas globales del transform. No las hemos de confundir con las variables del mismo nombre de la estructura Vector3. As, Vector3.up es un atajo que equivale a Vector3(0,1,0), esto es, implica un movimiento de una unidad hacia arriba. En cambio, transform.up meramente hace referencia al eje arriba/abajo, pero no implica movimiento. Para mover un transform por esta va tendramos que hacer algo como esto: En Unity eliminamos el script que tenemos vinculado a nuestro cubo. En Proyecto abrimos nuestro script y tecleamos: var unObjeto : GameObject; unObjeto.transform.position = transform.right*10; unObjeto.transform.eulerAngles = transform.up*45; Arrastramos nuestro script tras salvarlo a PortaScripts en la Jerarqua y con Portascripts seleccionado arrastramos el cubo a la variable expuesta. Play. Efectivamente, el cubo se desplaza 10 unidades a la derecha y 45 grados sobre el eje Y.

localScale: var localScale : Vector3 Como su nombre indica, es una variable de tipo Vector3 que permite consultar o establecer la escala de un transform en relacin con la de su padre. Obviamente, un transform con esta variable en 0,0,0 tendr la misma escala que su padre.

parent: var parent : Transform Hace referencia al padre del transform (que es obviamente otro transform), y a travs de esta variable se puede consultar y/o cambiar dicho padre. Veamos primero de qu forma podemos consultar valores relativos al padre de nuestro transform: Nos vamos a Unity, arrastramos en la Jerarqua el cubo dentro de la cpsula, y a PortaScripts le borramos el script para que no nos d errores. En Proyecto le damos doble click a miPrimerScript y escribimos lo que sigue: Debug.Log(transform.parent.gameObject.name); Arrastramos tras salvar el script dentro del cubo (que est dentro de la cpsula). Play. Aparece el nombre de la cpsula,que es lo que pretendamos. Fijaros cmo a travs del operador punto le decimos al Unity (leyendo de derecha a izquierda) que busque el nombre del gameobject al que pertenece el transform que es el padre del transform del gameobject que hace la consulta (al que va vinculado el script) y lo imprima en pantalla. Vamos ahora a darle un padre nuevo a nuestro cubo. Abrimos el script y, sin borrarla, desplazamos la declaracin que habamos escrito un par de renglones hacia abajo, y encima escribimos lo siguiente:

var nuevoPadre : Transform; transform.parent = nuevoPadre; Debug.Log(transform.parent.gameObject.name);//Esto ya lo tenamos escrito Salvamos, y seleccionamos el cubo para que en el inspector quede expuesta la variable nuevoPadre. Arrastramos hasta ella la cmara principal desde la jerarqua y le damos al play. Nuestro cubo ha cambiado de padre. Pensemos, llegados a este punto, que nuestro transform hijo tiene una posicin, rotacin y escala relativa con respecto a su padre. Si cambiamos su padre, stas obviamente cambiarn.

root: var root : Transform Esta variable hace referencia al transform ms alto de la jerarqua, por lo que guarda muchas similitudes con parent, pero referida al parent de los parent del que depende nuestro transform. Si ste tiene un padre sin padre, el resultado equivaldr a parent. Si su padre tiene un padre que tiene un padre que tiene un padre, la variable ir escalando hasta llegar al ltimo padre y devolver su valor (o nos permitir modificar dicho valor). Para el caso de que el objeto que invoca esta variable no tenga padre, lo que se devuelve no es null, sino el propio transform que la invoca.

childCount: var childCount : int Es meramente una variable de tipo int que indica el nmero de hijos que tiene un transform.

lossyScale: var lossyScale : Vector3 Es esta una variable de tipo Vector3 que representa la escala global del objeto. Es una variable de slo lectura, por lo que obviamente no podemos modificar la escala global (la local ya vimos que s con localScale) asignando valores a esta variable.

FUNCIONES: Translate: function Translate (translation : Vector3, relativeTo : Space = Space.Self) : void Esta funcin nos permite mover el transform en la direccin y distancia indicados en el parmetro de tipo Vector3 traslation. El segundo parmetro nos permite decidir si el transform se mover segn sus propias coordenadas (locales) o lo har en base al espacio global. Por defecto, si no indicamos el segundo parmetro, Unity entiende que el transform se mover segn sus propias coordenadas (Space.Self). Desarrollemos esto con un ejemplo: Para empezar, desemparentamos nuestro cubo respecto de la cpsula, arrastrndolo a un espacio vaco de la jerarqua. Acto seguido, con el cubo seleccionado, en el inspector le asignamos a la coordenada Y de rotacin un valor de 35. Abrimos el script que tenemos asignado al cubo y tecleamos:

transform.Translate(Vector3.forward * 5); Salvamos y presionamos play. El cubo avanza cinco unidades en su eje Y, y recalcamos lo de "su" eje, ya que al no aadirle un segundo parmetro que diga lo contrario, se mueve segn sus coordenadas locales. Para ver la diferencia, aadamos como segundo parmetro a la funcin la variable World de la enumeracin Space, para que sustituya al parmetro por defecto Space.Self: transform.Translate(Vector3.forward * 5, Space.World); function Translate (x : float, y : float, z : float, relativeTo : Space = Space.Self) : void Existe un segundo prototipo para la funcin Translate. Como se puede comprobar, se diferencia del primero en que en lugar de pasar como parmetro para establecer la direccin y longitud del movimiento un Vector3, se pasa cada eje como un float independiente. function Translate (translation : Vector3, relativeTo : Transform) : void function Translate (x : float, y : float, z : float, relativeTo : Transform) : void Estos dos prototipos varan de los anteriores en el segundo parmetro, que ya no versa sobre si el movimiento se har tomando en cuenta las coordenadas locales del objeto que se mueve o las globales de la escena. En cambio, aqu el movimiento de nuestro transform vendr fijado por otro transform. De esta manera, nos moveremos de acuerdo con las coordenadas locales de ese segundo objeto al que hacemos referencia. Si por ejemplo el parmetro relativeTo es una cmara, la derecha del traslation no es la derecha local de nuestro transform, o la derecha global, sino la derecha de la cmara. Por ejemplo:

Tecleamos lo siguiente en nuestro script transform.Translate(Vector3.right * 5); Esto har que nuestro cubo se mueva cinco unidades a su derecha. Y ahora modificamos el script para que quede as: var miCamara : Transform; transform.Translate(Vector3.right * 5, miCamara); Arrastramos la cmara principal hasta la variable miCamara. De nuevo al play. Ahora el cubo se mueve cinco unidades a la derecha de la cmara. Como ltimo apundo hemos de aadir que si relativeTo es nulo, las coordenadas del movimiento pasarn a ser las globales.

Rotate: function Rotate (eulerAngles : Vector3, relativeTo : Space = Space.Self) : void Esta funcin permite rotar un transform. Acepta como parmetro un Vector3 con los grados de rotacin en ngulos Euler. Por defecto, al igual que sucediera con la funcin translate, el transform rota sobre sus coordenadas locales, pudiendo hacerlo segn las coordenadas globales si se lo indicamos con Space.World como segundo parmetro.

Veamos un ejemplo. Rehagamos nuestro script con el siguiente contenido: function Update() { transform.Rotate(Vector3.right * 25 * Time.deltaTime); transform.Rotate(Vector3.up * 20 * Time.deltaTime, Space.World); } Al darle al play, observaremos que nuestro cubo rota sobre su eje X a razn de 25 grados por segundo mientras a la vez gira sobre el eje Y global a razn de 20 grados por minuto. Es de sealar que ambas instrucciones se encuentran contenidas dentro de la funcin Update. Esta funcin, que en su momento estudiaremos con la debida profundidad, es llamada cada frame por nuestro ordenador (el framerate de cada ordenador vara), de tal manera que el movimiento es contnuo, pues los valores de rotacin de nuestro cubo son actualizados constantemente. Precisamente porque el framerate de cada ordenador es distinto, y para evitar que en funcin de cada PC los objetos se movieran ms o menos deprisa (lo que tendra indeseables consecuencias, sobre todo en juegos en lnea multijugador), se suele utilizar la variable de la clase Time Time.deltaTime. Time.deltaTime lo que consigue es transformar la unidad de frecuencia de cualquier tipo de movimiento de frames a segundos. Si por ejemplo en el ltimo script no hubiramos usado estas variables de tiempo, el cubo girara 25 y 20 grados cada frame, quedando al albur de cada ordenador la frecuencia real que eso supondra. Al multiplicarlo por Time.deltaTime las rotaciones dependern del tiempo y en consecuencia se producirn con la misma cadencia en cualquier ordenador. function Rotate (xAngle : float, yAngle : float, zAngle : float, relativeTo : Space = Space.Self) : void En esta versin de la funcin, la nica diferencia es que se sustituye el Vector3 por tres floats, en los cuales se consignarn igualmente los grados de rotacin. function Rotate (axis : Vector3, angle : float, relativeTo : Space = Space.Self) : void La variante que nos ofrece este tercer prototipo es que por un lado se indica en el primer parmetro sobre qu eje queremos que rote el transform, y en un segundo parmetro de tipo float le hemos de indicar el nmero de grados ha de rotar.

RotateAround: function RotateAround (point : Vector3, axis : Vector3, angle : float) : void Esta funcin nos permite que nuestro transform rote alrededor de un punto (u objeto situado en ese punto), como si orbitara. El parmetro point sera el punto, descrito por un Vector3, alrededor del cual queremos hacer girar nuestro transform. Axis nos servir para indicar sobre qu eje queremos girar, y angle el nmero de grados por frame (si est dentro de la funcin update) o por segundo (si implicamos la variable de clase Time.deltaTime) que queremos que gire. Obviamente, aqu estamos variando tanto la rotacin como la posicin de nuestro transform. si por ejemplo quiriramos que nuestro cubo girara sobre su eje Y alrededor del centro exacto del espacio global, a razn de 20 grados por segundo, escribiramos este script: function Update() { transform.RotateAround (Vector3.zero, Vector3.up, 20 * Time.deltaTime); } Dado que el cubo se hallaba ya en las coordenadas globales 0,0,0 el script anterior lo nico que consigue es que el cubo parezca girar sobre s mismo. Vamos a hace lo siguiente: colocamos en el inspector a nuestro cubo en position.x = -1, y

volvemos a darle al play. Y vemos ya ms claramente cmo orbita alrededor del punto dado, cambiando simultneamente de posicin y de rotacin. Podemos hacer tambin con esta funcin que un objeto orbite alrededor de otro. Escribimos: var centroDeGravedad: Transform; function Update() { transform.RotateAround (centroDeGravedad.position, Vector3.up, 20 * Time.deltaTime); } Acto seguido, arrastramos el objeto sobre el que queremos que orbite nuestro cubo, en este caso la cpsula. Le damos al play y comprobamos. Observemos que aunque arrastramos un gameobject, lo que est esperando nuestro scrips es un transform. Lo que sucede es que -tal como vimos en las primeras lecciones- todos los componentes de nuestro gameobject comparten nombre, de tal manera que cuando en casos como este Unity detecta que uno de los componentes del gameobject que le estamos arrastrando tiene el nombre y el tipo del que est esperando para cumplimentar una variable, automticamente selecciona en este caso- el transform homnimo y no el gameobject. Ese transform, no obstante, no es del tipo Vector3 que espera nuestra funcin. S que lo es la variable position del mismo, que adems contiene las coordenadas globales del transform sobre el que queremos orbitar. Podis probar a sustituir en el segundo parmetro Vector3.up por Vector3.right (o Vector3.forward), y comprobar qu es lo que sucede.

LookAt: function LookAt (target : Transform, worldUp : Vector3 = Vector3.up) : void El nombre de esta funcin se podra traducir al castellano como "mira a", y es exactamente eso lo que hace: Rotar nuestro transform hacia un objetivo -parmetro target- que es asimismo de tipo transform (y no Vector3, como en el caso de la funcin anterior). Esa rotacin se efecta sobre un eje global, y por defecto ste ser el eje Y. Ello implicar que nuestro transform, si no le indicamos lo contrario, girar hacia la derecha y la izquierda "mirando" al transform que hayamos designado como objetivo. Huelga decir que esta funcin se usa mucho para cmaras, cuando pretendemos que stas sigan en todo momento a un determinado personaje. Es importante avisar de que para que el transform gire sobre el eje que le indiquemos, ha de estar totalmente perpendicular a dicho eje global. Vamos a la prctica. En el Proyecto, colocamos el ratn sobre la carpeta Mis Scripts y le damos al botn derecho=>create=>javascript. Al nuevo script lo renombramos como MiSegundoScript y le damos doble click para se se nos abra el editor. Desplazamos un poco hacia abajo la funcin Update, y la dejamos como sigue: var sigueme : Transform; function Update () { transform.LookAt(sigueme); }

Salvamos, y la arrastramos hasta nuestra cmara en la jerarqua. Seleccionamos entonces la cmara y arrastramos ahora hasta la variable sigueme nuestro cubo. Previamente a darle al play nos aseguramos de que el otro script (MiPrimerScript) que tenemos vinculado al cubo, contenga lo siguiente: var centroDeGravedad: Transform; function Update() { transform.RotateAround (centroDeGravedad.position, Vector3.up, 20 * Time.deltaTime); } Y ahora s, ya podemos darle al play y perseguir a nuestro cubo. function LookAt (worldPosition : Vector3, worldUp : Vector3 = Vector3.up) : void Este segundo prototipo se diferencia del primero en que el objetivo que ha de seguir nuestro transform no es otro transform, sino un Vector3. Esto tiene sentido, siguiendo con el ejemplo de la cmara, si quisiramos que sta enfocara un punto concreto de la escena (en coordenadas globales) Por ejemplo, si queremos que una cmara enfoque al centro de la escena, le vinculamos este script: transform.LookAt(Vector3.zero); Otra posibilidad que nos permite esta funcin es que sea nuestro jugador, desde su teclado, quien se encargue de decidir dnde ha de enfocar la cmara. Para ello tendremos que recurrir a una clase que an no hemos visto, la clase input. Abrimos el script MiSegundoScript, y tecleamos lo que sigue: function Update () { transform.LookAt(Vector3(Input.GetAxis("Horizontal") * 10.0,0,0)); } Le damos al play y movemos la cmara con las flechas de desplazamiento horizontal. Quizs notemos que el resultado es un poco basto, pero meramente quera que tuvirais una idea de las utilidades de esta funcin. Tambin podramos controlar la cmara desde el ratn y no desde el teclado. Veremos todo esto en profundidad cuando estudiemos la clase input.

TransformDirection: function TransformDirection (direction : Vector3) : Vector3 Esta funcin toma como nico parmetro la direccin local de un transform almacenada en un Vector3 y la convierte en direccin global, devolvindola en otro Vector3. La utilidad de esta funcin puede resultar un poco confusa al principio. Pensemos, para intentar aproximarnos al concepto, que quisiramos hacer nuestra propia versin del FIFA 2011. Modelamos un campo de futbol y, para darle ms realismo y emocin al juego, colocamos varias cmaras en los laterales del campo, cmaras que mediante LookAt iran siguiendo los lances del juego. El problema que nos encontraramos es que cuando Messi (por poner un caso) est avanzando hacia delante (en las coordenadas globales), en cambio en nuestra cmara lateral pareciera que lo est haciento -por ejemplohacia la izquierda. Y en consecuencia, cuando intentamos que nuestro defensa lo ataje movindolo hacia atrs (segn la perspectiva que nos da la cmara lateral) veremos consternados que el defensa en lugar de retroceder se desplaza hacia la derecha. Esto no nos pasara si, gracias a esta funcin, convertimos la coordenada "hacia detrs" de nuestra cmara en su

equivalente en coordenadas globales. Si esa funcin se la aplicamos a todas las cmaras, no tendremos que estar pensando "Ojo, que esta cmara est en el gol norte, por lo que si me baso en ella cuando haga un movimiento, he de recordar que arriba es abajo y viceversa y la derecha es la izquierda y bla, bla, bla". Vemoslo en un ejemplo. En Unity borramos el script MiSegundoScript de la cmara. Colocamos en el inspector a nuestro cubo en las coordenadas 0.0.0. con una rotacin igualmente de 0,0,0. Asimismo, la cmara debera estar en las coordenadas de posicin 0,1,-5 con los tres ejes de rotacin a 0. Abrimos MiPrimerScript. Tecleamos esto: var miCamara : Transform; var estaEsMiDerecha : Vector3; estaEsMiDerecha = miCamara.TransformDirection(Vector3.right); transform.Translate(estaEsMiDerecha * 3); Arrastramos la cmara a miCamara. Le damos al play. El cubo se mover 10 unidades a la derecha. Pero, a la derecha de quin?. Si observamos, la derecha del cubo es tambin la derecha de la cmara. Para averiguarlo, vamos a recolocar la cmara en estas coordenadas: Position: -10, 1, -0.5 Rotation: 0, 90, 0 Y de nuevo le damos al play. Obviamente, el cubo se mueve a la derecha de la cmara. Visto desde la ventana game, coincidir ahora "nuestra" derecha (entendiendo como tal la que nos muestra la pantalla) con el sentido el movimiento.

El script no necesita mucha explicacin. Inicializamos una variable con el transform de la cmara que hemos arrastrado. La derecha de esa cmara la almacenamos en una variable de tipo Vector3, la cual luego pasamos como parmetro a nuestra funcin TransformDirection para que nos convierta la derecha de nuestra cmara en la derecha de las coordenadas

globales. A partir de ah, todo lo que le suceda a la derecha de nuestra cmara (por as decirlo) le estar pasando a la derecha del mundo. function TransformDirection (x : float, y : float, z : float) : Vector3 Es la misma funcin, pero aplicando como parmetros 3 floats para cada eje en lugar de un Vector3.

InverseTransformDirection: function InverseTransformDirection (direction : Vector3) : Vector3 o bien function InverseTransformDirection (x : float, y : float, z : float) : Vector3 Se trata obviamente de la funcin inversa a la anterior, y por consiguiente transforma una direccin global en direccin local. Veamos un ejemplo: Devolvemos antes que nada a nuestra cmara a su lugar y rotacin originales: Position: 0,1,-5 Rotation: 0,0,0 La posicin y rotacin de nuestro cubo, por su parte, est totalmente a 0. Abrimos MiPrimerScipt, y tecleamos: var estaEsLaDerechaDelMundo : Vector3; estaEsLaDerechaDelMundo = transform.InverseTransformDirection(Vector3.right); transform.Translate(estaEsLaDerechaDelMundo * 2); Como vemos, declaramos una variable de tipo Vector3 que luego inicializamos de la siguiente forma: le pasamos a la funcin InverseTransformDirection el parmetro Vector3.right, que en esta funcin representa la derecha en coordenadas globales (no la derecha de ningn transform). Esa derecha del mundo, global, es "traducida" por la funcin en una coordenada local susceptible de usar por cualquier transform y es asignada,como decamos, a nuestra variable estaEsLaDerechaDelMundo. Dicha variable, por ltimo, es pasada como parmetro de movimiento al transform del gameobject que tiene vinculado el script (en este caso el cubo). La probamos? El cubo se desplaza a la derecha. Pero, para saber si la derecha es la derecha del cubo o la derecha global, podemos en el inspector darle un valor al rotation.Y del cubo de 45 grados, por ejemplo. Y probamos de nuevo.

Definitivamente, el cubo se mueve ahora siguiendo el eje X global, y no el suyo local.

TransformPoint: function TransformPoint (position : Vector3) : Vector3 function TransformPoint (x : float, y : float, z : float) : Vector3 A diferencia de TransformDirection, lo que esta funcin transforma de local en global es la posicin y no la direccin. Esto es, esta funcin no versa sobre si un transform se desplaza a su derecha o a la derecha de las coordenadas globales, sino de si las coordenadas en que se encuentra el transform son globales (respecto al mundo) o locales (respecto al padre de dicho transform). Con esto entendido, como decimos, esta funcin acepta como parmetro las coordenadas locales de un transform (su ubicacin respecto de la de su padre) y devuelve dichas coordenadas traducidas a coordenadas globales.

Lo veremos ms claron con un ejemplo. Con el cubo en position 0,0,0 y rotation en 0,0,0 (si no,no funcionar) arrastramos el cubo dentro de la cpsula en la Jerarqua, para convertir a cubo en hijo de la cpsula. Si seleccionamos el cubo, vemos en el inspector que sus coordenadas de posicin han pasado a ser locales respecto de su padre. Abrimos MiPrimerScript (que debera seguir siendo parte del cubo) y escribimos el siguiente script: var coordenadasLocales : Vector3; var coordenadasGlobales: Vector3; var coordenadasTransformadas: Vector3; coordenadasLocales = transform.localPosition; coordenadasGlobales = transform.position; coordenadasTransformadas = transform.position = transform.TransformPoint(transform.localPosition); Debug.Log("El cubo tiene las coordenadas locales " + coordenadasLocales.ToString() + " las globales " + coordenadasGlobales.ToString() + " y las transformadas " + coordenadasTransformadas.ToString()); El ejemplo parece ms complicado de lo que es. Declaramos tres variables de tipo Vector3 para que contengan las tres

coordenadas que imprimiremos para nuestro cubo (los nombres de las variables son lo suficientemente explicativos). Acto seguido inicializamos las dos primeras variables con la posicin global y local del transform, y la tercera con las coordenadas que tendr el transform cuando convirtamos sus coordinadas locales (respecto de la cpsula) en globales. Salvamos y le damos al play. Observamos que por un lado el cubo se desplaza en direccin y distancia opuesta al cilindro, ya que el -3,-4,-2 que constituan sus coordenadas locales ahora ha pasado a ser su posicin en coordenadas globales.

InverseTransformPoint: function InverseTransformPoint (position : Vector3) : Vector3 function InverseTransformPoint (x : float, y : float, z : float) : Vector3 Funcin inversa a la precedente, que por tanto transforma la posicin de un transform dado del espacio global al espacio local.

DetachChildren: function DetachChildren () : void Es una funcin muy sencilla que sirve para desparentar los hijos. Para probarla debemos eliminar el script vinculado al cubo, y posteriormente hacer doble click en MiPrimerScript en el Proyecto para teclear lo siguiente: transform.DetachChildren(); Salvamos y lo arrastramos a la cpsula, que es el transform que tiene hijos. Le damos al play y observaremos cmo en la Jerarqua el cubo deja de aparecer como hijo de la cpsula. Esta funcin es til, entre otras cosas, cuando por alguna razn queramos destruir al objeto padre sin destruir a sus hijos: transform.DetachChildren(); Destroy(gameObject);

Find: function Find (name : String) : Transform Con esta funcin podemos buscar por su nombre -y en su caso acceder- a un transform hijo de nuestro transform. La funcin devuelve dicho transform hijo, si lo encuentra. Si no lo encuentra, retorna null. Si tenemos que buscar a varios niveles, esto es, hijos de los hijos de nuestros hijos, podemos utilizar un slash o barra inclinada (/) para recrear la jerarqua donde queremos buscar (p ej. "Cuerpo/Brazo/Mano/Indice") Dado que deberamos tener el cubo an dentro de la cpsula, y MiPrimerScript vinculado a sta, lo aprovecharemos para realizar un ejemplo: var aquiMiHijo : Transform; function Update() { aquiMiHijo = transform.Find("Cubo"); aquiMiHijo.Rotate(Time.deltaTime*60, 0, 0); }

Como podemos comprobar al darle al play, la funcin Find encuentra un transform hijo llamado "Cubo" (recordemos que, por un lado hemos de suministrarle un string, esto es, no nos debemos olvidar de las comillas, y por otro lado que todos los componentes de un gameobject comparten por defecto el mismo nombre que ste, as que el transform del Cubo se llama Cubo), y almacena ese transform que encuentra dentro de la variable aquiMiHijo. A partir de ah, podemos utilizar esa variable como si fuera un alias del propio transform.

IsChildOf: function IsChildOf (parent : Transform) : boolean Esta funcin casi no requiere explicacin. Devuelve true si el transform que hace la pregunta es hijo, "nieto" o incluso idntico al transform parent que pasamos como parmetro. En otro caso, devuelve false. Y con esto acabamos la clase transform, que como deca al inicio es una de las diez clases ms importantes de la API de Unity.

4. CLASE RIGIDBODY

Nos disponemos a estudiar otra de las clases vitales para entender el funcionamiento de Unity. Es raro en juego en el que no interviene de alguna manera la fsica (un enemigo se cae, un personaje salta, y coche choca contra un muro...) La clase Rigidbody controla la posicin de un objeto a travs de simulacin de fsica. El componente Rigidbody, al ser aadido a un gameobject, toma el control sobre la posicin de un objeto, haciendo que caiga bajo la influencia de la gravedad, y puede calcular cmo los objetos respondern a las colisiones. Vamos a inspeccionar unas cosas en Unity: antes que nada, si estis siguiendo por orden estas lecciones tendris (como yo) emparentado el cubo dentro de la cpsula, as que lo arrastramos fuera para desemparentarlo. Luego, con el cubo seleccionado, echamos un vistazo al inspector. Vemos en l diferentes apartados (su transform, su malla, un collider y elementos de renderizado) pero no un rigidbody. Lo mismo nos pasara si examinamos la cpsula. Ambos objetos, por lo tanto, no estn sometidos a leyes fsicas, y en consecuencia es como si carecieran de masa y por ende fueran ajenos a la gravedad. Vamos a regalarles un rigidbody a nuestros objetos. Para hacer eso nos vamos -con uno de los obtetos seleccionado- al men superior, y le damos a Component=>Physics=>Rigidbody. El gameobject que tenamos selecionado tiene ahora un componente nuevo:

Hacemos lo mismo con el otro gameobject. Acto seguido, en la ventana Escena pulsamos la X de nuestro gizmo,para tener una visin de los objetos desde el eje horizontal, y comprobar mejor lo que pasar ahora. Le damos al play... y los objetos caen, porque ya no son inmunes a la gravedad.

Lo que procede ahora, para evitar que nuestros objetos abandonen la escena a la primera de cambio, es colocar un suelo. Vamos a ello. Antes que nada, vamos a eliminar a nuestra vieja amiga la cpsula (conocida por los ms veteranos por Origen). La razn es que por su forma especfica no es demasiado estable para nuestros ejemplos una vez se ve afectada por la gravedad. As que adis, cpsula. Y como a rey muerto, rey puesto, nos vamos al men y le damos a GameObject=>Create other=>Sphere. La renombramos como "Esfera". A continuacin vamos a colocar a nuestros dos objetos a ras de suelo (antes no importaba que estuvieran flotando por ah, pero ahora no querremos empezar el juego con un objeto pegndose un tortazo contra el suelo). Colocamos, como decimos, nuestros objetos en las siguientes coordenadas de posicin (las rotaciones deben estar a 0): Cubo: 0,0,0. Esfera: 2,0,2. Nos vamos ahora al men=>Gameobject=>Create Other=>Plane. Lo renombramos antes que nada como "Suelo". Luego colocamos nuestra ventana de escena en vista superior (click en eje Y del gizmo), y para acabar, en la coordenada Y de su transform.position escribimos -0.5. Esto ltimo supongo que merece una explicacin. Veamos, tanto el cubo como la esfera tienen una altura de una unidad y su origen (el 0,0,0) de dichos objetos se halla en su centro geomtrico. Esto quiere decir que cuando un cubo est en el valor 0 de su eje Y, la mitad del cubo (0,5) se halla por debajo del nivel 0 (que es donde hemos colocado el suelo). En definitiva, si tanto el cubo como la esfera y el suelo los dejramos con sus respectivos ejes Y a cero, los dos primeros apareceran semienterrados en el tercero. Para evitarlo, o bien levantamos todos los objetos o bien bajamos el suelo, que es lo que hemos hecho. Dmosle al play. Observamos que los objetos ya no se caen, aunque a decir verdad y siendo todos los elementos de nuestra escena del mismo color, quizs nos interesara ponerle a nuestro suelo un color que los hiciera resaltar. Con el mouse situado sobre la carpeta Mis Scripts, pulsamos el botn derecho y creamos otro script (javascript, recordemos). Lo llamaremos ColorSuelo, y dice as: function Start() { renderer.material.color=Color.red; } La funcin Start es llamada por Unity, como su nombre indica, cuando se inicia el juego. Slo es llamada una vez, a diferencia de Update, y en este caso nos interesa que sea as ya que vamos a dejar el color de nuestro suelo fijo durante todo el juego. Salvamos y arrastramos el script a Suelo. Le damos al play.

Y voil, el suelo se nos vuelve de color rojo y los objetos contrastan algo ms. An y todo, la escena contina un poco oscura, as que mejor iluminarla un poco, no? Introducimos en la escena desde el men gameobject una luz direccional, que renombraremos como "Luz" y ubicaremos/rotaremos en las siguientes coordenadas: Posicin: -5,15,-10 Rotacin: 20,0,0 Si le damos al play, deberamos ver algo parecido a esto:

Y ms o menos con esto tendramos ya la escena "preparada" para empezar a trabajar con la clase Rigidbody.

De un mero vistazo al siguiente grfico podris sin duda deducir dos cosas:

1.- La clase Rigidbody es "hermana" de la clase Transform. Estn al mismo nivel y heredan de las mismas clases. 2.- Nos va a ocupar un buen nmero de lecciones estudiarla. Pero el esfuerzo veris que merece la pena, ya que dominando las clases Transform, Rigidbody (y Collider con sus dos clases hijas, que estudiaremos tras Rigidbody) tendremos controlado en gran parte el tema del movimiento y reaccin ante el movimiento ajeno de nuestros gameobjects. Y sin ms dilacin, vamos all.

VARIABLES: velocity: Var velocity : Vector3 Representa a travs de un vector la velocidad del rigidbody. No es aconsejable en la mayora de casos modificar esta variable directamente, ya que derivara en un comportamiento poco realista (no habra una transicin entre la velocidad (o incluso inactividad) anterior y la nueva velocidad. S est justificado en cambio su uso para aquellos cambios de velocidad que provienen de un impulso, como por ejemplo un salto. function FixedUpdate () { if (Input.GetButtonDown ("Jump")) { rigidbody.velocity = Vector3(0,6,0); } } Tecleamos este script en MiPrimerScript, lo salvamos y lo arrastramos al cubo. Hay varias cosas del mismo que necesitarn una explicacin. Para empezar, vemos que se est usando una funcin llamada FixedUpdate. Esta funcin es parecida a la funcin Update, de la que ya habamos hablado, pero a diferencia de sta, FixedUpdate es llamada (actualizada) a intervalos regulares (fijos). Por lo tanto, as como en la funcin Update la actualizacin depende del framerate de cada ordenador, en la funcin FixedUpdate la actualizacin se produce en

intervalos fijos, iguales para todos los ordenadores. Por esa razn, cuando tratamos con cuestiones relacionadas con la fsica (y toda la clase Rigidbody est relacionada con la fsica) habremos de usar la funcin FixedUpdate y no la funcin Update (salvo que queramos que las cadas, colisiones y velocidad de los objetos de nuestro juego sean diferentes en funcin del ordenador con el que juguemos o que, yendo an ms all, en un juego online multijugador el personaje de cada user vaya a una velocidad distinta, por ejemplo.) Lo segundo nuevo del script es una referencia a la clase input. La clase input (otra de las clases que ocupan el top ten de importancia en Unity) es la que controla los eventos, esto es, qu tiene que hacer el usuario para disparar, qu tecla hace qu cosa, qu tipo de colisiones provocan que pase otra cosa distinta, etc. En este caso, Input.GetButtomDown(string) dispara un evento cuando el usuario pulsa la tecla que le pasamos a la funcin como un string. En nuestro Script le pasamos el string "Jump", que por defecto se corresponde a la barra espaciadora. Y qu sucede cuando le damos a la barra espaciadora?. Pues que al rigidbody que en el captulo anterior le aadimos a nuestro cubo le ser aumentada de golpe la velocidad en el vector Y (arriba/abajo). Para comprobarlo, dale al play y cuando el juego est corriendo presiona la barra espaciadora.

angularVelocity: Var angularVelocity : Vector3 Vector que representa la velocidad angular del rigidbody. Por velocidad angular nos referimos a la velocidad de rotacin. Al igual que con velocity, en la mayora de casos no cambiaremos la velocidad directamente, pues salvo casos en que precisamos un impulso sbito de la velocidad, no queda realista. Para entender bien la diferencia entre velocidad y velocidad angular, vamos a completar el script anterior, permitindonos aplicar una u otra velocidad, o incluso ambas a la par. MiPrimerScript quedar as: function FixedUpdate () { if (Input.GetButtonDown ("Jump")) { rigidbody.velocity = Vector3(0,6,0); } if (Input.GetButtonDown ("Horizontal")) { rigidbody.angularVelocity = Vector3(7,0,0); } } Como podemos observar, hemos aadido un segundo if de tal manera de que si el jugador en lugar de presionar la barra espaciadora (jump) presiona cualquiera de las dos flechas horizontales de direccin del teclado, la velocidad que se aplique al cubo ser velocidad angular. Salvamos, le damos al play y pulsamos cualquiera de las flechas horizontales. Probablemente observaremos que el cubo hace intencin de girarse, pero no tiene la fuerza suficiente para hacerlo. Si, en cambio, pulsamos la barra espaciadora y mientras el cubo est en el aire presionamos la flecha horizontal, asistiremos seguramente a una bonita pirueta de nuestro cubo.

drag: Var drag : float Indica la resistencia al movimiento de un objeto y por lo tanto se usa para enlentecer dicho objeto. Cuando ms algo el valor, mayor resistencia. Vemoslo aadiendo un tercer if a nuestro script, de tal forma que quede as:

function FixedUpdate () { if (Input.GetButtonDown ("Jump")) { rigidbody.velocity = Vector3(0,6,0); } if (Input.GetButtonDown ("Horizontal")) { rigidbody.angularVelocity = Vector3(7,0,0); } if (Input.GetKeyDown ("z")) { rigidbody.drag = 10; } } Salvamos. La funcin GetKeyDown de la clase input dispara un evento cuando el user presiona una determinada tecla, en nuestro ejemplo la zeta. Le damos al play y lanzamos al aire nuestro cubo presionando la barra espaciadora, y cuando est en el aire presionamos la z. Observaremos cmo los movimientos del cubo se enlentecen. Si a continuacin volvemos a presionar la barra espaciadora o la flecha horizontal, comprobaremos que la resistencia al movimiento de nuestro cubo es mucho mayor.

angularDrag: rigidbody.angularDrag = 10; Indica la resistencia angular del objeto. Puede ser usado para enlentecer la rotacin de un objeto.

mass: Var mass : float Variable que representa la masa del rigidbody, su peso. Recomienda el manual de referencia que el valor de la masa debera estar entre 0.1 y 10. Masas grandes -segn el manual- hacen las simulaciones fsicas inestables. Obviamente, los objetos con mayor masa proyectan a los que tienen menos masa cuando chocan. Pensemos en un camin grande golpeando un coche pequeo. Vamos a verlo con un ejemplo sencillo. Para llevarlo a cabo eliminamos el script que tiene vinculado nuestro cubo. Luego seleccionamos la esfera, y la ubicamos en las coordenadas -3,0,0. Acto seguido hacemos doble click en MiPrimerScript para abrir el editor y tecleamos lo que sigue: function FixedUpdate () { if (Input.GetButtonDown ("Horizontal")) { rigidbody.velocity = Vector3(9,0,0); } } Salvamos y arrastramos el script a la esfera. Este no tiene mucho misterio: al presionar la flecha horizontal del teclado, nuestra esfera debera tomar una velocidad de aceleracin hacia su derecha, por lo que en principio debera impactar con el cubo. Probmoslo. Play. Observamos que efectivamente al pulsar la flecha de desplazamiento horizontal, la esfera golpea contra el cubo con la suficiente fuerza como para incluso volcarlo. Si nos fijamos, en los respectivos rigidbodies del cubo y la esfera que aparecen en el inspector, ambos tienen una mass de 1. Debido a ello, a raz del impacto no hay un objeto que parezca "salir victorioso" de este (el cubo gira una cara y la esfera retrocede lentamente tras el impacto).

Qu pasara, no obstante, si uno de los dos rigidbodies tuviera una masa sensiblemente distinta del otro? Probmoslo aadiendo una expresin ms a nuestro script: function FixedUpdate () { if (Input.GetButtonDown ("Horizontal")) { rigidbody.velocity = Vector3(9,0,0); rigidbody.mass = 0.1; } } Ahora nuestra esfera tendr una masa de 0.1, esto es, una dcima parte de la masa del cubo. Salvamos, play, flecha lateral... Casi ni mueve el cubo. Podis probar a la inversa, si queris, darle ms masa a la esfera (sin pasar de 10, recordad). Comprobad que una vez pulsis la flecha de desplazamiento horizontal, la masa de la esfera (si es que la tenis seleccionada) cambia en el inspector y se convierte en la que habis asignado en el script. Para acabar, advertiros de que un error comn es asumir que objetos pesados caen ms rpido que los ligeros. Esto no es verdad, ya que la velocidad depende de la gravedad y la resistencia (drag), y no de la masa.

useGravity: Var useGravity : boolean Booleano que controla si la gravedad afecta a este rigidbody. Si est en false el rigidbody se comportar como si estuviera en el espacio. Probamos. Rehacemos MiPrimerScript: function FixedUpdate () { if (Input.GetButtonDown ("Jump")) { rigidbody.velocity = Vector3(0,7,0); } if (Input.GetButtonDown ("Horizontal")) { rigidbody.useGravity = false; } if (Input.GetButtonDown ("Vertical")) { rigidbody.useGravity = true; } } Salvamos, y le damos impulso hacia arriba a nuestra esfera. Alternad las flechas de desplazamiento horizontal y vertical para comprobar la diferencia de movimientos sin y con gravedad.

isKinematic: Var isKinematic : boolean Es un booleano que controla si las fsicas afectan al rigidbody. Si isKinematic est habilitado (es true), a nuestro rigidbody no le afectarn ni fuerzas, ni colisiones ni junturas (joints). Ello quiere decir que no podemos esperar que frente -por

ejemplo- a una colisin ese rigidbody kinemtico se comporte de la manera lgica que por su masa, resistencia y gravedad debiera comportarse. Sus movimientos, reacciones y respuestas, por tanto, deberemos marcrselos especficamente mediante scripts o animaciones. Los cuerpos kinemticos, por el contrario y a su vez, s afectan el movimiento de otros rigidbodies no kinemticos a travs de colisiones o joints. Quisiera aprovechar para recordar que las variables "expuestas" de tipo booleano son mostradas por el inspector como un checkbox, donde el cuadro marcado se corresponde a true y el desmarcado al false.

freezeRotation: Var freezeRotation : Boolean Esta variable vendra a ser una especializacin de la anterior. freezeRotation controla si las fsicas cambiarn la rotacin del objeto. Si esta variable est habilitada (true), la rotacin no ser mofificada por la simulacin de fsicas, y en todo caso tendremos que establecerla nosotros manualmente mediante scripts o animaciones.

constraints: Var constraints : RigidbodyConstraints Controla qu grados de libertad estn permitidos para la simulacin de nuestro rigidbody. Por defecto esta variable tiene el valor RigidbodyConstraints.FreezeNone, permitiendo rotacin y movimiento en todos los ejes. En algunos casos, puedes querer constreir un rigidbody para que slo se mueva o rote sobre algunos ejes, como por ejemplo cuando desarrolles juegos en 2D. Puedes usar el operador de bits OR ('||') para combinar mltiples constraints. Vamos a probar con un sencillo ejemplo la utilidad de esta variable. En Unity alejamos un poco la cmara para que se vea tanto la esfera como el lateral izquierdo (segn se mira) del plano. Abrimos nuestro script habitual: function FixedUpdate () { if (Input.GetButtonDown ("Horizontal")) { rigidbody.velocity = Vector3(-6,0,0); } } Salvamos, play, flecha desplazamiento lateral. La esfera sobrepasa la superficie del plano y arrastrada por la gravedad cae. Podramos solucionar esta eventualidad quitndole la gravedad a la esfera, pero tenemos una solucin ms elegante: No permitir que nuestra esfera se mueva en el eje Y (arriba/abajo). As que modificamos nuestro script: function FixedUpdate () { if (Input.GetButtonDown ("Horizontal")) { rigidbody.velocity = Vector3(-6,0,0); rigidbody.constraints = RigidbodyConstraints.FreezePositionY; } } Y volvemos a probar. Dado que le hemos congelado ("freeze") a nuestra esfera la posibilidad de alterar el valor de su eje de posicin Y, la esfera no puede ni ascender ni caer, razn por la cual contina rodando allende el plano.

Observamos que esta variable es de tipo RigidbodyConstraints, lo cual en el fondo es una enumeracin que nos permite elegir entre una serie de valores, a saber: None FreezePositionX FreezePositionY FreezePositionZ FreezeRotationX FreezeRotationY FreezeRotationZ FreezePosition FreezeRotation FreezeAll Sin limitaciones de posicin ni de rotacin Congela la posicin en el eje X. Congela la posicin en el eje Y. Congela la posicin en el eje Z. Congela la rotacin sobre el eje X. Congela la rotacin sobre el eje Y. Congela la rotacin sobre el eje Z. Congela la posicin sobre todos los ejes. Congela la rotacin sobre todos los ejes Congela rotacin y posicin de todos los ejes

collisionDetectionMode: var collisionDetectionMode : CollisionDetectionMode Esta variable nos permite establecer el modo de deteccin de colisiones del rigidbody. Como podemos observar, es de tipo CollisionDetectionMode, tratndose sta al igual que en el caso anterior de una enumeracin que admite tres tipos de valores, que pasamos a desarrollar: Distrete: Este es el modo de deteccin de colisiones por defecto. Es el que menos recursos consume, pero no garantiza que nuestro rigidbody detecte un conjunto de colisiones, sobre todo si estas acontencen a gran velocidad. En modo discrete Unity comprueba si el rigidbody ha sido colisionado cada vez que se llama a la funcin fixedUpdate, que como ya explicamos es llamada un nmero fijo de veces por segundo. Si la colisin se produce en el impass entre una llamada a fixedupdate y la siguiente, nuestro rigidbody no la captar. Continuous: Con este modo on, nuestro rigidbody detectar las colisiones con cualquier malla geomtrica esttica que se tropiece en su camino, incluso si la colisin ocurre entre dos llamadas a FixedUpdate. Por malla geomtrica esttica Unity entiende cualquier MeshCollider (no tardaremos en estudiarlo) que no tenga un rigidbody vinculado. ContinuousDinamic: Si establecemos este sistema de deteccin de colisiones para nuestro rigigbody, ste detectar colisiones tanto con mallas geomtricas estticas como con otros rigidbodies que tengan a su vez activado el modo continous collision detection. Este sistema consume bastantes recursos y debe ser slo usado para prevenir movimientos muy rpidos de objetos. Slo es soportado, adems, por rigidbodies con sphere o box collider. A efectos de sintaxis, para colocar el sistema de deteccin de un rigidbody en modo ContinuousDinamic, por ejemplo, lo escribiramos as: rigidbody.collisionDetectionMode = CollisionDetectionMode.ContinuousDynamic;

centerOfMass: CenterOfMass : Vector3 Representa el centro de masa relativo al origen del transform. El centro del transform se corresponde a las coordenadas locales 0,0,0, y si no reubicamos va un script el centro de masa, Unity lo calcula automticamente (suele coincidir con el centro del transform) Si bien no es una variable con demasiada utilidad, s que a veces puede servirnos para, por ejemplo, hacer ms estable y menos propenso a los vuelcos a un coche. Un coche con un centro de masa/gravedad bajo es menos propenso a volcar. rigidbody.centerOfMass = Vector3 (0, -2, 0);

worldCenterOfMass: var worldCenterOfMass : Vector3 Esta variable nos indica el centro de masa/gravedad de un rigidbody en el espacio global. Tengamos presente que a diferencia de la anterior esta variable es de solo lectura.

detectCollisions: Var detectCollisions : Boolean Indica si la deteccin de colisiones est habilitada (por defecto, s). Deshabilitar esta variable es util si tenemos un objeto que es kinemtico y queremos evitar que el sistema realice clculos intiles de deteccin de colisiones para l.

interpolation: Var interpolation : RigidbodyInterpolation La interpolacin nos permite suavizar el efecto de correr fsicas en un framerate fijo. Por defecto la interpolacin est off. Comunmente se usa la interpolacin de rigidbodies en los personajes de los jugadores. Las fsicas suelen transcurrir en pasos fijos (FixedUpdate), mientras los grficos son renderizados en framerates variables. Esto puede llevar a que los objetos parezcan temblorosos, porque fsicas y grficos no estn completamente sincronizados. El efecto es sutil pero perceptible, y sobre todo afecta a los personajes principales que son seguidos por alguna cmara. Es recomentable poner en on la interpolacin para el personaje principal pero deshabilitarla para los dems. La enumeracin RigidbodyInterpolation tiene los siguientes valores: None Interpolate Extrapolate Significa que no hay interpolacin. Es la opcin por defecto. La interpolacin ir con un poco de retraso, pero puede ser un poco ms suave que la extrapolacin. La extrapolacin predecir la posicin del rigidbody en base a la velocidad actual.

sleepVelocity: var sleepVelocity : float La velocidad lineal, por debajo de la cual los objetos empiezan a dormir (por defecto 0.14) en un rango que va de 0 a infinity. La hecho de que los objetos duerman es una optimizacin que permite que el engine de fsicas deje de procesar para estor rigidbodies. As, cuando el objeto se duerme deja de detectar colisiones o realizar simulaciones, por ejemplo.

sleepAngularVelocity: var sleepAngularVelocity : float La velocidad angular, por debajo de los cuales los objetos empiezan a dormirse (por defecto 0.14)

maxAngularVelocity: Var maxAngularVelocity : float

Representa la maxima velocidad angular del rigidbody (por defecto 7) en un rango que va de 0 a infinity. Se tiene que fijar una velocidad angular mxima para evitar inestabilidades numricas con objetos rotando demasiado rpido.

Bueno, y hasta aqu las variables de la clase Rigidbody. He omitido la explicacin de unas cuantas que me han parecido poco importantes, de poco uso.

FUNCIONES: SetDensity: Function SetDensity (density : float) : void Nos permite asignar una masa en base al collider vinculado, lo cual es til para asignar una masa en unos valores acordes al tamao de los colliders. Podemos aplicar un ejemplo similar al que realizamos con la variable mass. Abrimos nuestro script habitual y tecleamos: function FixedUpdate () { if (Input.GetButtonDown ("Horizontal")) { rigidbody.velocity = Vector3(6,0,0); rigidbody.SetDensity(6.0); } } Salvamos. Play. Presionamos la flecha de desplazamiento horizontal y comprobamos que la masa de la esfera le permite literalmente arrastrar al cubo.

AddForce: function AddForce (force : Vector3, mode : ForceMode = ForceMode.Force) : void Esta funcin (una de las ms importantes de la API de Unity) aade una fuerza al rigidbody. Como resultado de esto el rigidbody comenzar a moverse. El primer parmetro es un Vector3, que nos servir para indicar la potencia y direccin de la fuerza que aplicamos. Por ejemplo, podemos teclear en nuestro script de cabecera: function FixedUpdate () { rigidbody.AddForce (Vector3.up * 10); } Y al darle al play nuestra esfera ascender, fruto de una fuerza constante (aplicada en cada actualizacin de la funcin FixedUpdate). Obviamente, la velocidad de movimiento depender -adems de la fuerza aplicada - de la masa del rigidbody y de la resistencia, esto es, varios rigidbodies diferentes tendrn reaccione diferentes cuando les es aplicada la misma fuerza. function AddForce (x : float, y : float, z : float, mode : ForceMode = ForceMode.Force) : void Este segundo prototipo de la funcin, como ya viene siendo habitual, meramente sustituye el parmetro de tipo Vector3 por 3 de tipo float.

//Equivale al script anterior function FixedUpdate () { rigidbody.AddForce (0, 10, 0); } El segundo parmetro observamos que es de tipo ForceMode, que como posiblemente sospechis es una nueva enumeracin made in Unity, que tiene los siguientes valores: Force Aade una fuerza contnua al rigidbody, dependiendo de su masa. Es el valor por defecto y que obtiene resultados ms realistas, ya que como decamos costar ms esfuerzo mover objetos ms pesados que ms livianos. Aade una aceleracin contnua al rigidbody, ignorando su masa. A diferencia de ForceMode.Force, Acceleration mover cualquier rigidbody de la misma forma sin tener en cuenta su masa, lo que es til si slo queremos controlar la aceleracin de un objeto sin preocuparnos de la fuerza que deberamos aplicarle para obtenerla teniendo en cuenta su masa y resistencia. Aade un impulso puntual de fuerza al rigidbody, teniendo en cuenta su masa. Hay que tener la precaucin de no incluir este modo dentro de una funcin que se actualice a menudo (como FixedUpdate). Este modo es til para aplicar fuerzas que acontecen de repente, como explosiones o colisiones. Aade un cambio de velocidad instantneo al rigidbody, ignorando su masa. Con esa salvedad (una misma fuerza tendr los mismos resultados con rigidbodies de diferente masa), le es aplicable lo mismo que al modo precedente.

Acceleration

Impulse

VelocityChange

Podemos ver la diferencia entre fuerzas aplicadas en el mismo script de arriba. Lo modificamos para que quede as: function FixedUpdate () { rigidbody.AddForce (Vector3.up * 10, ForceMode.Impulse); } Podis ver que la esfera sale disparada. No retorna porque como la tenemos dentro de la funcin FixedUpdate est recibiendo un impulso peridico. Vamos a liberarla: rigidbody.AddForce (Vector3.up * 10, ForceMode.Impulse); Supongo que queda demostrada la diferencia entre fuerza constante e impulso.

AddRelativeForce function AddRelativeForce (force : Vector3, mode : ForceMode = ForceMode.Force) : void Aade una fuerza al rigidbody relativa al sistema local de coordenadas de dicho rigidbody. Para explicar qu quiere decir esto, vamos a preparar un ejemplo que requerir varias fases: Para empezar, eliminamos el script que tenemos vinculado a la esfera. Nos colocamos en la vista vertical en la ventana Scene, haciendo click en la Y del gizmo. En Proyecto hacemos doble click en MiPrimer Script para abrir el editor, y tecleamos: function FixedUpdate(){ rigidbody.AddForce (Vector3.right * 15); } Salvamos, arrastramos el script al cubo y le damos al play. Tal como era de esperar, se aplica una fuerza lateral al cubo, pero ste da demasiadas vueltas sobre s como para hacer una demostracin respecto a las coordenadas de desplazamiento, as que vamos a completar el script con una de esas variables que cuando uno las estudia cree que no las usar nunca.

rigidbody.centerOfMass = Vector3(0,-0.3,0); function FixedUpdate(){ rigidbody.AddForce (Vector3.right * 15); } Exacto. Le bajamos el centro de gravedad al cubo y en principio deberamos ahora poderlo arrastrar como un mueble. Probemos si esto funciona en la prctica. Lo suficiente para poder realizar la explicacin. Ahora giremos en el inspector el cubo 35 grados sobre el eje Y. Volvamos a darle al play. Vemos que la fuerza que aplica la funcin AddForce lo es en relacin a las coordenadas globales, y no a las del objeto. Sustituimos en el script AddForce por AddRelativeForce y probemos de nuevo. Ahora la fuerza no es aplicada a la derecha del mundo, sino a la derecha relativa del cubo.

AddTorque: function AddTorque (torque : Vector3, mode : ForceMode = ForceMode.Force) : void function AddTorque (x : float, y : float, z : float, mode : ForceMode = ForceMode.Force) : void Esta funcin aade una torsin (no he podido encontrar una traduccin mejor para torque) al rigidbody. Como resultado el rigidbody empezar a girar alrededor del eje de torsin. As, si al eje Y de rotacin de nuestro cubo le reintegramos su valor de 0 y luego modificamos de la siguiente manera nuestro script del ltimo ejemplo... rigidbody.centerOfMass = Vector3(0,-0.3,0); function FixedUpdate(){ rigidbody.AddTorque (Vector3.right * 15); } ...vemos que efectivamente se le ha aadido a nuestro cubo una fuerza de torsin/rotacin sobre el eje X. Recordemos que cuando hablamos de rotacin, hemos de considerar a cada eje como si se tratara de una lnea rgida alrededor de la cual nuestro objeto gira. Esto es, si quisiramos que el cubo se moviera como una peonza, tendriamos que hacerlo rotar sobre su eje Y. Probad a cambiar "Vector.right * 15" por "Vector.up * 25". (Y si queremos que rote en direccin opuesta, le anteponemos un signo - al Vector.)

AddRelativeTorque: function AddRelativeTorque (torque : Vector3, mode : ForceMode = ForceMode.Force) : void function AddRelativeTorque (x : float, y : float, z : float, mode : ForceMode = ForceMode.Force) : void Como podris suponer, esta funcin aade una fuerza de torsin relativa a las coordenadas locales/propias del rigidbody. Es a AddTorque lo mismo que AddRelativeForce a AddForce.

AddForceAtPosition: Function AddForceAtPosition (force : Vector3, position : Vector3, mode : ForceMode = ForceMode.Force) : void

Aplica fuerza a un rigidbody en una posicin determinada.

AddExplosionForce: Function AddExplosionForce (explosionForce : float, explosionPosition : Vector3, explosionRadius : float, upwardsModifier : float = 0.0F, mode : ForceMode = ForceMode.Force) : void Aplica una fuerza al rigidbody que simula el efecto de una explosin. La fuerza de la explosin decaer de manera lineal con la distancia del rigidbody. Esta funcin tambin funciona bien con objetos inertes. Si el radio es 0, la fuerza plena ser aplicada sin importar cuan lejos se produzda la explosin del rigidbody. UpwardsModifier aplica la fuerza como si fuera aplicada desde debajo del objeto.

MovePosition: Function MovePosition (position : Vector3) : void Mueve el rigidbody de posicin. Por ejemplo: private var velocidad : Vector3 = Vector3 (3, 0, 0); function FixedUpdate () { rigidbody.MovePosition(rigidbody.position + velocidad * Time.deltaTime); } En este script declaramos primero una variable de tipo Vector3. Le anteponemos la palabra clave "private", que implica que dicha variable no ser accesible desde el inspector (no quedar expuesta). Se declara como privada una variable que no queremos que se modifique desde la interface. El resto del script no merece mucha explicacin. Se suma el Vector3 con la velociadd a la posicin del rigidbody, y para que el desplazamiento se produzca en segundos y no en porciones de frames, lo multiplicamos por Time.deltaTime.

MoveRotation: function MoveRotation (rot : Quaternion) : void Rota el rididbody. Si observamos el prototipo de la funcin, vemos que hemos de pasarle a la misma un parmetro de tipo Quaternion. Ya hemos dicho en otras ocasiones que resulta bastante complejo para los humanos trabajar con cuaterniones, razn por la cual por norma general trabajaremos en grados Euler se los pasaremos a la funcin convenientemente traducidos. Un ejemplo: private var velocidadEnAngulos : Vector3 = Vector3 (0, 100, 0); function FixedUpdate () { var velocidadEnCuaternionesPorTiempo : Quaternion = Quaternion.Euler(velocidadEnAngulos * Time.deltaTime); rigidbody.MoveRotation(rigidbody.rotation * velocidadEnCuaternionesPorTiempo); }

Como podemos comprobar, meramente tenemos que usar la funcin Quaternion.Euler, que recibe grados euler como parmetro y devuelve cuaterniones. El resto es sencillo.

Sleep: Function Sleep () : void Fuerza al rigidbody a dormir al menos un frame. Un uso comn es llamar esta funcin al principio del juego para que el rigidbody no consuma recursos hasta que sea activado.

IsSleeping: Function IsSleeping () : Boolean Booleano que devuelve true si el rigidbody est durmiendo.

WakeUp: Function WakeUp () : void Fuerza al rigidbody a despertarse.

SweepTest: Function SweepTest (direction : Vector3, hitInfo : RaycastHit, distance : float = Mathf.Infinity) : Boolean Devuelve true cuando un barrido del rigidbody intercepta algn collider. Esto funciona de la siguiente manera: nuestro rigidbody lanza en una direccin (parmetro direction de tipo Vector3) un rayo (pensemos hasta que no estudiemos la clase RaycastHit en una especie de lser o sonar de presencia, con la salvedad de que en este caso el rayo devolver informacin de aqullo con lo que ha chocado) hasta una determinada distancia (distance, de tipo float, que por defecto es infinito) y si el rayo tropieza con un collider, la funcin devuelve true. Obviamente, esto es de gran utilidad para, por ejemplo, que nuestro personaje tenga informacin para evitar colisiones. Veamos un pequeo ejemplo: var rayo : RaycastHit; function Update () { if (rigidbody.SweepTest (-transform.right, rayo, 10)) { Debug.Log("Hay un obstaculo a " + rayo.distance + " metros a la izquierda"); } } El script funciona como sigue: primero declaramos una variable de tipo RaycastHit para que recoja toda la informacin del collider que nuestra funcin pueda detectar en su barrido. Acto seguido lanzamos a travs de la funcin SweepTest un rayo en direccin izquierda (-transform.right) hasta una distancia de diez metros. Caso de topar con un collider, distinta informacin del mismo ser almacenada en la variable rayo y la funcin devolver true, con lo cual se imprimir la informacin tecleada, indicando la distancia del collider hallado. Si le damos al play, observamos que nuestra funcin ha hallado un collider a la izquierda de nuestro cubo.

SweepTestAll: Function SweepTestAll (direction : Vector3, distance : float = Mathf.Infinity) : RaycastHit[] Es parecida a la anterior, pero devolviendo un array de tipo RaycastHit con toda la informacin de todos los colliders hallados en el camino

Adems de las funciones tradicionales contenidas en la clase Rigidbody, sta tambin tiene un tipo de funcin especfica, que se disparan cuando acontece un evento. Unity las trata como "mensajes que enva la clase". Son tres:

OnCollisionEnter: function OnCollisionEnter (collisionInfo : Collision) : void OnCollisionEnter es llamada cuando nuestro rigidbody/collider toca otro rigidbody/collider. En contraste con la funcin OnTriggerEnter, a OnCollisionEnter se le pasa como parmetro una instancia de la clase Collision, la cual contiene informacin sobre puntos de contacto, velocidad de impacto, etc.

OnCollisionExit: function OnCollisionExit (collisionInfo : Collision) : void OnCollisionExit es llamada cuando nuestro collider/rigidbody deja de tocar otro rigidbody/collider.

OnCollisionStay: function OnCollisionStay (collisionInfo : Collision) : void OnCollisionStay es llamada una vez cada frame para cada collider/rigidbody que est tocando nuestro rigidbody/collider.

5. CLASE COLLIDER

Esta es la clase base para todos los tipos de colliders (que en castellano traduciramos por "colisionadores"). Las clases BoxCollider, SphereCollider, CapsuleCollider y MeshCollider derivan de ella. Un collider vendra a ser la estructura que hace slidos a los objetos. Seleccionemos en Unity la esfera. En el inspector observamos que tiene un Sphere Collider, que no es ms que un collider con forma de esfera. Si desmarcamos el checkbox de dicho collider y le damos al play, automticamente la esfera deja de ser slida y, por efecto de la gravedad que le da el rigidbody, atraviesa el suelo y cae. Podemos seleccionar el cubo. Obviamente, el cubo no tiene una sphere collider, sino una box collider. Y si importramos un gameobject capsule, tendra un capsule Collider. El problema viene cuando importamos un game object que no tiene una de estas formas primitivas. A veces se puede "encajar" una capsule collider en un rbol, o una box collider en un coche. A veces no necesitamos que el colisionador de un objeto coincida al 100% con dicho objeto y uno de estos colliders bsicos nos pueden hacer el apao. Pero hay veces en que, bien por la importancia del game object en el juego, bien por la forma compleja que tiene dicho game object, bien en la mayora de casos por ambas cosas (pensemos en el ninja protagonista de nuestro juego, por ejemplo) necesitamos un collider que sea completamente fiel a la forma del gameobject. Para ello tenemos el mesh collider (que estudiaremos en breve), que es meramente la malla del objeto convertida en la estructura slida del mismo que interacta con el resto del mundo. Existe bastante confusin entre los nuevos en Unity respecto la diferencia entre un collider y un rigidbody. Un collider, como decimos, es meramente la superficie de nuestro objeto. Un rigidbody en cambio implica la aplicacin de las leyes fsicas a dicho objeto. Un objeto puede tener un collider y no un rigidbody (chocar con otros objetos, aunque no podremos controlar sus reacciones a las colisiones y ser Unity quien se encargue de ellas automticamente), y puede tener un rigidbody y no un collider (aunque entre otras cosas tendremos que desactivarle la gravedad, para que no atraviese los suelos). Obviamente, un objeto puede tener un rigidbody y un collider, y de hecho Unity recomienda que si tu objeto es previsible que vaya a intervenir en muchas colisiones, adems de un collider es recomendable aadirle un rigidbody kinemtico. Vamos a ello:

VARIABLES: enabled: var enabled : boolean Si el collider est habilitado (true), colisionar con otros colliders. Se corresponde al checkbox que est en el inspector en el apartado del collider.

attachedRididbody: var attachedRigidbody : Rigidbody Esta variable hace referencia al rigidbody vinculado a este collider, y permite acceder a l. Devuelve nulo si el collider no tiene rigidbody. Los colliders son automticamente conectado al rigidbody relacionado con el mismo game object o con algn game object padre. Esto es, por ejemplo el rigidbody que le aadimos en su momento al cubo automticamente qued vinculado al box collider de ste. Probmoslo rehaciendo MiPrimerSript: function FixedUpdate() { collider.attachedRigidbody.AddForce(0,15,0); } Salvamos, nos aseguramos de que el script siga vinculado al cubo, y le damos al play.

isTrigger: var isTrigger : boolean Si esta variable est habilitada (true) el collider se convierte en un trigger (lo podramos traducir por "desencadenante" o "disparador"). Un trigger no colisiona con rigidbodies, y en su lugar enva los mensajes OnTriggerEnter, OnTriggerExit y OnTriggerStay (que estudiaremos al final de la clase) cuando un rigidbody entra o sale de l. De esta manera nos permite a nosotros disear de manera especfica su comportamiento o las consecuencias de entrar en contacto con un trigger (pensemos en una puerta que nos lleva a otra dimensin, que se puede atravesar pero dispara un evento que nos teletransporta, por ejemplo)

material: var material : PhysicMaterial El material usado por el collider. Si el material es compartido por varios colliders, al ser asignado a esta variable se har una copia de dicho material que le ser asignada al collider. La variable es del tipo PhysicMaterial, que como en su momento estudiaremos es una clase que nos permite manejar aspectos de los materiales como la friccin o la capacidad de rebote y el grado de la misma.

sharedMaterial: var sharedMaterial : PhysicMaterial

El material compartido de este collider. Modificando este material cambiaremos las propiedades de la superficie de todos los colliders que estn usando el mismo material. En muchos casos es preferible modificar en su lugar el Collider.material.

bounds: var bounds : Bounds Los lmites/bordes del collider en coordenadas globales.

FUNCIONES: ClosestPointOfBounds: function ClosestPointOnBounds (position : Vector3) : Vector3 Devuelve el punto ms cercano de nuestro Collider con respecto a un punto dado. Esto puede ser usado para calcular puntos de choque cuando se aplique dao derivado de una explosin.

Raycast: function Raycast (ray : Ray, hitInfo : RaycastHit, distance : float) : boolean Proyecta un rayo que devuelve true si tropieza con algn collider en la direccin y distancia indicadas. Consta de varios parmetros. El primero es de tipo Ray, y nos vamos a detener un momento en l. La estructura Ray nos permite crear una lnea con un origen y una direccin. Consta de dos variables -de nombre origin y direction- que no son sino sendos Vector3 para representar el inicio y la direccin de dicha linea. Para verlo grficamente, tecleamos el siguiente script: function Update(){ var rayo : Ray; rayo.origin = transform.position; rayo.direction = transform.right; Debug.DrawLine(rayo.origin, rayo.direction); } Al darle al play, observamos en la ventana de escena el rayo saliendo del cubo. Si queremos ver el mismo efecto en la ventana del juego, hemos de activar el botn gizmo que aparece encima de sta, a su derecha:

El segundo parmetro de la funcin Raycast -HitInfo- contendr informacin sobre aquello con lo que golpe el collider para el caso de que la funcin devuelva true, esto es, tropiece con algo. El tercer parmetro -distance- es obviamente la longitud del rayo.

OnTriggerEnter: function OnTriggerEnter (other : Collider) : void Esta funcin y las que restan forman parte de la categora de "mensajes enviados". Al estudiar la variable isTrigger decamos que si nuestro collider habilitaba dicha variable, se converta en un trigger (disparador) y dejaba de colisionar con otros rigidbodies, y que en lugar de responder a las fsicas, al entrar en contacto (o dejar de tenerlo) con ellos lanzaba una serie de mensajes. OnTriggerEnter, as, es llamada cuando nuestro trigger entra en contacto con otros colliders, de tal manera que podemos escribir dentro de dicha funcin el cdigo que defina lo que queramos que ocurra cuando se produce dicho contacto. Para explicarlo grficamente, vamos a intentar hacer un script progresivo. Empecemos por eliminar el script que tenemos vinculado al cubo. Despus, abrimos MiPrimerScript en Proyecto. Tecleamos lo siguiente: function FixedUpdate(){ rigidbody.AddForce(4,0,0); } Salvamos y arrastramos el script a la esfera. Tal como es de esperar, sta recibe una fuerza hacia la derecha que le lleva a chocar con el cubo. Qu sucede si nuestra esfera es convertida en trigger?. Probmoslo: collider.isTrigger =true; function FixedUpdate(){ rigidbody.AddForce(4,0,0); } Le damos al play y observamos que la esfera ha perdido toda solidez, de tal suerte que atraviesa el suelo y cae. Tenemos que evitar para nuestros fines que la esfera se mueva en el eje Y, evitando que caiga. Una variable que ya hemos estudiado viene en nuestra ayuda:

collider.isTrigger =true; rigidbody.constraints = RigidbodyConstraints.FreezePositionY; function FixedUpdate(){ rigidbody.AddForce(4,0,0); } Ahora hemos preparado el terreno para lo que quera demostrar. De momento observamos que la esfera, en efecto, ya no cae (no puede operar en el eje Y), pero atraviesa -tal como era de esperar- el cubo. Vamos ahora a disearle un comportamiento especfico a la esfera para cuando entre en contacto con el cubo. collider.isTrigger =true; rigidbody.constraints = RigidbodyConstraints.FreezePositionY; function FixedUpdate(){ rigidbody.AddForce(4,0,0); } function OnTriggerEnter(loPrimeroQuePille) { loPrimeroQuePille.gameObject.renderer.material.color = Color.red; } Dmosle al play y luego la explicamos. Efectivamente, en el momento en que nuestro trigger/esfera topa con otro collider, lo valores del mismo son asignados al parmetro de la funcin OnTriggerEnter y podemos acceder a ellos para, como es el caso, por ejemplo cambiarle el color al cubo. Puede parecer un poco tortuoso todo el camino que nos lleva del collider loPrimeroQuePille hasta el color, pero con un poco de prctica y/o una guia rpida a mano, y conociendo el principio y el final del path, el resto es bastante sencillo. Fijmonos por otro lado en que este tipo de funciones no pertenecen propiamente a la clase, no usan un operador punto para vincularse a un objeto de una clase, sino que se usan de manera independiente, aunque para su activacin requieren que efectivamente un collider con el trigger habilitado entre en contacto con algo. Es decir, su inclusin en la clase collider es ms por "afinidad" que porque realmente formen parte de aquella.

OnTriggerExit: function OnTriggerExit (other : Collider) : void Es llamada cuando el collider "other" deja de tocar con nuestro trigger.

OnTriggerStay: function OnTriggerStay (other : Collider) : void Es llamada casi todos los frames que el collider other est tocando nuestro trigger.

OnCollisionEnter: function OnCollisionEnter (collisionInfo : Collision) : void Es llamada cuando nuestro collider/rigidbody empiece a tocar otro rigidbody/collider.

OnCollisionExit: function OnCollisionExit (collisionInfo : Collision) : void Es llamada cuando nuestro collider/rigidbody deja de tocar otro rigidbody/collider.

OnCollisionStay: function OnCollisionStay (collisionInfo : Collision) : void Es llamada una vez por frame por cada collider/rigidbody que est tocando nuestro rigidbody/collider.

6. CLASE MESHCOLLIDER

La clase MeshCollider, como vemos, hereda de la recin estudiada Collider, razn por la que hereda todas sus variables, funciones y mensajes que enva, amn de hacer lo propio con las clases Component y Object. Una MeshCollider (o colisionador de malla), tal como dijimos no hace mucho, es meramente la malla de un gameobject que convertimos en collider, por norma general porque nuestro gameobject tiene una forma en la que difcilmente se puede encajar una malla primitiva. Como ventajas de usar esta opcin, obviamente que habr una mayor coherencia entre la apariencia del gameobject y su superficie de colisin. Como mayor desventaja, el aumento de consumo para que nuestro ordenador haga los pertinentes clculos para cada plano de nuestra malla.

VARIABLES: sharedMesh: var sharedMesh : Mesh Hace referencia al objeto malla que nuestro gameobject est usando como detector de colisiones, si lo hay. Nos permite consultar sus caractersticas y/o asignar uno. La variable es de tipo mesh (malla) y la estudiaremos ms adelante.

convex: var convex : boolean Usa un collider convexo para la malla, esto es, con esta variable establecida en true nuestro collider de malla automticamente pasa a ser convexo y todas las entradas y agujeros que pudiera tener nuestra malla desaparecen, permitiendo una deteccin de colisiones mucho ms completa. Las mallas convexas pueden colisionar con otros colliders

convexos y no convexos. Por lo tanto los colliders de malla convexos son apropiados para rigidbodies en el caso de que necesitramos colliders con formas ms detalladas que los colliders primitivos. transform.collider.convex = true;

smoothSphereCollisions: var smoothSphereCollisions : boolean Usa normales interpolados para colisiones de esferas en lugar de normales planos poligonales. Esto suaviza los baches para rodamientos de esferas sobre superficies suaves.

7. CLASE CHARACTERCONTROLLER

Un character Controller nos permite hacer fcilmente movimientos limitados por colisiones sin tener que lidiar con un rigidbody. Comprobmoslo empricamente, siguiendo estos pasos: 1.- Le borramos a la esfera el script que tiene vinculado. 2.- Le eliminamos a la esfera su componente rigidbody (botn derecho del ratn situado sobre el nombre de dicho componente=> remove component). 3.- Con la esfera seleccionada, vamos al men Component=>Physics=>Character Controller. Nos saldr un aviso preguntndonos si realmente queremos sustituir el collider primitivo que por defecto trae la esfera por un Character collider. Presionamos Replace. 4.- En Jerarqua seleccionamos suelo, y en el inspector desmarcamos el checkbox situado junto a Mesh Collider. 5.- Play. El cubo, afectado por las leyes fsicas, atraviesa el suelo al que le hemos deshabillitado la malla. Sin embargo el cubo, que ahora est controlado por el character controller, no se ve afectado por las leyes fsicas. Antes de seguir, volvamos a habilitar la malla del suelo en su correspondiente checkbox. Un character Controller no se ve afectado tampoco por fuerzas y se mover slo cuando llamemos a la funcin Move, especfica de esta clase.

VARIABLES: isGrounded: var isGrounded : boolean Booleano que devuelve true si nuestro character controller (controlador de personaje, podramos traducirlo) estaba tocando el suelo durante el ltimo movimiento.

velocity: var velocity : Vector3 La velocidad relativa actual del character. La velocidad as retornada es la diferencia durante la ltima actualizacin entre la distancia antes y despus de llamar a la funcin Move o SimpleMove, esto es, dnde estaba el ltimo frame, o la ltima porcin de frame o el ltimo segundo el character antes de llamar a una de esas funciones y dnde estba despues, para que distancia partida por (tiempo, frame o fraccin dada) sea igual a la velocidad por tiempo, frame o fraccin dada. Decimos que la velocidad es relativa porque no puede seguir movimientos del transform que suceden fuera del character controller (por ej un character emparentado bajo otro transform en movimiento, como por ejemplo un vehculo movindose)

collisionFlags: var collisionFlags : CollisionFlags Esta variable nos indic qu parte de la cpsula (que es la forma que tiene un character controller) colision con el entorno durante la ltima llamada a CharacterController.Move. Comprobamos que la variable es de tipo CollisionFlags, que tal como podemos sospechar es de tipo enumeracin, permitindonos usar los siguientes valores: None: Sides: Above: Bellow: No hay colisin. Colisin en los lados. Colisin en la parte superior. Colisin en la parte inferior.

As, un sistema para determinar si nuestro character controller ha topado con algo, y en qu parte de la cpsula, sera como sigue (no hace falta que tecleis esto, es slo a modo indicativo): function Update () { var controller : CharacterController = GetComponent(CharacterController); controller.Move(Vector3(1,0,0)); if (controller.collisionFlags == CollisionFlags.None) print("No hay colisiones"); if (controller.collisionFlags & CollisionFlags.Sides) print("Colisin lateral, al menos"); if (controller.collisionFlags == CollisionFlags.Sides) print("Slo colisin lateral, ninguna de otro tipo"); if (controller.collisionFlags & CollisionFlags.Above) print("Colisin superior, al menos"); if (controller.collisionFlags == CollisionFlags.Above) print("Slo colisin superior, ninguna de otro tipo"); if (controller.collisionFlags & CollisionFlags.Below) print("Tocando tierra"); if (controller.collisionFlags == CollisionFlags.Below) print("Slo tocando tierra, nada ms"); }

Le aadimos el script a la esfera (si no lo tena ya vinculado) y le damos al play. La esfera se mueve hacia la derecha, hasta que impacta con el cubo (dmonos cuenta que la esfera ya no tiene un ridigbody, pero gracias al character controller sigue colisionando con otros colliders. Debajo de la ventana game aparece impresa la ltima colisin, pero no es la nica. Si le hacemos click al mensaje impreso nos saldr una lista de todas las colisiones que ha sufrido nuestra esfera hasta topar con el cubo. La funcin GetComponent que hemos tecleado al inicio del script an no la hemos estudiado, pero su cometido es bastante obvio: buscar el componente del gameobject que hace la llamada y que sea del tipo que le pasamos como parmetro, retornndolo. En este caso, nos sirve para inicializar la variable controller, con la que trabajaremos para montar un primitivo sistema de identificacin de colisiones. La funcin Print es similar a Debug.Log, y la funcin Move la estudiaremos ms adelante.

radius: var radius : float El radio de la cpsula del character controller.

height: var height : float La altura de la cpsula del character controller.

center: var center : Vector3 El centro de la cpsula del character relativo a la posicin del transform.

slopeLimit: var slopeLimit : float El lmite de pendiente en grados por el que puede ascender nuestro character controller. Vamos a probar esta variable. Sigue estos pasos: 1.- Seleccionamos el cubo y lo desplazamos a la derecha (transform.x = 3, por ejemplo). 2.- Vamos al men=>GameObject=>create other=>Cube. 3.- En el apartado transform, le damos al nuevo cube estos valores: position = 0,2,0 rotation = 0,0,315 scale = 0.2,7,1 Nos debera haber quedado algo as:

Vale, ahora tenemos una pasarela con una inclinacin de 45 grados (360-315), por lo tanto, que nuestra esfera la pueda subir o no depende del valor que le demos a slopeLimit. As, si tecleamos: function Update () { var controller : CharacterController = GetComponent(CharacterController); controller.slopeLimit = 46.0; controller.Move(Vector3(1,0,0)); } Nuestra esfera s ascender por la rampa, ya que el grado de inclinacin de esta es inferior al que puede asumir nuestro character controller. Pero le asignamos a slopeLimit el valor 45.0. observaremos que ya la esfera se niega a subir.

stepOffset: var stepOffset : float Los lmites de altura que el character controller podr superar, fijados en metros.(no podr por ejemplo subir una escalera si cada escaln mide ms de ese lmite) Para trabajar con un ejemplo, vamos a seleccionar el gameobject que nos sirvi como rampa en el ejemplo anterior. Le establecemos estos valores: position: 0,0,0 rotation: 0,0,90 scale: 0.6,3,1 Por otro lado, a nuestro cubo le vamos a aumentar momentneamente la altura (scale.y = 4). Y tecleamos el siguiente cdigo para nuestra esfera: function Update () { var controller : CharacterController = GetComponent(CharacterController); controller.stepOffset = 0.3; controller.Move(Vector3(1,0,0)); } Tomemos nota de que la antigua rampa tiene una altura de 0.6. En cambio, a nuestro character controller le hemos limitado la capacidad de superar alturas mayores de 0.3, por lo que cuando le demos al play...la esfera topar con la rampa. En cambio, si variamos el valor de stepOffset y lo colocamos, por ejemplo, a 0.9, la esfera no tendr problemas en superar la rampa, aunque tras hacerlo topar con el cubo. Por experiencia personal, las mediciones de esta variable no siempre resulta exactas, ya que no todos los gameobjects se asientan completamente y de manera exacta sobre el suelo, o ste presenta desniveles. Para evitar este tipo de

inexactitudes es necesario probar el comportamiento de los objetos y modificar stepOffsset en consecuencia, hasta dar con el comportamiento adecuado. Borramos la rampa y devolvemos al cubo a sus dimensiones habituales y a su posicin 0,0,0.

detectCollisions: var detectCollisions : boolean Determina si otros rigidbodies o character controllers colisionan con nuestro character Controller (por defecto esto est siempre habilitado). Esta variable no afecta a las colisiones que nuestro character controller sufre cuando se mueve, sino las que sufre a raz del movimiento de otros character controllers o colliders, y en concreto a si esos colliders o character controllers entrantes deben ser bloqueados por nuestro controller. Para este ejemplo tenemos que escribir dos scripts. Abrimos MiPrimerScript, que deberamos tener vinculado a nuestra esfera, y tecleamos: function Update () { var controller : CharacterController = GetComponent(CharacterController); controller.detectCollisions = false; } Aqu meramente le decimos a nuestro character controller que no queremos que bloquee los colliders entrantes. Y ahora abrimos MiSegundoScript y escribimos: function FixedUpdate() { rigidbody.AddForce(-10,0,0); } Le asignamos este segundo script al cubo, de tal forma que se desplazar hacia la izquierda, hasta colisionar con la esfera. Es preferible colocar la escena en vista superior (eje Y del gizmo). Le damos al play. Y tal como era de esperar, nuestra esfera no bloquea al cubo. Eso s, si lo hubiramos hecho al revs (mover la esfera hacia el cubo) aunque la variable detectCollisions estuviera en false, se producira la colisin y el consiguiente bloqueo.

FUNCIONES: Move: function Move (motion : Vector3) : CollisionFlags Esta funcin mueve un character controller en la direccin y velocidad establecida por el parmetro de tipo vector tres. Dicho movimiento slo ser restringido por las colisiones que sufra el character. Empecemos por un ejemplo bsico. Eliminamos el script vinculado al cubo, y acto seguido modificamos el script vinculado a la esfera, para que quede as: private var miCharCol : CharacterController; miCharCol = GetComponent(CharacterController); function Update() {

miCharCol.Move(Vector3(1 * Time.deltaTime ,0,0)); } No tiene mucho misterio. Almacenamos el componente character controller de nuestro gameobject en una variable (que declaramos como privada para que no sea accesible desde el inspector), y acto seguido le damos un movimiento de una unidad por segundo a la derecha. Pulsando el play efectivamente la esfera se desplaza hasta que topa con el cubo. El collider del cubo en este caso detiene el avance de la esfera, porque lo intercepta de pleno. Pero si al cubo lo ubicamos en position.Z= 0.8 y volvemos a darle al play, observamos que la esfera no detiene su avance. Choca y se desplaza de manera acorde a la colisin, pero acto seguido contina avanzando hacia la derecha. La funcin devuelve una variable de tipo collisionFlags, que estudiamos hace un par de captulos, y que aporta informacin sobre la ubicacin de las colisiones que ha sufrido el character controller. Con esa informacin, podemos alterar el comportamiento de nuestro character controller cuando sufra una colisin en una zona determinada de su cpsula. Ampliamos el script anterior, para que quede as: private var miCharCol : CharacterController; miCharCol = GetComponent(CharacterController); private var direccion : Vector3 = Vector3.right; function Update() { var misGolpes : CollisionFlags = miCharCol.Move(direccion * Time.deltaTime); if(misGolpes == CollisionFlags.Sides) { direccion = Vector3(0,0,-1); } } La esfera empieza su desplazamiento hacia la derecha (que es la direccin inicial que se le asigna a la funcin Move), hasta que colisiona con el cubo. Al hacerlo, nuestro condicional "if" detecta si la colisin se ha producido en uno de los laterales de la cpsula de nuestro character controller (CollisionFlags.Sides) y, para ese caso, se le pasa un nuevo vector3 a la direccin de la esfera.

SimpleMove: function SimpleMove (speed : Vector3) : boolean Podramos deducir que esta funcin es similar a la anterior, y as es, pero con algunas peculiaridades. Por ejemplo, si a nuestra esfera le asignamos el siguiente script... function Update() { var miCharCol : CharacterController = GetComponent(CharacterController); miCharCol.SimpleMove(Vector3(1 * Time.deltaTime, 0,0)); } ...podramos esperar que la esfera se moviera hacia la derecha, pero se da el caso de que a la que presionamos play la esfera atraviesa el suelo y cae. Esto es porque esta funcin automticamente le asigna gravedad al character controller que la llama. Por otro lado, esta funcin no devuelve informacin sobre el lugar de contacto en que se ha producido las colisiones.

8. CLASE RENDERER

Un render vendra a ser el proceso por el que un ordenador muestra una imagen. De ah que sea incuestionable la importancia de esta clase dentro de Unity. Tanto los gameobjects como algunos componentes tiene una propiedad renderer a la que podemos acceder/modificar, o que incluso se puede deshabilitar para hacer dicho gameobject o componente invisible.

VARIABLES: enabled: var enabled : boolean Hace el objeto visible (true) o invisible (false).

castShadows: var castShadows : boolean Proyecta sombras este objeto?

receiveShadows: var receiveShadows : boolean Recibe sombras este objeto?

material: var material : Material El material de nuestro objeto. Modificar esta variable slo cambiar el material para este objeto. Si el material que asignamos a nuestro objeto est siendo usado para otros renders, se clonar el material compartido y se asignar una copia de dicho material para nuestro objeto. La variable es de tipo Material,que estudiaremos en su momento, y que nos permite cambiar el color del objeto, su textura y la manera en que reacciona a la luz, entre otras propiedades. Veamos un ejemplo sencillo. Le asignamos este script a la esfera: renderer.material.color = Color.green; renderer.material.shader = Shader.Find( "Transparent/Diffuse" ); renderer.receiveShadows = false; Al darle al play, podemos observar el cambio de apariencia.

sharedMaterial: var sharedMaterial : Material Hace referencia al material que nuestro objeto comparte con otros. Modificar esta variabla cambiar la apariencia de todos los objetos que usen este material y las propiedades del mismo que estn almacenadas en el proyecto tambin, razn por la que no es recomendable modificar materiales retornados por sharedMaterial. Si quieres modificar el material de un renderer usa la variable material en su lugar.

sharedMaterials: var sharedMaterials : Material[] Devuelve un array con todos los materials compartidos de este objeto, a diferencia de sharedMaterial y material, que slo devuelven el primer material usado si el objeto tiene ms de uno. Unity soporta que un objeto use mltiples materiales. Al igual que la variable anterior y por la misma razn, no es aconsejable modificar materiales devueltos por esta variable

materials: var materials : Material[] Devuelve un array con todos los materiales usados por el renderer.

bounds: var bounds : Bounds Es una variable de slo lectura que indica los lmites del volumen del renderer. A cada renderer Unity le asigna una caja invisible que contiene (que envuelve) al objeto y cuyos bordes estn alineados con los ejes globales. De esta manera a Unity le resulta ms sencillo hacer clculos de desplazamiento y situacin. Por ejemplo, renderer.bounds.center normalmente es ms preciso para indicar el centro de un objeto que transform.position, especialmente si el objeto no es simtrico. Pensemos, para aproximarnos intuitivamente al concepto, en esas rosas que vienen dentro de cajas transparentes de plstico. En cualquier caso, la estructura Bounds la estudiaremos ms adelante.

lightmapIndex: var lightmapIndex : int El ndice del lightmap aplicado a este renderer. El ndice se refiere al array de lightmaps que est en la clase LightmapSettings. Un valor de 255 significa que no se ha asignado ningn lightmap, por lo que se usa el que est por defecto. Una escena puede tener varias lightmaps almacenados en ella, y el renderer puede usar uno o varios. Esto hace posible tener el mismo material en varios objetos, mientras cada objeto puede referirse a un ligthmap diferente o diferente porcin de un lightmap.

isVisible: ar isVisible : boolean

Variable de slo lectura que indica si el renderer es visible en alguna cmara. Hay que tener presente que un objeto es considerado visible para Unity cuando necesita ser renderizado en la escena. Podra por lo tanto no ser visible por ninguna cmara, pero todava necesitar ser renderizado (para proyectar sombras, por ejemplo).

FUNCIONES: OnBecameVisible: function OnBecameVisible () : void Esta funcin (del tipo mensaje enviado) es llamada cuando el objeto se vuelve visible para alguna cmara. Este mensaje es enviado a todos los scripts vinculados al renderer. Es til para evitar clculos que son slo necesarios cuando el objeto es visible. Recordemos que la sintaxis de este tipo de funciones es distinta, as que si quisiramos por ejemplo que un gameobject fuera visible cuando fuera a salir en una cmara, escribiramos esto: function OnBecameVisible() { enabled = true; }

OnBecameInvisible: function OnBecameInvisible () : void Es llamada cuando el objeto ya no es visible por ninguna cmara.

9. CLASE MESHFILTER

Un mesh filter (o filtro de malla) toma una malla de la carpeta de assets y se la pasa a mesh renderer para renderizarla en la pantalla. Es, para entendernos, la estructura de alambre de la malla.

VARIABLES: mesh: var mesh : Mesh Devuelve la instancia de malla asignada al mesh filter. Si no se ha asignado ninguna malla al mesh filter se crear y asignar una nueva. Si la malla asignada al mesh filter es compartida por otros objetos, automticamente se duplicar y la malla instanciada ser retornada. Usando las propiedades de malla puedes modificar la malla para un solo objeto solamente. Los otros objetos que usan la misma malla no sern modificados. Cuando estudiemos la clase Mesh aprenderemos las diferentes posibilidades de alteracin y deformacin de mallas que esto nos permite.

sharedMesh: var sharedMesh : Mesh Devuelve la malla compartida del mesh filter. Es recomendable usar esta funcin slo para leer datos de malla y no para escribirlos, dado que podras modificar los assets importados y todos los objetos que usan esta malla podran ser afectados. Tengamos en cuenta tambin que no ser posible deshacer los cambios hechos a esta malla.

10. CLASE JOINT

Es la clase base para todos los tipos de joints. Por clase base queremos decir que no podemos instanciarla como tal, sino que sirve para ser heredada por diferentes tipos de joint (hingejoint, springjoint, characterjoint) que estudiaremos a continuacin. Podramos traducir joint por juntura o articulacin, pero en principio usaremos la palabra en ingls. No obstante, tal como denota el significado en castellano de joint, podemos deducir que esta clase sirve para unir varios objetos de una manera u otra (pensemos en una puerta unida por una bisagra, en las articulaciones que mantienen unidos los huesos, o meramente en una pared de objetos-ladrillo.)

VARIABLES: connectedBody: var connectedBody : Rigidbody Esta variable referencia a otro rigidbody con el que este nuestra variante de joint conecta. Si la variable es null, el joint conecta el objeto con el mundo, esto es, en lugar de estar vinculado a otro rigidbody, nuestro objeto quedar "clavado" en su lugar en la escena.

axis: var axis : Vector3 El eje altededor del cual el movimiento del rigidbody estar restringido, indicado en coordenadas locales.

anchor: var anchor : Vector3 La posicin del ancla alrededor de la cual el movimiento de los joints est restringido. La posicin es definida en espacio local. Un poco ms adelante realizaremos una serie de ejemplos que nos permitir comprender con mayor claridad la funcionalidad de estas variables.

breakForce: var breakForce : float La fuerza que es necesario aplicarle a este joint para romperlo. La fuerza podra venir por colisiones con otros objetos, fuerzas aplicadas con rigidbody.AddForce o por otros joints. Vamos a realizar una serie de ejemplos que incluirn tanto las variables vistas en la leccin anterior como en sta. Para ello vamos a seguir los siguientes pasos: 1.- Eliminamos en el inspector el hingejoint de la esfera, y a sta le aadimos un sphere collider. La ubicamos en la posicin (-1,0,-5). Le eliminamos el script que tena vinculado. 2.-Vamos al men gameobject=>Create other=>Cube. Ubicamos este cube en (-1,0,0) y le aadimos un hingejoint. 3.-Editamos el script MiPrimerScript como sigue: var pegadoATi : Rigidbody; hingeJoint.connectedBody = pegadoATi; hingeJoint.breakForce = 20; 4.-Asignamos MiPrimerScript al recin creado gameobject Cube, y luego arrastramos nuestro cubo a la variable pegadoATi. 5.-Editamos ahora MiSegundo script, tecleando: function FixedUpdate() { rigidbody.AddForce(0,0,9); } 6.-Este script se lo asignamos a la esfera. Bueno, pues vamos ahora a jugar a los bolos ms rupestres de la historia. Tenemos por un lado dos cubos unidos por un joint (el cubo que tiene el hinge joint y el cubo unido a ste primero a travs de la variable connectedBody), con una fuerza de ruptura de 20, y una esfera dispuesta a chocar contra el cubo situado a nuestra izquierda con una fuerza de 9. Dmosle al play y probemos qu sucede. Est claro que es mayor la resistencia del cubo que la fuerza de la esfera. Veamos si la variable breakForce ha tenido algo que ver en dicha resistencia cambiando su valor de 20 a 4. Play. Observamos que -aunque con algo de esfuerzo- ahora s la esfera rompe el joint y consigue arrastrar el cubo de la izquierda (el portador del hingejoint).

Hagamos ahora unas pequeas modificaciones: Ubicamos la esfera en (0,0,-5) para que nos vaya a impactar al cubo que no tiene asignado el hingejoint. Para hacer un acercamiento intuitivo al ejercicio, podemos pensar que el cubo situado a nuestra izquierda (cube) sera el marco y el de nuestra derecha (nuestro cubo) la puerta. Visto as, ahora vamos a intentar impactar nuestra esfera con la puerta. Restablecemos la variable breakForce a 20. Le damos al play. Veremos que la esfera arrastra al cubo (abre la puerta), pero no rompe su unin con el otro cubo. Cambiemos de nuevo la variable breakForce de valor, pongmmosle un 1. De nuevo play. Observad cmo la esfera no tiene problemas en romper la juntura. Pero vamos a seguir jugando con las variables que hemos ido viendo en estos dos captulos. Antes que nada desplazaremos un poco nuestra esfera para que slo golpee en el cubo que no tiene el hinge joint, as que ubicamos la esfera en (0.5,0,-5) Vamos a aadir luego la variable axis a MiPrimerScript, de la siguiente manera: var pegadoATi : Rigidbody; hingeJoint.connectedBody = pegadoATi; hingeJoint.axis = Vector3.up; hingeJoint.breakForce = 20; Recordemos que axis indica el eje alrededor del cual el movimiento de nuestro rigidbody portador del hingejoint permanecer bloqueado. Por lo tanto, si bloqueamos el eje up/down a travs de la variable axis, tericamente el cubo de nuestra izquierda no debera girar sobre dicho eje. Como truco os recomendara que antes de darle al play seleccionrais en el inspector el Cube, para que veis la flecha naranja saliendo del gameobject. Al darle al play, la flecha sealar en la direccin del eje indicado por la variable axis. Pulsamos el play, decimos, y tal como esperbamos, la esfera pasa a travs del cubo de nuestra derecha, pero el que tiene el hinge joint no gira sobre su eje vertical. La diferencia resulta muy clara si cambiamos en lugar de Vector3.up colocamos Vector3.forward como valor de axis. probadlo sin miedo. Probemos ahora la variable anchor, que tal como indicbamos indica la posicin del ancla alrededor de la cual se restringe el movimiento de los joints. Probemos a dejar MiPrimerScript as: var pegadoATi : Rigidbody; hingeJoint.connectedBody = pegadoATi; hingeJoint.axis = Vector3.right; hingeJoint.anchor = Vector3(0,0,0); hingeJoint.breakForce = 20; Hemos cambiado, como vemos, el eje que restringir la variable axis, pasando del eje arriba/abajo al derecha/izquierda. Ubicamos la variable anchor en las coordenadas locales de nuestro hingejoint (0,0,0). Dmosle al play y observemos por un lado la ubicacin de la flecha naranja (recordemos previo pulsar play dejar seleccionado Cube) y por otro el comportamiento de ambos cubos al ser impactados por la esfera. Vale. Ahora vamos a modificar la ubicacin del ancla. Dejmosla as: hingeJoint.anchor = Vector3(0,-0.5,0.5); Eso significa (recordemos que estamos en coordenadas locales del cube) que el ancla estar situada en el centro del cube respecto del eje X (0), en la parte inferior del cube respecto del eje Y (-0.5) y en la parte trasera del cube respecto al eje Z (0.5). Dmosle al play y observemos la situacin del ancla y la diferencia de comportamiento.

breakTorque: var breakTorque : float La torsin que es necesario aplicar a este joint para romperlo.

FUNCIONES: OnJointBreak: function OnJointBreak (breakForce : float) : void Funcin de tipo "mensaje enviado" que es llamada cuando un joint vinculado al mismo game object se rompe. Cuando una fuerza que es mayor que el breakForce del joint es aplicada, el joint se romper. En ese momento, esta funcin ser llamada y el la fuerza de ruptura aplicada al joint le ser pasada a la misma. Despus de OnJointBreak el joint automticamente ser borrado del game object. Adaptemos MiPrimerScript para explicar esta funcin: var pegadoATi : Rigidbody; hingeJoint.connectedBody = pegadoATi; hingeJoint.breakForce = 1.0; function OnJointBreak(resistencia : float) { Debug.Log("Se nos rompi el joint con resistencia " + resistencia); } El script es bastante sencillo. Le aplicamos a nuestro hingejoint una fuerza de ruptura baja, para asegurarnos de que el impacto de la esfera lo romper. Cuando esto suceda ser llamada la funcin OnJointBreak, que en este caso imprimir un mensaje en el que, adems de un texto, mostrar el valor que tendr tras la ruptura la variable que le pasamos como parmetro, y que coincidir con la fuerza de ruptura previamente asignada. Bueno, pues explicada la clase base, iremos a por las diferentes clases que heredan de joint.

11. CLASE HINGEJOINT

Esta clase agrupa juntos 2 rigidbodies, constreindolos a moverse como si estuvieran conectados por una bisagra. Este tipo de joints es perfecto para puertas, pero tambin puede usarse para modelar cadenas, por ejemplo.

VARIABLES: motor: var motor : JointMotor La variable motor aplicar una fuerza en aumento hasta conseguir la velocidad deseada en grados por segundo. Esta variable es de tipo JointMotor, que es una estructura que a su vez tiene las siguientes variables: targetVelocity force freeSpin Es la velocidad de desplazamiento o rotacin que se pretende conseguir. Es la fuerza que aplicar el motor para conseguir la velocidad fijada en targetVelocity. Es un booleano. Si est habilitado, el motor slo acelerar y nunca reducir.

Si unimos intuitivamente los conceptos junturas y motor, posiblemente se nos vengan a la cabeza engranajes, vehculos o maquinarias. Esa intuicin no va muy desencaminada. Hagamos las siguientes modificaciones para prepararnos el terreno. Eliminamos el script vinculado a la esfera. Luego vamos a colocar a nuestros cubos siameses (cubo y cube) dos unidades sobre tierra, lo que obviamente conseguiremos colocando su posicin (la de los dos) en el eje X en 2. En ambos casos, adems y para evitar que se nos caigan al suelo por la gravedad, en sus respectivos constrainst marcaremos Freeze Position Y. Ahora editamos el script MiPrimerScript (que si hemos seguido las lecciones al pie de la letra debemos tener vinculado a Cube), para que luzca as:

var pegadoATi : Rigidbody; hingeJoint.connectedBody = pegadoATi; hingeJoint.anchor = Vector3(0,0,0); hingeJoint.motor.force =100; hingeJoint.motor.targetVelocity = 90; hingeJoint.motor.freeSpin = true; Resumamos lo que hemos hecho: El rigidbody del segundo cubo (el que no tiene asignado un hingeJoint) es asignado a la variable pegadoATi, que posteriormente es conectada al hingeJoint. El ancla entre ambos cubos (que por defecto se ubica en el eje X) la colocamos en el centro geomtrico del cubo, para que el giro que pretendemos sea ms natural. Luego aplicamos un motor al hingejoint con una fuerza de 100 hasta conseguir alcanzar una velocidad de 90 grados por segundo, y sin que el motor pueda reducir. Dmosle al play para comprobar que funciona. El motor trata de alcanzar la velocidad angular de motor.targetVelocity en grados por segundo. El motor slo ser capaz de alcanzar motor.targetVelocity si motor.force es suficientemente grande. Si el joint est girando ms rpido que el motor.targetVelocity el motor se romper. Un velor negativo para motor.targetVelocity har que el motor gire en direccin contraria. El motor.force es la torsin mxima que el motor puede ejercer. Si es cero el motor se deshabilita. El motor frenar cuando gire ms rpido que motor.targetVelocity slo si motor.freeSpin es false. Si motor.freeSpin es true el motor no frenar.

limits: var limits : JointLimits Variable que establece/indica los lmites de nuestro hingejoint (recordemos, para que tengamos ms o menos claro a qu nos referimos con lo de lmites, que hinge lo podemos traducir por "bisagra"). La variable es del tipo JointLimits, que es una estructura que a su vez tiene las siguientes cuatro variables: min max minBounce maxBounce Es el lmite inferior del joint. Cuando el ngulo o posicin del joint se halla por debajo de este valor, el joint recibe la fuerza necesaria para restablecerlo a ese mnimo. El lmite superior del joint. Si el ngulo o posicin de ste est por encima de este valor, el joint recibe fuerzas para restablecerlo a dicho mximo. La capacidad de retorno del joint a su lmite inferior cuando es golpeado por debajo de ste (pensemos en las puertas del Saloon. Lo mismo que la anterior aplicado al lmite superior.

El joint ser limitado para que el angulo est siempre entre limits.min y limits.max. Dicho ngulo se calcula en trminos relativos al ngulo existente al principio de la simulacin, esto es, si entre dos rigidbodys hay ya al inicio un ngulo de 20, si su variable limits.min la fijamos en 10, el ngulo real ser de 30 Vamos a trastear un rato, que es la mejor manera de quedarse con los conceptos. De entrada, vamos a devolver al suelo a nuestros cubos, as que devolvemos sus transform.position.y respectivas a cero, y no nos olvidemos de desmarcar la casilla de sus constraints que marcamos en el ejemplo anterior. Por otro lado, el script MiSegundoScript, que en el anterior captulo le habamos sustraido a la esfera, se lo volvemos a asignar, para que de nuevo impacte contra nuestros cubos. Le daremos algo ms de fuerza (AddForce(0,0,20)). Ubicaremos a la esfera en la posicin 0.3,0,-5.

Ahora vamos a intentar convertir los cubos en lo ms parecido a una puerta, y le vamos a dar unos ngulos mximo y mnimo de apertura. Para evitar que el cubo que tiene asignado el hinge joint (cube) se nos mueva demasiado le asignaremos un valor a su variable mass en el rigidbody (en el inspector ) de 6. Y tecleamos en MiPrimerScript: var pegadoATi : Rigidbody; hingeJoint.connectedBody = pegadoATi; hingeJoint.axis = Vector3.up; hingeJoint.anchor = Vector3(0.5,-0.5,0.5); hingeJoint.limits.min = 0; hingeJoint.limits.max = 70; hingeJoint.limits.minBounce = 0; hingeJoint.limits.maxBounce = 0; Si lo probamos, veremos que al impacto de la esfera nuestro joint alcanza un grado mximo de 70 grados, sin rebote. Si quisiramos obtener un rebote de nuestra puerta precaria, podramos asignarle a maxBounce un valor de 4, por ejemplo.

spring: var spring : JointSpring Esta variable intenta alcanzar un ngulo que es su objetivo a base de aadir fuerzas de resorte y amortiguacin. Podemos traducir en este contexto spring como muelle, lo que nos da una idea del tipo de impulso del que estamos hablando. El tipo de esta variable es JointSpring, que tal como podemos suponer es de nuevo una estructura, que en este caso consta de tres variables: spring damper targetPosition La fuerza tipo resorte para alcanzar la targetPosition, del ngulo deseado. Un valor ms grande hace que alcancemos la posicin ms rpido. La fuerza del amortiguador usada para amortiguar la velocidad angular. Un valor ms grande hace que alcance el objetivo ms lento. la posicin que el joint intenta alcanzar. El spring alcanza la targetPosition en ngulos relativos al ngulo inicial.

Pongmoslo con un ejemplo. Para ello previamente eliminamos el script vinculado a la esfera. Y luego, MiPrimerScript debera quedar como sigue: var pegadoATi : Rigidbody; hingeJoint.connectedBody = pegadoATi; hingeJoint.axis = Vector3.up; hingeJoint.anchor = Vector3(0.5,-0.5,0.5); hingeJoint.spring.spring = 20; hingeJoint.spring.damper = 6; hingeJoint.spring.targetPosition = 90; Aqu abriremos nuestra puerta precaria con un impulso inicial de 20 y una amortiguacin de 6, tendiendo a alcanzar los 90 grados. Si le damos al play notaremos el evidente efecto catapulta.

useMotor: var useMotor : boolean Habilita/deshabilita el motor del joint.

useLimits: var useLimits : boolean Habilita/deshabilita los lmites del joint.

useSpring: var useSpring : boolean Habilita/deshabilita el resorte del joint.

velocity: var velocity : float Devuelve la velocidad actual del joint en grados por segundo.

angle: var angle : float Devuelve el ngulo actual en grados del joint con respecto a la posicin inicial. Es una variable de solo lectura.

12. CLASE SPRINGJOINT

El spring joint ata juntos dos rigid bodies que se encuentran a una cierta distancia. Las fuerzas spring (resorte) se aplicarn automticamente para mantener el objeto a la distancia dada, intentando mantener la distancia que haba cuando empez. Las propiedades minDistante y maxDistance aaden unos lmites de implcita distancia.

VARIABLES: spring: var spring : float La fuerza del spring usada para mantener los dos objetos juntos.

damper: var damper : float La fuerza de amortiguacin usada para amortiguar la fuerza del spring.

minDistance: var minDistance : float La distancia mnima entre los rigidbodies relativa a su distancia inicial. La distancia que habr de mantenerse se conservar entre minDistance y maxDistance. Ambos valores son relativos a la distancia entre los respectivos centros de masa cuando la escena fue cargada al principio.

maxDistance: var maxDistance : float La distancia mxima entre los rigidbodies relativa a su distancia inicial.

Veamos todo esto con un ejemplo rpido, para lo cual previamente haremos las pertinentes modificaciones en la interfaz de Unity. Asignamos (una vez ms) el script MiSegundoScript a la esfera. Seleccionamos "Cube" en la jerarqua, y lo ubicamos en position.x = -3. Asimismo le eliminamos el componente hingejoint y en components=>Physics=>spring joints le aadimos un spring. Observaremos que ahora el cube en lugar de una flecha tiene un minicubo. Y -ahora s- remozamos MiPrimerScript: var pegadoATi : Rigidbody; var springJoint : SpringJoint; springJoint = GetComponent(SpringJoint); springJoint.connectedBody = pegadoATi; springJoint.spring = 25; springJoint.damper = 4; springJoint.minDistance = 0; springJoint.maxDistance = 0; Veamos lo que hemos querido hacer. En primer lugar declaramos una variable (que la llamamos springJoint por claridad didctica, pero que hubiramos podido darle otro nombre legal) de tipo SpringJoint y le asignamos el componente SpringJoint de nuestro cube. Luego vinculamos el cubo a nuestro joint. Y a partir de ah le damos al sprint/resorte una fuerza de recuperacin de 25, una de amortiguacin de 4, y establecemos la distancia mnima y mxima la que ya ambos cubos tenan al darle al play, esto es, 3 metros. Si quisiramos que los cubos tras el impacto de la esfera quedaran a ms o menos distancia de la inicial retocaramos respectivamente minDistance o maxDistance. Dadle al play. Nuestro muelle retiene al cubo a la distancia estipulada del portador del spring joint. Podis jugar con spring y damper para que esa fuerza de tipo resorte sea ms o menos acusada.

13. CLASE CHARACTERJOINT

Esta clase, como su nombre indica, es principalmente usada con personajes. En concreto, la utilidad bsica de la misma consiste en simular lo que se vienen llamando efectos Ragdoll (proceso de animacin para simular muertes, valga la aparente paradoja). Ragdoll podra traducirse como "mueca de trapo", para que nos hagamos una idea del efecto que se pretende conseguir.Esta especialidad de joint nos permite limitar el joint de cada eje.

VARIABLES: swingAxis: var swingAxis : Vector3 El eje secundario alrededor del cual el joint puede rotar. Los lmites de rotacin permitida alrededor de este eje vendrn establecidos por CharacterJoint.swing1Limit.

lowTwistLimit: var lowTwistLimit : SoftJointLimit El lmite menor del ngulo permitido alrededor del eje primario del characterjoint. El lmite es relativo al ngulo de los dos rigidbody con el que comenz la simulacin. La variable es de tipo SoftJointLimit, que es una estructura con estos valores: limit: spring: damper: bounciness: El lmite de posicin u ngulo del joint. Si es mayor que cero, el lmite es soft. El spring retornar el joint a su posicin inicial. Si spring es mayor que cero, el lmite es soft. Cuando el joint golpea el lmite, esta variable puede establecerse para impedir un rebote.

highTwistLimit: var highTwistLimit : SoftJointLimit El lmite superior altededor del eje primario del characterjoint. El lmite es relativo al ngulo de los dos rigidbody con el que comenz la simulacin.

swing1Limit: var swing1Limit : SoftJointLimit El lmite alrededor del eje primario del characterjoint. El lmite es simtrico, as que un valor de 30 limitara la rotacin entre -30 y 30. El lmite es relativo al ngulo de los dos rigidbodys con que empez la simulacin.

swing2Limit: var swing2Limit : SoftJointLimit El lmite alrededor el eje primario del joint del character.

Lamentablemente, por la especificidad de esta clase en estos momentos no podemos utilizar ejemplos, pero cuando estemos a un nivel ms avanzado me comprometo volver a esta clase para verla con ms profundidad y claridad (y si yo me olvido, que alguien me lo recuerde por el blog, please).

14. CLASE BEHAVIOUR

Para comprender el sentido de la clase Behaviour he considerado que lo mejor era traer a la vista de nuevo el organigrama general que estuvimos comentando en las primeras lecciones. Si os fijis ya hemos estudiado todas las clases que derivaban de Component, a excepcin de sta, de la que a su vez deriva otra serie de clases (que son las que estudiaremos a continuacin). Explico todo esto porque la clase Behaviour, como tal, slo cuenta con una variable (con independencia, obviamente, de las que hereda de Object y Component). Dicha variable es

enabled: var enabled : boolean Como podemos imaginar, esta variable solamente habilita o deshabilita el objeto Behaviour (y/o los objetos derivados de esta clase) de un gameobject. Dicho de otra forma, tenemos por un lado las clases que derivan directamente de Component (las que ya hemos estudiado) y por otro las que derivan de Behaviour, que heredan lo mismo que las anteriores, ms una variable que les permite deshabilitarse. Esto es, la diferencia entre, por ejemplo, transform y camera es que la segunda se puede desactivar. Esto lo podemos comprobar en el inspector, con la main camera seleccionada: veremos que Camera cuenta con un checkbox (el equivalente a la variable enabled) y Transform no. Os suelto este rollo para que entendis que las clases que explicaremos a continuacin son en esencia de raz idntica a las ltimas que hemos estudiado, con la peculiaridad indicada.

15. CLASE MONOBEHAVIOUR

Como podris deducir de un mero vistazo a las funciones contenidas en esta clase, estudiarla nos va a llevar un buen rato. La clase Monobehaviour es uno de los miembros destacados del top ten de la API de Unity, as que es vital dominarla con una cierta solvencia. MonoBehaviour es la clase base de la que derivan todos los scripts. Ni ms ni menos. Al ser clase base, salvo en C# no hace falta escribirla expresamente cuando llamemos a alguna de sus funciones, pues Unity la da por sobreentendida. Dicho de otra manera, para Unity es lo mismo esto MonoBehaviour.Invoke() que esto Invoke() Vamos ya a empezar con las funciones de MonoBehaviour:

FUNCIONES:

Invoke: function Invoke (methodName : String, time : float) : void Llama a la funcin que le pasemos como primer parmetro en el tiempo contado en segundos que le indiquemos como segundo parmetro. Aunque creo que el funcionamiento de esta funcin es bastante evidente, nada mejor que verlo con un ejemplo. Y previamente a empezar a disear el mismo, vamos a reorganizar nuestra escena en la interfaz de Unity siguiendo estos pasos:

1.- Eliminamos el Gameobject Cube. 2.- Ubicamos el Gameobject Cubo en -2,0,0. 3.- Eliminamos el script vinculado a la esfera. 4.- Colocamos la esfera en 2,0,0. 5.- Asignamos por la va de arrastre MiPrimerScript en Project al GameObject PortaScripts. Si por lo que sea no has seguido todas las lecciones y en la jerarqua no tienes un gameobject con ese nombre, crea un Gameobject vaco y lo bautizas como PortaScripts. 6.- Doble click en MiPrimerScript para abrir el editor y poder trabajar en l. Tecleamos esto: var original : GameObject; function OtroDeLoMismo() { Instantiate(original, original.transform.position + Vector3.right, original.transform.rotation); } Invoke("OtroDeLoMismo", 5); Seleccionamos PortaScripts y en el inspector arrastramos el cubo hasta el valor de la variable Original. Pulsamos el play. Transcurridos cinco segundos, observaremos que la funcin Invoke llama a la funcin OtroDeLoMismo, que a su vez crea una instancia clonada de nuestro cubo una unidad a la derecha. Si queremos, podemos arrastrar la esfera a la variable Original, para que sea ella la clonada. Un problema que me he encontrado a la hora de hacer este ejemplo, es que no s si Invoke funciona para llamar a una funcin que tenga uno o ms parmetros, y en caso afirmativo cmo se ha de aadir dicho parmetro al string. Si alguien conoce la respuesta a esto agradecera lo reportara en el blog.

InvokeRepeating: function InvokeRepeating (methodName : String, time : float, repeatRate : float) : void Invoca la funcin que le pasamos como string para dentro del nmero de segundos que le pasamos como segundo parmetro, y una vez se ejecuta, lo vuelve a hacer cada repeatRate segundos (el tercer parmetro. Veremos claramente su funcionamiento rehaciendo ligeramente el ejemplo anterior (previamente es mejor que coloquemos la esfera en position.Z = 3): var original : GameObject; function OtroDeLoMismo() { var copia : GameObject = Instantiate(original, original.transform.position + Vector3.right, original.transform.rotation); copia.transform.position += Vector3(Time.time - 5, 0,0); } InvokeRepeating("OtroDeLoMismo", 5,1); Arrastramos nuestro cubo para inicializar la variable "original" en el inspector, y le damos al play. Nuestro cubo, pasados los 5 primeros segundos, empezar a clonarse cada segundo.

Vamos por partes: Lo que hemos hecho es primero declarar una funcin que -al igual que en el ejemplo anterior- clona el objeto que le hayamos arrastrado a "original" y lo coloca una unidad a la derecha del objeto clonado. Asimismo, para que no se nos amontonen los cubos en el mismo punto, aprovechamos que la funcin Instantiate devuelve el objeto clonado, para almacenarlo en una variable -que llamamos copia- y lo que hacemos es que cada nuevo objeto instanciado se mueva una unidad ms a la derecha que el anterior, cosa que obtenemos aprovechando que Time.time hace precisamente eso, avanzar una unidad cada segundo. Al resultado le restamos 5, que es el nmero de segundos que transcurren hasta que empiezan a clonarse los cubos, por obra y gracia del segundo parmetro de InvokeRepeating. Si no le restramos ese 5, el primer muro se clonara 5 unidades a la derecha del cubo clonado. Observamos que, centrndonos en la funcin estudiada, que InvokeRepeating llama a la funcin transcurridos 5 segundos -en este caso- y pasados los mismos, se repite de forma infinita cada segundo (3er parmetro).

CancelInvoke: function CancelInvoke () : void function CancelInvoke (methodName : String) : void Tal como seguro que estaris suponiendo, CancelInvoke cancela las funciones que hayan sido invocadas por las dos funciones anteriores para un determinado script. La primera variacin de esta funcin no tiene parmetros, y al llamarse cancela todas las funciones Invoke e InvokeRepeating del script. La segunda variacin de la funcin slo cancelar la funcin de dicho tipo que coincida con el nombre que se le pasa como parmetro. Arreglemos un poco ms nuestro script dndole al usuario la posibilidad de cancelar la clonacin de cubos: var original : GameObject; function OtroDeLoMismo() { var copia : GameObject = Instantiate(original, original.transform.position + Vector3.right, original.transform.rotation); copia.transform.position += Vector3(Time.time - 5, 0,0); } InvokeRepeating("OtroDeLoMismo", 5,1); function Update() { if (Input.GetButton ("Fire1")) CancelInvoke(); } Es la misma funcin anterior, slo que con el aadido que le hemos puesto, la funcin update comprobar cada frame si el usuario ha pulsado la tecla definida en input como Fire1. Si tenemos la configuracin por defecto, debera ser el ctrl izquierdo o el botn izquierdo del ratn.

IsInvoking: function IsInvoking (methodName : String) : boolean Este primer prototipo de la funcin devuelve true si hay algn invoke pendiente de la funcin que se introduce como parmetro. function IsInvoking () : boolean En esta segunda modalidad devuelve true si algn invoke pendiente en este script.

StartCoroutine: function StartCoroutine (routine : IEnumerator) : Coroutine Antes de entrar a analizar esta funcin quisiera explicar aunque fuera de forma superficial lo que es una corutina y cmo son tratadas por Unity. Una corutina es una funcin -que individualizamos con la palabra clave yield- que puede suspender su ejecucin hasta que una instruction dada -que tambin contendr la palabra clave yield- termine. Vemoslo con un ejemplo sacado del manual de referencia de Unity: //Imprime Starting 0.0 print ("Starting " + Time.time); /* Se llama a continuacin a la funcin WaitAndPrint como coroutine, cosa que se consigue anteponiendo la palabra clave yield. Al hacer esto permitimos que la funcin se pueda suspender por una instruccin yield. Por lo tanto, el flujo del script se va a la funcin waitandprint, donde se encuentra con una instruccin yield que le dice que espere cinco segundos, luego imprimir WaitandPrint 5.0 (que ser el tiempo transcurrido desde el inicio del cmputo) y volver arriba para imprimir done 5.0 (o un nmero cercano).*/ yield WaitAndPrint(); print ("Done " + Time.time); function WaitAndPrint () { // suspende la ejecucin por 5 segundos yield WaitForSeconds (5); print ("WaitAndPrint "+ Time.time); } Si no veis clara la diferencia con el proceso secuencial habitual, no tenis ms que borrar la palabra yield que est antes de la llamada a la funcin. Si hacis eso, el programa empezar escribiendo "starting 0", bajar a la siguiente instruccin, donde se encuentra con la funcin WaitAndPrint, que le indica que no va a hacer nada durante cinco segundos, as que pasar inmediatamente a la siguiente declaracin e imprimir "Done 0", para luego, cinco segundos despus, imprimir por fin "Waitandprint 5".

Bien. Con estas nociones vamos ya a la funcin que nos ocupa, StartCoroutine. Como su nombre indica, inicia una corrutina cuya ejecucin puede ser pausada en cualquier momento usando una instruccin yield. Programando en javascript, no es necesario escribir StartCoroutine, ya que el compilador la dar por supuesta. Veamos un segundo ejemplo sacado igualmente del manual de referencia de Unity. En este ejemplo, a diferencia del anterior, vamos a invocar una corrutina que no suspender la ejecucin de la funcin que se desarrolla en paralelo: function Start() { // - Despus de 0 segundos imprimir "Starting 0.0" // - Despus de 0 segundos, imprimir "Before WaitAndPrint Finishes 0.0" // - Despus de 2 segundos imprimir "WaitAndPrint 2.0" //Empezamos (funcin Start) imprimiendo Starting 0.0 print ("Starting " + Time.time); /* Ahora vamos a iniciar la funcin WaitAndPrint como coroutine (en paralelo), pero sin suspender el flujo de llamadas a funciones que se puedan seguir dando en el hilo principal. Si hubiramos querido suspenderlo, hubiramos utilizado la

frmula del ejemplo anterior, y hubiramos antepuesto la palabra clave yield a la llamada a la funcin. Lo que sigue podra tambin haberse escrito (en javascript) as: WaitAndPrint(2.0) y el compilador aadira el StartCoroutine por ti automticamente.*/ StartCoroutine(WaitAndPrint(2.0)); /*Como no hemos interrumpido el flujo principal con yield, la declaracin que viene ahora se ejecutar antes que la la funcin anterior, puesto que la anterior ha de esperar dos segundos y el print que viene ahora no.*/ print ("Before WaitAndPrint Finishes " + Time.time); } function WaitAndPrint (waitTime : float) { // suspende la ejecucin por los segundos que le fijemos en waitTime yield WaitForSeconds (waitTime); print ("WaitAndPrint "+ Time.time); } La funcin StartCoroutine tiene una segunda modalidad: function StartCoroutine (methodName : String, value : object = null) : Coroutine Es como la funcin anterior, pero usando un string. Esta variante tiene una mayor sobrecarga de procesamiento, pero es la nica que se puede detener con StopCoroutine. Vamos a realizar otro ejemplo en el que , aparte de usar la variante con string de la funcin, aprovecharemos para ilustrar de nuevo otra posibilidad que nos dan este tipo de instrucciones Yield. El script ejecuta la funcin DoSomething, que dispara un bucle. Al siguiente frame el script se detendr un segundo al toparse con la instruccin yield, pasar al yielf waitforseconds, esperar un segundo y luego se detendr. function Start () { StartCoroutine("DoSomething", 2.0); yield WaitForSeconds(1); StopCoroutine("DoSomething"); } function DoSomething (someParameter : float) { while (true) { print("DoSomething Loop"); // Detiene la ejecucin de esta corutina y vuelve al loop principal hasta el //siguiente frame. yield; } }

StopCoroutine: function StopCoroutine (methodName : String) : void Como hemos visto en el ejemplo anterior, detiene las corrutinas con el nombre que le suministramos como parmetro iniciadas en este script. Dicho nombre de funcin lo hemos de pasar como un string, y no hemos de olvidar que slo las

corrutinas con el nombre indicado que se hayan iniciado mediante la variante string de StartCoroutine (la segunda modalidad de las anteriormente vistas) podrn ser detenidas con StopCoroutine.

StopAllCoroutines: function StopAllCoroutines () : void Detiene todas las corrutinas que estn corriendo en ese script.

El resto de funciones que nos quedan por estudiar de la clase MonoBehaviour (que son unas cuantas) son comnmente conocidas como "funciones sobreescribibles". El nombre les viene dado porque estas funciones tienen, con respecto a las "standard", la peculiaridad de que nos permiten disear nosotros su contenido. Por explicarlo de alguna manera, la firma de estas funciones, que es lo que nos brinda Unity, supondran el cundo y lo que nosotros escribiremos ser el qu y el cmo. Incidentalmente, y para entender un poco mas la plyade de funciones que vienen a continuacin, vamos a explicar el orden en que Unity inicializa los distintos elementos que lo componen cada vez que se carga una escena en el juego: -Primero se cargan los objects (game objects y components). -Acto seguido se cargan los scripts que van vinculados a estos objects, y una serie de funciones (las que veremos a continuacin) son llamadas en un orden especfico: 1. Awake. 2. Start. 3. Update/FixedUpdate. 4. LateUpdate.

Update: function Update () : void Esta funcin, con la que ya hemos lidiado en alguna ocasin, es llamada cada frame, si el Monobehaviour (script que la invoca) est activo. Es la funcin ms usada en los scripts, si bien arrastra el inconveniente de que cada ordenador puede tener un framerate distinto, por lo que la misma instruccin de movimiento, por ejemplo, dara pie a diferentes velocidades dependiendo del framerate de cada uno (con resultados catastrficos, sin ir ms lejos, en juegos online para varios jugadores). Para transformar las unidades de actualizacin de la funcin de frames a segundos se utiliza Time.deltaTime.

LateUpdate: function LateUpdate () : void LateUpdate es llamado una vez todas las funciones Update han sido llamadas. Esto nos permite ordenar la ejecucin de scripts. Por ejemplo, una cmara que sigue a un objeto debera implementarse en un lateUpdate, pues cabe que el objeto al que sigue se inicialice con un determinado movimiento en update, movimiento que debera tener en cuenta la cmara.

FixedUpdate: function FixedUpdate () : void Esta funcin se ejecuta cada cierto nmero preestablecido y fijo de frames, lo que hace que no presente los problemas de update. Se debe utilizar en aquellos scripts que impliquen un componente de fsicas, y sobre todo, siempre se ha de utilizar cuando haya que aadir una fuerza a un Rigidbody.

Awake: function Awake () : void Awake es llamada cuando se inicia el script, osea, cuando se carga la escena, y justo despus de que se carguen los objects (gameobjects y components) a que el script hace referencia. De tal manera, es til para inicializar variables o estados del juego antes de que el juego empiece, referenciando si es preciso a los objects a que hacen mencin (y que ya habrn sido como decimos inicializados previamente). Por ejemplo, dentro de un awake puedes tranquilamente usar Gameobject.FindWithTag. Cada funcin awake para gameobjects es llamada de forma aleatoria, razn por la cual se utiliza Awake para colocar referencias entre scripts (pej, el script X llamar al script Y) pero se ha de utiliza Start para pasar informacin de un lado a otro (pej: El script x le pasa el valor 5 al script Y), ya que Awake es llamada siempre antes que Start y as al mandar valores va Start nos aseguramos de que las relaciones entre scripts estn ya establecidas va Awake. Por ltimo, indicar que Awake no puede formar parte de una corrutina, y que ser llamada aunque en el inspector la instancia del script est deshabilitada/desmarcada.

Start: function Start () : void Es llamada despus de Awake y antes de Update. Al igual que awake, slo es llamada una vez a lo largo de toda la vida del script. Aparte del momento en que son llamadas, Start se diferencia de Awake en que Start slo es llamada si la instancia del script est habilitada, esto es, tiene su checkbox marcado en el inspector. As, cuando un gameobject es inicialmente usado en una escena esta funcin es llamada automticamente.

Reset: function Reset () : void

Resetea a los valores por defecto, restaurando los valores originales. Esta funcin es llamada cuando se pulsa reset en el inspector o cuando se aade un componente por primera vez.

OnMouseEnter: function OnMouseEnter () : void Esta funcin es llamada cuando el cursor entra en un collider o un GUIElement.

Vemoslo con un ejemplo muy sencillo. Tecleamos: function OnMouseOver(){ Debug.Log("El mouse est sobre el objeto " + gameObject.name); } Arrastramos el script al cubo. Pulsamos play y observaremos que cuando el cursor est sobre el cubo, se imprime la frase debajo de la ventana game.

Esta funcin no ser llamada en objetos que pertenezcan a Ignore Raycast layer. OnMouseEnter puede ser una corrutina, siempre que utilicemos una instruccin Yield en la funcin, y el evento ser enviado a todos los scripts vinculados con el collider o GUIElement

OnMouseOver: function OnMouseOver () : void Esta funcin es llamada cada frame en la que el mouse permanezca sobre el Collider o GUIElement, a diferencia de onMouseEnter, que slo se dispara cuando entra el mouse. Como esta funcin se actualiza cada frame, podemos hacer cosas como la del ejemplo: function OnMouseOver () { renderer.material.color += Color(0.1, 0, 0) * Time.deltaTime; } Si pulsamos play y mantenemos el cursor sobre el cubo, lentamente ste se ir tornando de color rojizo, debido al paulatino aumento del componente R (red) de su RGB. OnMouseOver puede ser, como OnMouseEnter, una corrutina, simplemente utilizando la declaracin yield en la funcin

OnMouseExit: function OnMouseExit () : void Esta funcin es llamada cuando el ratn ya no esta sobre un GUIElement o un Collider. Podemos completar con ella el script anterior: function OnMouseOver () { renderer.material.color += Color(0.1, 0, 0) * Time.deltaTime; } function OnMouseExit () { renderer.material.color = Color.white; } Cuando se retira el mouse del cubo, ste retorna a su color blanco inicial. Como las precedentes, la funcin no es llamada en objetos que tienen el Ignore Raycast Layer y puede formar parte de una coroutine.

OnMouseDown: function OnMouseDown () : void Es llamada cuando el usuario pulsa el botn del mouse sobre un GUIElement o Collider. Por seguir con el ejemplo anterior, podramos aadir al script: function OnMouseOver () { renderer.material.color += Color(0.1, 0, 0) * Time.deltaTime; } function OnMouseExit () { renderer.material.color = Color.white; } function OnMouseDown () { renderer.material.color = Color.blue; } Al presionar el botn del ratn, el cubo se torna de color azul. A esta funcin le es de aplicacin lo indicado para las precedentes en relacin con Ignore Raycast y la posibilidad de ser una corrutina.

OnMouseUp: function OnMouseUp () : void Esta funcin es llamada cuando el usuario libera/suelta el botn del ratn. Es llamada incluso si el mouse no est al soltar el botn sobre el mismo GUIElement o Collider en que estaba cuando el botn fue presionado. (Para que tuviera ese comportamiento habra que usar OnMouseUpAsButton, que vamos a examinar a continuacin)

OnMouseUpAsButton: function OnMouseUpAsButton () : void Como anticipbamos en la funcin anterior, sta es llamada slo cuando el mouse es liberado estando sobre el mismo GUIElement o Collider en el que fue presionado.

OnMouseDrag: function OnMouseDrag () : void Es llamada esta funcin cuando el usuario presiona el botn del mouse sobre un GUIElement o un Collider y todava lo mantiene presionado. Es llamada cada frame mientras el botn siga presionado.

OnTriggerEnter, OnTriggerExit, OnTriggerStay, OnCollisionEnter, On CollisionExit, OnCollisionStay: Todas estas funciones ya fueron explicadas en la clase Collider, as que a la misma me remito.

OnControllerColliderHit: function OnControllerColliderHit (hit : ControllerColliderHit) : void Es llamada cuando nuestro character controller golpea un collider mientras realiza un movimiento, de tal manera que muchas veces esta funcin sirve para empujar objetos cuando colisionan con el personaje. Hagamos unas modificaciones previas al pertinente ejemplo en la interfaz de Unity. 1. Eliminamos el script vinculado a PortaScripts, para que no nos lance errores. 2. Aadimos un CharacterController al cubo, reemplazando cuando nos lo pida Unity el antiguo boxCollider. 3. Desconectamos provisionalmente el boxCollider del gameobject Suelo, dado que en caso contrario ser el suelo el primer collider con el que se tope nuestra funcin. 4.- Escribimos este script, que le vincularemos al cubo: var miCharCon : CharacterController; miCharCon = GetComponent(CharacterController); function Update() { miCharCon.Move(Vector3(1 * Time.deltaTime ,0,0)); } function OnControllerColliderHit(teToco) { teToco.rigidbody.AddForce(Vector3(0,0,50)); } Play. Nuestro character controller (tambin conocido como cubo) avanza hacia la izquierda a razn de un metro por segundo, y cuando se topa con un controller (la esfera), algunos datos de la colisin y sus intervinientes son pasador al nico parmetro de la funcin, que es de la clase ControllerColliderHit. La clase ControllerColliderHit, aunque la veremos ms en profundidad en otra leccin, cuenta con una serie de variables, entre las que destacan: controller collider rigidbody gameObject Transform point normal moveDirection moveLength El character controller que golpea el collider (nuestro cubo en el ejemplo) El collider que es golpeado por el character controller (la esfera, aqu) El rigidbody que ha sido golpeado por el character controller, si es que el collider que golpeamos tiene rigidbody (en el ejemplo lo usamos porque la esfera tiene rigidbody). El game object que ha sido golpeado por el character controller. El transform que ha sido golpeado por el controller. El punto de impacto en coordenadas globales. El normal de la superficie que ha sido colisionado en coordenadas globales. Aproximadamente la direccin desde el centro de la cpsula del character controller al punto que tocamos. La distancia que el character controller ha recorrido hasta golpear con el collider.

Entonces, volviendo al ejemplo, a travs del parmetro de tipo ControllerColliderHit que hemos dado en llamar teToco, accedemos a la variable rigidbody, que obviamente se corresponde con el rigidbody de la esfera, y a partir de ah le asignamos un comportamiento, que en este caso es meramente desplazarse en el eje Z.

OnJointBreak: function OnJointBreak (breakForce : float) : void

Esta funcin ya la explicamos en la leccin correspondiente a la clase Joint.

OnParticleCollision: function OnParticleCollision (other : GameObject) : void Esta funcin es llamada cuando una partcula choca con un collider. Puede por tanto usarse para computar el dao recibido por un gameobject cuando choca con partculas. Este mensaje es enviado a todos los scripts vinculados con el WorldParticleCollider y al collider que fue colisionado. El mensaje es slo enviado si habilitamos SendCollisionMessage en el inspector del WroldParticleCollider. Quedmonos de momento con esta sucinta informacin, que ya trabajaremos cuando nos toque lidiar con la clase ParticleEmitter.

OnBecameVisible: function OnBecameVisible () : void Se llama a esta funcin cuando el renderer se convierte en visible por alguna cmara. Este mensaje se enva a todos los scripts relacionados con el renderer. Esta funcin y su opuesta OnBecameInvisible- son tiles para evitar cmputos que son slo necesarios cuando el objeto es visible.

OnBecameInvisible: function OnBecameInvisible () : void Es llamada cuando el renderer ya no es visible por ninguna cmara.

OnLevelWasLoaded: function OnLevelWasLoaded (level : int) : void Esta funcin es llamada despus de que un nuevo level ha sido cargado. El parmetro level de la funcin es el level que ha sido cargado. Si quiere ver el ndice de levels de su juego, use el men File=>Build settings.

OnEnable: function OnEnable () : void Es llamada cuando el objeto pasa a estar habilitado y activo.

OnDisable: function OnDisable () : void Es llamada cuando el objeto se convierte en deshabilitado o inactivo. Tambin cuando el objeto es destruido y puede ser usada la funcin para procesos de limpieza. Cuando los scripts son recargados despus de que la compilacin haya acabado, OnDisable se llamar seguida por OnEnable despus de que el script haya sido cargado.

OnDestroy: function OnDestroy () : void Es llamada cuando el MonoBehaviour (script) es destruido. Slo puede ser llamada para gameobjects que previamente hayan estado activos.

OnPreCull: function OnPreCull () : void Es llamada antes de que la cmara deseche la escena. Culling es un proceso que determina qu objetos son visibles en la cmara, y OnPreCull es llamada justo antes de dicho proceso. Esta function es llamada slo si el script est vinculado con la cmara y est activado. Si queremos cambiar los parmetros de visin de la cmara (tal como fieldOfView) lo tendremos que hacer aqu. La visibilidad de los objetos de la escena se determinar en base a los parmetros de la cmara despus de la funcin OnPreCull.

OnPreRender: function OnPreRender () : void Es llamada antes de que la cmara empiece a renderizar la escena. Slo se llama si el script est vinculado a la cmara y activo. Es importante comprender que si cambiamos con esta funcin los parmetros de visin de la cmara, como por ejemplo fieldOfView, slo tendrn efecto el siguiente frame, por lo que hay que hacerlo mejor en la funcin OnPreCull, como hemos dicho antes.

OnPostRender: function OnPostRender () : void Es llamada despus de que la cmara acaba de renderizar la escena, siempre que el script est vinculado con la cmara y activo.

OnRenderObject: function OnRenderObject () : void Es llamada despus de que la cmara renderiza la escena. Se diferencia de OnPostRender en que OnRenderObject es llamada para cada objeto que tenga un script con la funcin, sin importar si est vinculado a una cmara o no.

OnWillRenderObject: function OnWillRenderObject () : void Esta funcin es llamada una vez por cada cmara si el objeto es visible. Es llamada durante el proceso de culling (que podramos traducir por eleccin o desechamiento), justo antes de renderizar todos los objetos seleccionados. Podra usarse por tanto esta funcin para crear texturas que pudieran actualizarse slo si el objeto a renderizar es en realidad visible.

OnGUI: function OnGUI () : void Es llamada para renderizar y manejar eventos GUI. Esto significa que nuestra implementacin de OnGUI podra ser llamada varias veces por frame, a razn de una llamada por evento. Esto lo trabajaremos ms cuando estudiemos las clases Event y GUI.

OnRenderImage: function OnRenderImage (source : RenderTexture, destination : RenderTexture) : void Es llamada cuando se tiene toda la informacin de renderizado de una imagen, permitiendo modificar la imagen final procesndola con filtros. La imagen entrante (source) es de tipo renderTexture y el resultado lo almacenamos en otro parmetro del mismo tipo (destination en el prototipo de la funcin). Cuando hay mltiples filtros de imagen vinculados a la cmara, estos procesan la imagen secuencialmente, pasando el primer filter destination como source del siguiente filtro. Este mensaje ser enviado a todos los scripts vinculados a la cmara.

OnDrawGizmosSelected: function OnDrawGizmosSelected () : void Implementa esta function si quieres dibujar gizmos slo si el objeto est seleccionado. Vamos a verlo con un ejemplo simple. Es necesario para ver el efecto que previo a darle al play el cubo no est seleccionado. function OnDrawGizmosSelected () { Gizmos.color = Color.white; Gizmos.DrawCube (transform.position, Vector3 (2,2,2)); } No nos fijemos demasiado en los elementos de la clase Gizmos, que ya veremos en su momento. De momento slo necesitamos saber que, cuando se seleccione el cubo -bien en la jerarqua, bien en la escena, bien con el juego activado o incluso sin que el juego est activado- nos aparecer un gizmo que se corresponder a un cubo blanco de 2 unidades de lado. Probmoslo.

OnDrawGizmos: function OnDrawGizmos () : void Implementa esta funcin si quieres dibujar gizmos que aparezcan siempre dibujados. Esto te permite rpidamente seleccionar objetos importantes en tu escena, por ejemplo. Notad que esta funcin usa una posicin del ratn que es relativa a la vista de la escena.

Para mostrar esto en un ejemplo necesitamos unos pasos previos: 1. Buscad por la red la imagen de una bombilla (no demasiado grande). 2. La guardis y le asignis el nombre "Bombilla" (Fijaros en la extensin de la imagen. Si es distinta de la que voy a utilizar yo, cambiadla en el script) 3. Buscis la carpeta de nuestro proyecto Unity, y arrastris la imagen dentro de la carpeta assets. 4. En la interfaz, hacemos click derecho sobre Proyecto =>Create =>Folder. Llamamos a la nueva carpeta Gizmos (es donde por defecto buscar Unity) 5. En Proyecto, arrastramos la imagen dentro de esta carpeta. 6. Doble click sobre MiPrimerScript. Tecleamos:

function Update(){ transform.Translate(-Vector3.right * Time.deltaTime); } function OnDrawGizmos() { Gizmos.DrawIcon (transform.position + Vector3(0,5,0) , "Bombilla.jpeg"); } Si hemos seguido correctamente estos pasos, cubo e imagen deberan desplazarse al unsono hacia la izquierda, tal que as:

OnApplicationPause: function OnApplicationPause (pause : boolean) : void Es enviada a todos los gameobjects cuando el jugador presiona la pausa.

OnApplicationFocus: function OnApplicationFocus (focus : boolean) : void Funcin enviada a todos los gameobjects cuando el jugador obtiene o pierde el foco.

OnApplicationQuit: function OnApplicationQuit () : void Funcin que se enva a todos los gameobjects antes de que la aplicacin se cierre. En el editor es llamada cuando el usuario detiene el play, en la web es llamada cuando la pgina se cierra.

OnPlayerConnected: function OnPlayerConnected (player : NetworkPlayer) : void Es llamada en el servidor cada vez que un nuevo jugador se conecta con xito. Esta funcin y las que relacionaremos a continuacin las trataremos en profundidad la funcin Network y familia.

OnServerInitialized: function OnServerInitialized () : void Llamada en el server cada vez que Network.InitializeServer es invocada y completada.

OnConnectedToServer: function OnConnectedToServer () : void Es llamada esta funcin en el cliente cuando consigues conectarte con xito al servidor.

OnPlayerDisconnected: function OnPlayerDisconnected (player : NetworkPlayer) : void Llamada en el server cada vez que un jugador se desconecta del server.

OnDisconnectedFromServer: function OnDisconnectedFromServer (mode : NetworkDisconnection) : void Llamada en el cliente cuando la conexin se pierde o desconectas del servidor.

OnFailedToConnect: function OnFailedToConnect (error : NetworkConnectionError) : void Llamada en el cliente cuando un intento de conexin falla por alguna razn. La razn por la que falla es pasada como una enumeracin de tipo Network.ConnectionError.

OnFailedToConnectToMasterServer: function OnFailedToConnectToMasterServer (error : NetworkConnectionError) : void Llamada en clientes o servidores cuando hay un problema conectando con el MasterServer. La razn del error es pasada como una enumeracin de tipo Network.ConnectionError.

OnMasterServerEvent: function OnMasterServerEvent (msEvent : MasterServerEvent) : void Llamada en clientes o servidores cuando informan de eventos desde el MasterServer, como por ejemplo que haya tenido xito el registro en el host.

El tipo MasterServerEvent es una enum con los siguientes valores: RegistrationFailedGameName: RegistrationFailedGameType: RegistrationFailedNoServer: RegistrationSucceeded: HostListReceived: El registro fall porque se indic un nombre de juego vaco. El registro fall porque se indic un tipo vaco de juego. El registro fall porque ningn servidor est funcionando. El registro al servidor maestro tuvo xito, y se recibi confirmacin. Recibida una lista de hosts desde el master server.

OnNetworkInstantiate: Function OnNetworkInstantiate (info : NetworkMessageInfo) : void Llamada en objetos que han sido instanciados en red con Network.Instantiate. Esto es til para deshabilitar o habilitar componentes de objetos los cuales han sido instanciados y su comportamiento depende de si ellos son de propiedad local o remota.

OnSerializeNetworkView: function OnSerializeNetworkView (stream : BitStream, info : NetworkMessageInfo) : void Usada para personalizar la sincronizacin de variables en un script controlado por una network view. Esto es automticamente determinado si las variables que han sido serializadas deben ser enviadas o recibidas.

16. CLASE CAMERA

Bienvenid@s a otra de las clases importantes de Unity. La clase cmera le permite al jugador interactuar con tu juego. La cmara en Unity es un dispositivo a travs del cual el jugador ve el mundo. Hemos de diferenciar desde el primer momento, y ah residen no pocas confusiones de los recin llegados a Unity, entre pantalla y cmara. Ambas son cosas diferentes y tienen una unidad de medida distinta: La unidad de medida de la pantalla est definida en pxeles. La esquina izquierda-inferior de la pantalla es (0,0), la derecha-superior est contenida en las variables (pixelWidth,pixelHeight), que representan la anchura y altura de la pantalla respectivamente. La posicin Z estara en unidades globales contadas desde la cmara. Si la unidad de medida es relativa a la cmara, la esquina izquierda-inferior de la cmara es (0,0) y la derecha-superior (1,1). La posicin Z estara en unidades globales desde la cmara. Con esto en mente, empecemos:

VARIABLES: fieldOfView: var fieldOfView : float Variable que contiene el campo de visin de la cmara en grados. Se referira al campo de visin vertical, ya que el horizontal vara dependiendo del viewports aspect ratio. El campo de visin es ignorado cuando la cmara est en modo ortogrfico. Antes de empezar con los ejemplos, vamos a retocar un par de cosillas en la interfaz de Unity. En primer lugar, en Proyecto le damos al botn derecho del ratn sobre la carpeta Gizmos=>Delete, para deshacernos de la bombilla. Nos aseguramos de que el cubo est en posicin -2,0,0. Eliminamos el script vinculado al cubo. Nos aseguramos de que la cmara no est en modo ortogrfico, sino en perspectiva. Doble click en MiPrimer Script:

Camera.main.fieldOfView = 20; Arrastramos el script a PortaScripts en la Jerarqua. Notemos antes que nada que en el script nos estamos refiriendo a la cmara principal. Si quisiramos que el script afectara a otra cmara distinta, por un lado deberamos quitarle el "main" del script y por otro lo tendramos que arrastrar a la cmara que queremos afectar por ste. Vamos a probarlo, para que no haya dudas, pero antes dadle al play y comprobar cmo el campo de visin, que por defecto es 60, pasa a ser 20 y -aunque parezca al principio poco intuitivo- al tener un ngulo menor de visin, dicho campo reducido es ampliado para que ocupe toda la pantalla. Esto a muchos les recordar las fotos en las bodas: cuanta ms gente queremos abarcar (ms campo de visin) ms lejos tenemos que tirar la foto. Pero habamos prometido que aplicaramos el ejemplo a una cmara no principal, as que ah vamos. Gameobject=>Create other=>Camera. Llamamos a la Camera "Camara 2". Ahora la ubicaremos en la siguiente posicin/rotacin: Posicion: -0.6,15,1 Rotacion: 85,0,0 Con la cmara 2 seleccionada, le damos al play y observamos nuestro pequeo mundo desde otra perspectiva. Nos daremos cuenta de que Unity nos lanza un mensaje, avisndonos de que tenemos dos receptores (listeners) de audio en la escena. Esto es porque por defecto cada cmara tiene un Audio Listener para recoger el sonido adems de la imagen. Para evitar problemas, eliminamos el AudioListener de la cmara 2 en el inspector. Vale, y ahora montemos otro miniscript para la segunda cmara. Hacemos doble click en MiSegundoScript (ya que el primero lo tenemos ocupado) y tecleamos: camera.fieldOfView = 20; Arrastramos este script a la Camara 2 (si lo arrastrramos al PortaScripts no funcionara, ya que no sabra a qu cmara ha de afectar, salvo que creramos una variable "expuesta" de tipo Camera a la que arrastrar esta y etc, etc, aunque para lo que queremos hacer es ms cmodo el mtodo primero) Le damos al play y observaremos que funciona. Aprovecho para comentaros una cosilla que seguro que la mayora ya sabe. Cada cmara al ser creada tiene una variable (depth, que luego veremos) que establece la prioridad de cada una. Cuanto ms alto el valor de depth, ms prioridad tiene la cmara. Si os fijis en el inspector, la cmara principal debera tener la variable depth en -1, y camara 2 en 0. Es por ello que cuando le damos al play, la vista que nos aparece es la que recoge la cmara 2. Si quisiramos retomar a vista grabada por la cmara principal, no tendramos ms que darle un valor a depth superior al del resto de cmaras.

nearClipPlane: var nearClipPlane : float El plano de recorte de cerca. Cualquier cosa que se halle ms cerca de la cmara de la distancia establecida en esta variable no se mostrar en la cmara. Vemoslo con un ejemplo un poco extremo. Si a MiSegundoScript lo dejamos como sigue... camera.nearClipPlane = 13; ... observaremos que todo lo que se halle a menos de 13 metros de la cmara ser recortado.

farClipPlane: var farClipPlane : float El plano de recorte de lejos. Cualquier cosa que se halle ms lejos de la cmara de la distancia establecida en esta variable no se mostrar en la cmara. Probad cambiar en nuestro ejemplo el "near" por el "far", para obtener una especie de negativo de la toma anterior.

renderingPath: var renderingPath : RenderingPath Indica el tipo de renderizado de entre los que contempla la enum RenderingPath (UsePlayerSettings, VertexLit, Forward y DeferredLighting). Desde el inspector, con la cmara en uso seleccionada, podemos intercambiar entre las cuatro posibilidades para captar sus matices.

actualRenderingPath: var actualRenderingPath : RenderingPath Variable de slo lectura que contiene el rendering path que se est usando.

orthographicSize: var orthographicSize : float El campo de visin de la cmara cuando est en modo ortogrfico. En el prximo ejemplo colocamos a la camara 2 primero en modo ortogrfico, y le fijamos luego un tamao de 3, de tal forma que al tener poco campo de visin ample los objetos enfocados. camera.orthographic = true; camera.orthographicSize = 3; Podramos hacer lo mismo con la cmara principal modificando MiPrimerScript y aadiendo "Main". Recordemos que con la cmara principal no es preciso que el script se incluya en el gameobject mainCamera. Camera.main.orthographic = true; Camera.main.orthographicSize = 3;

orthographic: var orthographic : boolean Variable de tipo booleano que indica si la cmara est en modo ortogrfico (true) o en perspectiva (false) y que permite pasar de uno a otro. Como ya hemos visto, cuando esta variable esta en true, el campo de visin de la cmara se define por orthographicSize, y cuando est en false por fieldOfView.

depth: Var depth : float La profundidad de la cmara en el orden de renderizado de las cmaras. Las cmaras con profundidad ms baja son renderizadas antes de las cmaras con profundidad ms alta. Si tienes varias cmaras, usa este control para decidir el orden en el que las cmaras mostrarn la escena si algunas de ellas no cubren la totalidad de la pantalla.

aspect: var aspect : float Variable en la que se guarda/coloca la proporcin de aspecto (aspect ratio), que es el nombre con que se conoce a la anchura dividida por la altura de la cmara. Por defecto, el aspect ratio es calculado automticamente tomando como base la el aspect ratio de la pantalla. Esto es as incluso si la cmara no est renderizando el rea entera. Si modificas el aspect ratio de la cmara, el valor permanecer hasta que llames a la funcin camera.ResetAspect().

cullingMask: var cullingMask : int Es usada para renderizar de manera selectiva partes de la escena. Si el layerMask del gameobject (que veremos a no mucho tardar) y el cullingMask de la cmara son cero, entonces el game object ser invisible para esa cmara. El layerMask es parecido al sistema de capas de Blender, que brinda la posibilidad de arrastrar objetos a una capa diferente. Con esto se consigue, por ejemplo, que objetos pertenecientes a una fase un poco ms avanzada del juego no sean mostrados hasta que permitamos a la cmara renderizar los relativos a esa capa.

backgroundColor: var backgroundColor : Color Variable que indica el color con el cual la pantalla ser completada.

rect: var rect : Rect Establece qu parte de la pantalla esta la cmara renderizando. Dicha parte de la pantalla es fijada a travs de una instancia de la estructura Rect, en coordenadas normalizadas. Por coordenadas normalizadas nos referimos a que los valores en el rango del rect irn de 0,0 (izquierda,abajo) a 1,1 (derecha,arriba) As, si queremos que la cmara a la que vinculamos el script renderice toda la pantalla, meramente haremos lo siguiente. Editamos MiSegundoScript (que es el que tenemos vinculado a Camara 2) y escribimos: camera.rect = Rect (0, 0, 1, 1); Tratndose de coordenadas normalizadas, lo que estamos pidindole aqu a Unity es que lo que est captando la cmara 2 se nos vea en el rectngulo que le pasamos a la variable rect, y que en este caso ocupa toda la pantalla (de 0,0 a 1,1)

Si queremos que lo que capta la cmara dos se nos vea en la esquina superior derecha de la pantalla, calcularamos estas coordenadas: 0,5: Corresponde al eje horizontal del primer punto, donde 0 sera izquierda y 1 derecha. 0,5: Corresponde al eje vertical del primer punto, donde 0 sera abajo y 1 arriba. El primer punto de nuestro rectngulo, pues, estara justo en el centro de la pantalla. 1: Corresponde al eje horizontal del segundo punto. 1: Y este es el eje vertical del segundo punto. El segundo punto del rectntulo, por lo tanto, est justo en el vrtice derecho superior. As que podemos rectificar el script anterior, de la manera indicada: camera.rect = Rect (0.5, 0.5, 1, 1); De esta manera, lo que est grabando cmara dos queda relegado al recuadro superior derecho y, para el resto de la pantalla, entra en accin la cmara principal, que ya vimos que por profundidad (depth) es la siguiente en la lista de prioridad. Debera quedar algo parecido a esto:

Pero, qu sucedera si no hubiera ninguna cmara ms?. Probmoslo. Seleccionamos Main Camera y en el inspector desmarcamos el check box que aparece junto al componente camera. Volvemos a darle al play, y observaremos que la parte de pantalla no incluida en el rectngulo aparece en negro, tal como se muestra a continuacin:

pixelRect: var pixelRect : Rect Indica/establece qu parte de la pantalla esta la cmara renderizando, pero a diferencia de rect, no lo indica en coordenadas normalizadas, sino en pxeles. Por lo tanto, este script sera el equivalente al anterior: camera.pixelRect = Rect (Screen.width/2, Screen.height/2, Screen.width, Screen.height);

pixelWidth: var pixelWidth : float Indica la anchura de la cmara en pxeles. (Slo lectura).

pixelHeight: var pixelHeight : float Y esta variable indica la altura de la cmara en pxeles(slo lectura)

velocity: var velocity : Vector3 Variable de slo lectura que indica la velocidad de la cmara en el espacio global.

clearFlags: var clearFlags : CameraClearFlags Indica cmo la cmara completa el background. Admite los valores CameraClearFlags.Skybox (rellena el bacground con el skybox habilitado), CameraClearFlags.SolidColor (con el color que le indiquemos), CameraClearFlags.Depth (que mantiene el color que tuviera el background el frame anterior o en cualquier estado previo)o CameraClearFlags.Nothing (no se renderiza background alguno).

FUNCIONES:

ResetAspect: function ResetAspect () : void Revierte el aspect ratio de la cmara al aspect ratio de la pantalla, acabando con el efecto de modificar la variable aspect. Lo veremos mejor con un ejemplo (por cierto, si al trmino del ejemplo anterior no lo hicsteis, aprovechad ahora para volver a marcar el checkbox del componente Camera de Main camera) Editamos MiSegundoScript para que luzca como sigue: camera.aspect = 2; yield WaitForSeconds (5); camera.ResetAspect(); Lo que estamos haciendo es lo siguiente: primero establecemos la variable aspect en 2. Recordemos que aspect es la anchura de la cmara dividida por la altura, esto es, en este caso la cmara ser el doble de ancha que alta (y en consonancia lo grabado ser el doble de estrecho de lo normal). Para ver la diferencia, intercalamos una instruccin yield que -como ya sabemos- suspende la ejecucin de cualquier otra instruccin (en este caso durante cinco segundos) y acto seguido reseteamos el aspect de la cmara para devolverlo a sus parmetros normales.

WorldToScreenPoint: function WorldToScreenPoint (position : Vector3) : Vector3 Transforma la posicin de un transform desde el espacio global al espacio de la pantalla. Recordemos que el espacio de la pantalla est definido en pxeles (izquierda-abajo es (0,0) y derecha-arriba es (pixelWidth,pixelHeight). La posicin z se calcula en unidades globales desde la cmara. Un ejemplo. Editamos MiSegundoScript tecleando esto: var eseQueTuVesAhi : Transform; var posicionGlobal : String; var posicionEnPixeles : String; posicionGlobal = eseQueTuVesAhi.position.ToString(); posicionEnPixeles = Camera.WorldToScreenPoint(eseQueTuVesAhi.position).ToString(); Debug.Log("La posicion global es " + posicionGlobal + " y la posicion en pixeles " + posicionEnPixeles);

Guardamos y arrastramos desde la Jerarqua nuestro Cubo hasta la variable expuesta eseQueTuVesAhi. El script devuelve primero la posicin global del cubo en la escena, en un string generado por la funcin ToString. Acto seguido convertimos ese vector3 que contiene las coordenadas globales en otro Vector3 que contiene la ubicacin en pxeles del transform del cubo respecto de la pantalla. Al devolver un Vector3, podemos tambin aprovechar la funcin ToString para convertir dichas coordenadas en un String e imprimirlas. Recordemos que el tercer parmetro del Vector3 con la ubicacin en pxeles viene referido (eje Z) a la distancia en unidades globales (metros) entre la cmara y el transform.

WorldToViewportPoint: function WorldToViewportPoint (position : Vector3) : Vector3 Convierte la posicin de un transform desde las coordenadas globales al espacio de punto de vista (viewport space en ingls). El viewport space es el relativo a la cmara, donde izquierda-abajo es (0,0) y derecha-arriba (1,1). La posicin z se medira en unidades globales desde la cmara. Lo vemos con ms claridad modificando ligeramente el script anterior: var eseQueTuVesAhi : Transform; var posicionGlobal : String; var posicionEnEspacioCamara : String; posicionGlobal = eseQueTuVesAhi.position.ToString(); posicionEnEspacioCamara = camera.WorldToViewportPoint(eseQueTuVesAhi.position).ToString(); Debug.Log("La posicion global es " + posicionGlobal + " y la posicion en espacio normalizado de camara " +posicionEnEspacioCamara); Como vemos al darle al play, ahora se nos muestra en coordenadas relativas a la cmara la ubicacin del transform del cubo. Contina inalterada, eso s, la distancia respecto del eje Z (profundidad), que ya dijimos que va medido en unidades globales respecto de la posicin de la cmara.

ViewportToWorldPoint: function ViewportToWorldPoint (position : Vector3) : Vector3 Es la funcin inversa a WorldToViewportPoint, que estudiamos en la leccin anterior. Convierte por tanto la posicin de un transform medida en el viewport space relativo de la cmara (0,0 a 1,1) a coordenadas globales. Se suministra a la funcin un vector donde los componentes X e Y son las coordenadas de pantalla, y el componente Z es la distancia del plano resultante desde la cmara en unidades globales, y la funcin los transforma en coordenadas globales. As, podemos adaptar el ejemplo que nos propone el manual de referencia y dibujar una esfera amarilla en la esquina superior derecha de la pantalla, y traducir dichas coordenadas de ubicacin a las generales de la escena. function OnDrawGizmos () { var deLaCamaraAlMundo : Vector3 = camera.ViewportToWorldPoint (Vector3 (1,1,0.5)); Gizmos.color = Color.yellow; Gizmos.DrawSphere (deLaCamaraAlMundo, 0.1); }

Le hemos dado una profundidad a la ubicacin de la esfera de 0.5. Hemos de tener presente que esta distancia no debe ser inferior a la que est establecida en nearClipPlane, o no se ver.

ScreenToWorldPoint: function ScreenToWorldPoint (position : Vector3) : Vector3 Convierte la posicin de un transform desde el espacio de pantalla en pxeles (0,0 a pixelWidth,pixelHeight) a coordenadas globales, con la posicin z (como en el resto de casos) medida en unidades globales desde la cmara.

ScreenToViewportPoint: function ScreenToViewportPoint (position : Vector3) : Vector3 Convierte la posicin de un transform de espacio de pantalla en pxeles (0,0 a pixelWidth,pixelHeight) a viewport space relativo al espacio de cmara (0,0 a 1,1).

ViewportToScreenPoint: function ViewportToScreenPoint (position : Vector3) : Vector3 Convierte la posicin del transform de viewport space relativo al espacio de cmara (0,0 a 1,1) en espacio de pantalla en pxeles (0,0 a pixelWidth,pixelHeight). La posicin z en ambos tipo de medida es la misma, medida en unidades globales desde la cmara.

ViewportPointToRay: function ViewportPointToRay (position : Vector3) : Ray Devuelve un rayo que sale de la cmara en coordenadas relativas a sta (0,0 a 1,1). El rayo comienza en el plano ms cercano a la cmara, razn por la que la posicin Z es ignorada.

ScreenPointToRay: function ScreenPointToRay (position : Vector3) : Ray Devuelve un rayo que va de la cmara a travs de un punto de la pantalla. Estando el rayo en las coordenadas globales, empieza en el plano cercano a la cmara y va a travs de la posicin x e y en las coordenadas de pxeles (0,0 a pixelWidth,pixelHeight) en la pantalla (la posicin z es ignorada).

Render: function Render () : void Renderiza la cmara manualmente, usando el clear flags de la cmara, target texture y otras propiedades. La cmara puede enviar mensajes como OnPreCull, OnPreRender o OnPostRender a cualquier script que est vinculado, y renderizar algunos filtros de imagen.

Esto es usado para tener control preciso sobre el orden de renderizado. Para hacer uso de esta caracterstica, crea una cmara y deshabilitala, y entonces llama a la funcin Render para ella.

RenderWithShader: function RenderWithShader (shader : Shader, replacementTag : String) : void Hace que la cmara renderice con reemplazo de sombreado (shader) . Esto renderizar la cmara, usando los clear flags de la cmara, target texture y otras propiedades. A direrencia de la funcin anterior, la cmara no enviar OnPreCull, OnPreRender or OnPostRender a scripts vinculados. Los filtros de la imagen tampoco sern renderizados. Esto es usado para efectos especiales, como por ejemplo renderizar una visin de calor y cosas as. Para usar estas caractersticas, habitualmente crears una cmara y la deshabilitars y luego llamars RenderWithShader en ella.

SetReplacementShader: function SetReplacementShader (shader : Shader, replacementTag : String) : void Hace que la cmara renderice con shader replacement. Despus de llamar a esta funcin, la cmara renderizar su vista con shader replacement. Para volver al renderizado normal hay que llamar a ResetReplacementShader.

ResetReplacementShader: function ResetReplacementShader () : void Borra el shader replacement de la cmara provocado por la funcin anterior.

RenderToCubemap: function RenderToCubemap (cubemap : Cubemap, faceMask : int = 63) : boolean Renderiza un cubemap desde la cmara que llama a esta funcin. Esto es muy til en el editor para bakear cubemaps estticos de tu escena. La posicin de la cmara, clear flags y clipping plane distances son usados para renderizar dentro de las caras de un cubemap. faceMask es un mapa de bits que indica qu cara del cubemap debe ser renderizada. Cada bit se corresponde a una cara y est representado por un int dentro de una enum de tipo cubemapface. Por defecto las seis caras del cube map se renderizarn, que es lo que viene representado en la firma por el 63, que corresponde a lo que ocupan los bits de las seis caras. La funcin devuelve false si el renderizado del cubemap falla. Esta funcin tiene un segundo prototipo: function RenderToCubemap (cubemap : RenderTexture, faceMask : int = 63) : boolean Esta segunda modalidad es usada para reflexiones en tiempo real dentro de render textures de cubemap. Puede ser bastante caro en trminos de rendimiento, eso s, especialmente si las seiz caras del cubemap son renderizadas cada frame.

CopyFrom: function CopyFrom (other : Camera) : void Permite copiar para una cmara todas las variables de otra cmara (campo de vision, clear flags, culling mask) Puede ser til si queremos que una cmara coincida con la configuracin de otra, para conseguir efectos personalizados de rendering, como por ejemplo los objetidos usando RenderWithShader.

VARIABLES DE CLASE: main: static var main : Camera Se refiere a la cmara que est habilitada y con el tag Main Camera(Read On ly). Devuelve nulo si no hay una cmara con esas caractersticas en la escena.

allCameras: static var allCameras : Camera[] Devuelve todas las cmaras habilitadas en la escena.

17. CLASE LIGHT

Esta clase se usa para controlar todos los aspectos de las luces en Unity. Las propiedades que aqu veremos son exactamente las mismas que los valores que podemos encontrarnos en el inspector. Normalmente las luces son creadas en el editor, pero a veces puede ser que queramos crear o manipular una luz desde un script. Podemos, para tener una primera idea de lo que podemos hacer con esta clase, aplicar el ejemplo que nos viene en el manual de referencia. Antes de nada, modifiquemos el escenario para los ejemplos que vendrn: 1.- Eliminamos en Jerarqua Camara 2. 2.- Eliminamos el script vinculado a PortaScripts. Doble click en MiPrimerScript. Tecleamos: function Start () { var unaNuevaLuz : GameObject = new GameObject("La luz"); unaNuevaLuz.AddComponent(Light); unaNuevaLuz.light.color = Color.blue; unaNuevaLuz.transform.position = Vector3(0, 5, 0); } Salvamos y arrastramos el script a PortaScripts. Pulsamos play. Debera aparecer una nueva luz en la escena, tal que as:

La dinmica del script es sencilla: Creamos primero un gameobject (que sera el equivalente a crear en el men de la interface de Unity un gameobject vaco. A dicho gameobject vaco (que damos en llamar "la luz")le aadimos un componente de tipo luz (por defecto se crea una luz de tipo Point). Le damos por ltimo a esa luz recin creada un color y una ubicacin en la escena.

VARIABLES: type: var type : LightType El tipo de luz. Puede ser LightType.Spot LightType.Directional LightType.Point Consiste en una luz tipo tipo foco. Una luz direccional, parecida a la del sol. Un punto de luz.

Para mostrar la diferencia entre las tres, he apagado la luz principal de la escena deshabilitando su checkbox, y he rediseado el script anterior, y a su vez he hecho las pertinentes probaturas con los tres tipos de luz. function Start () { var unaNuevaLuz : GameObject = new GameObject("La luz"); unaNuevaLuz.AddComponent(Light); unaNuevaLuz.transform.position = Vector3(0, 3, 0); unaNuevaLuz.light.type = LightType.Spot; } Aqu os dejo las capturas de pantalla de este script con los tres tipos de luz.

Primero con luz tipo Spot:

Luz directional:

Y luz tipo point:

color: var color : Color El color de la luz. Para modificar la intensidad de la luz podemos cambiar el color de la luz. Por ejemplo, una luz de color negro es lo mismo que no tener ninguna luz.

intensity: var intensity : float La intensidad de la luz es multiplicada con el color de la luz. El valor puede estar entre 0 y 8. Esto nos permite crear luces muy brillantes. Realicemos un pequeo ejemplo. Previamente eliminamos el script vinculado a PortaScripts y volvemos a habilitar (si lo habamos desmarcado) el checkbox de nuestra luz principal. Doble click en MiPrimer Scipt. Tecleamos: function Update(){ var opaco : float = 0.0; var brillante : float = 8.0; light.color = Color.green; light.intensity = Random.Range(opaco, brillante); } Guardamos y vinculamos el script a nuestra Luz. Al darle al play deberamos asistir a una escena iluminada por una parpadeante luz de nen. Meramente lo que hemos hecho es utilizar una funcin de la clase Random (de prximo estudio)de nombre Range, que genera un nmero aleatorio entre un mximo y un mnimo. Dado que la intensidad de la luz va de 0 a 8, le damos ese amplio margen de actuacin a Random.Range para que cada frame vare la intensidad de la luz de manera aleatoria entre 0 y 8. Ello, unido al color verde tpicamente apocalptico, nos da este bonito efecto.

shadows: var shadows : LightShadows Indica cmo proyecta sombras la luz. Esta variable es de tipo LightShadows, que es una enumeracin que permite los siguientes valores: None Hard Soft No proyecta sombras (por defecto) Proyecta sombras duras (sin filtro de sombras) Proyecta sombras suaves (con filtro)

Pongamos un ejemplo. Doble click sobre MiPrimerScript. Tecleamos: function Start(){ light.color = Color.yellow; light.intensity = 3.0; light.shadows = LightShadows.Hard; }

Observemos las sombras, y comprenderemos por qu se les denomina como duras:

Y si usamos el valor LightShadows.Soft:

shadowStrenght: var shadowStrength : float Establece/indica la fuerza de las sombras.

shadowBias: var shadowBias : float

Vendra a ser la perpendicular de la sombra respecto del objeto que la emite.

shadowSoftness: var shadowSoftness : float Suavidad de las sombras de las luces direccionales.

shadowSoftnessFade: var shadowSoftnessFade : float Velocidad de fadeout de las sombras de las luces direccionales.

range: var range : float El dimetro del rango o haz de luz, en luces de tipo spot y point.

spotAngle: var spotAngle : float En ngulo en grados de las luces de tipo spotlight. Usado originalmente en luces de tipo spot, altera el tamao del foco de la galleta de luz en luces de tipo direccional. No tiene efectos para luces de tipo point.

cookie: var cookie : Texture Variable de tipo textura que establece la textura de la galleta proyectada por la luz.

flare: var flare : Flare Selecciona un halo para la luz. Este ha de ser previamente asignado en el inspector.

renderMode: var renderMode : LightRenderMode Establece cmo renderizar la luz, de entre las siguientes opciones que la enumeracin LightRenderMode permite: Auto ForcePixel ForceVertex Elige el modo de renderizado automticamente. Fuerza a la luz a ser una luz de pxeles. Fuerza a la luz a ser una luz de vrtices.

cullingMask: var cullingMask : int Es usado para separar luces de la escena de manera selectiva. Si el layerMask del gameobject y el cullingMask de la luz son cero, entonces el objeto no ser iluminado con esta luz.

18. CLASE MATERIAL

Como podis comprobar en el esquema superior, hemos subido dos peldaos en la jerarqua respecto a las ltimas clases que estbamos estudiando, y vamos ahora a aproximarnos a una serie de clases que derivan directamente de la clase base Object. La clase material, tal como es de suponer, accede a todas las propiedades de un material, permitindonos alterarlas/animarlas. Si pretendemos referirnos al material usado por un objeto, es preferible usar la propiedad Renderer.material, tal que as: renderer.material.color = Color.red;

VARIABLES: shader: var shader : Shader Es el shader del material. En modelado 3d, un shader vendra a ser el algoritmo que indica cmo una superficie ha de responder ante la luz. Es una variable de la clase Shader (que estudiaremos en su momento). Nos permite utilizar/crear/importar diferentes reacciones que tendr nuestro objeto al darle la luz (diffuse, transparent, ect) Por ejemplo, podemos comprobar qu tipo de shader tiene nuestra esfera. Para ello, antes que nada, eliminamos el script que tenemos vinculado a la luz (si es que estamos siguiendo las lecciones por orden), y editamos MiPrimerScript tal como sigue: renderer.material.shader = Shader.Find( "Transparent/Diffuse" ); var miShader : String; miShader = renderer.material.shader.ToString(); Debug.Log(miShader);

Como vemos, para obtener el tipo de material referido a un objeto recurrimos a la clase Renderer. Observamos que nuestra esfera tiene el shader por defecto, que es de tipo Difusse. Y si queremos cambiar el tipo de shader y convertirlo en especular, usamos la funcin Find (que estudiaremos en su momento cuando demos la clase Shader) y se la asignamos a nuestra esfera. var miShader : String; renderer.material.shader = Shader.Find( "Specular" ); miShader = renderer.material.shader.ToString(); Debug.Log(miShader);

color: var color : Color El color principal del material. Es lo mismo que -como veremos en breve- usar GetColor o SetColor con el nombre _Color. Aadimos una declaracin a nuestro script para cambiarle el color a la esfera: var miShader : String; renderer.material.shader = Shader.Find( "Specular" ); renderer.material.color = Color.cyan; miShader = renderer.material.shader.ToString(); Debug.Log(miShader);

mainTexture: var mainTexture : Texture La textura principal del material. Es lo mismo que usar GetTexture o SetTexture con el nombre _MainTex. Si por ejemplo escribiramos un script as: var texture : Texture; renderer.material.mainTexture = texture; tendramos una variable "expuesta" donde podramos arrastrar la textura principal que quisiramos que tuviera nuestro material.

mainTextureOffset: var mainTextureOffset : Vector2 Nos permite desplazar la textura principal. Hay un ejemplo muy indicativo en el manual de referencia de Unity, que he modificado ligeramente. Con carcter previo necesitara que os descargrais una textura, a poder ser alguna cuyo movimiento fuera perceptible. Yo por ejemplo voy a utilizar esta: http://www.blogger.com/img/blank.gif

Una vez descargada, la guardamos dentro de la carpeta "assets" de nuestro proyecto en Unity, de tal manera que en Proyecto nos salga. Acto seguido escribimos este script: var miTextura : Texture; renderer.material.mainTexture = miTextura; var scrollSpeed : float = 0.5; function Update() { var offset : float = Time.time * scrollSpeed; renderer.material.mainTextureOffset = Vector2 (offset, 0); } Salvamos y arrastramos la textura hasta la variable expuesta del script miTextura. Le damos al play y observaremos que la textura de nuestra esfera comienza a girar (ojo, si vemos las variables rotate de la esfera observaremos que no es el objeto el que gira, sino la textura la que se desplaza sobre el objeto). Meramente estamos cambiando de sitio a nuestra textura con respecto a nuestro objeto (pensemos en aplicaciones como anuncios de nen en una ciudad futurista).

mainTextureScale: var mainTextureScale : Vector2 La escala de la textura principal.

FUNCIONES: Constructor: static function Material (contents : String) : Material Crea un material temporal a partir de un shader descrito por un string. static function Material (shader : Shader) : Material O bien crea un material temporal directamente desde un shader que le proporcionemos de entre los que tengamos. A grandes rasgos la creacin de un nuevo material sera as: var shader : Shader; var texture : Texture; var color : Color; function Start () { renderer.material = new Material (shader); renderer.material.mainTexture = texture; renderer.material.color = color; } Arrastrndole el shader, material y color, o cuanto menos el primero, creamos un material totalmente nuevo. static function Material (source : Material) : Material Crea un material temporal copiando el shader y todas las propiedades del material que le pasamos como parmetro.

SetColor: function SetColor (propertyName : String, color : Color) : void Nos permite indicar el nombre para un determinado color. Muchos shaders usan ms de un color, por ejemplo: "_Color" "_SpecColor" "_Emission" "_ReflectColor" Es el color principal del material, que es el que puede ser tambin accedido desde la propiedad "color" de la clase. Es el color especular de un material (usado en shaders specular/glossy/vertexlit). Es el color que emite un material (usado en vertexlit shaders). Es el color de reflexin del material (usado en reflective shaders).

En el ejemplo siguiente, sacado del manual de referencia, asignamos el shader glossy (brillante) a nuestra esfera, y establecemos su color especular en rojo: function Start () { renderer.material.shader = Shader.Find ("Glossy"); renderer.material.SetColor ("_SpecColor", Color.red); }

GetColor: function GetColor (propertyName : String) : Color Obtiene el valor de un color con nombre. Por ejemplo: print (renderer.material.GetColor("_SpecColor"));

SetTexture: function SetTexture (propertyName : String, texture : Texture) : void Establece el nombre de una textura. Permite cambiar el propertyName de la textura. Los nombres comunes de las texturas que encontramos ya creadas en Unity son: "_MainTex" "_BumpMap" "_Cube" Es de Es Se la textura difusa principal. Puede ser accedida tambin a travs la propiedad mainTexture. el mapa de normales. refiere al cubemap.

GetTexture: function GetTexture (propertyName : String) : Texture Obtiene el nombre de una textura.

SetTextureOffset: function SetTextureOffset (propertyName : String, offset : Vector2) : void Establece el lugar de desplazamiento de la textura pasada como primer parmetro.

GetTextureOffset: function GetTextureOffset (propertyName : String) : Vector2 Obtiene la ubicacin del desplazamiento de la textura pasada como parmetro.

SetTextureScale: function SetTextureScale (propertyName : String, scale : Vector2) : void Establece la escala de la textura pasada como primer parmetro.

GetTextureScale: function GetTextureScale (propertyName : String) : Vector2 Obtiene la escala de la textura pasada como parmetro.

SetFloat: function SetFloat (propertyName : String, value : float) : void Establece un valor tipo float con nombre.

GetFloat: function GetFloat (propertyName : String) : float Obtiene un valor de tipo float con nombre.

HasProperty: function HasProperty (propertyName : String) : boolean Comprueba si el shader del material tiene una propiedad con un nombre determinado. Por ejemplo: if(renderer.material.HasProperty("_Color")) renderer.material.SetColor("_Color",Color.red);

GetTag: function GetTag (tag : String, searchFallbacks : boolean, defaultValue : String = "") : String Obtiene el valor del tag del shader del material. Si el shader del material no tiene definido el tag, devuelve defaultValue. Si el parmetro searchFallbacks es true, entonces esta funcin buscar el tag en todos los subshaders. Si searchFallbacks es falso entonces slo se har la consulta para el actual subshader.

Lerp: function Lerp (start : Material, end : Material, t : float) : void Interpola propiedades entre dos materiales. Hace que todos los colores y valores del primer material sean convertidos en los valores del segundo material en el tiempo t. Cuanto el tercer parmetro (t) es cero, se toman los valores de start; cuando es 1, los valores se toman de end.

CopyPropertiesFromMaterial: function CopyPropertiesFromMaterial (mat : Material) : void Copia propiedades de otro material en este material.

19. CLASE CUBEMAP

Como vemos, esta clase deriva directamente de Material, que vimos en la leccin pasada. No es quizs la clase que ms vayamos a utilizar, ya que por norma general utilizaremos tal cual los cubemaps con los que contemos, pero tampoco est de ms tener un conocimiento mnimo de la clase. VARIABLES: format: var format : TextureFormat El formato de los datos de los pxeles en la textura. Slo lectura.

FUNCIONES: Cubemap: static function Cubemap (size : int, format : TextureFormat, mipmap : boolean) : Cubemap Crea una nueva textura de cubemap. La textura puede tener tamao en cada lado y con o sin mipmaps.

SetPixel: function SetPixel (face : CubemapFace, x : int, y : int, color : Color) : void Coloca el color del pixel en las coordenadas (face, x, y)

GetPixel: function GetPixel (face : CubemapFace, x : int, y : int) : Color devuelve el color del pixel en las coordenadas (face, x, y)

GetPixels: function GetPixels (face : CubemapFace, miplevel : int = 0) : Color[] Devuelve el color del pixel de una cara del cubemap. Devuelve un array de colores de pxeles de una cara del cubemap.

SetPixels: function SetPixels (colors : Color[], face : CubemapFace, miplevel : int = 0) : void Establece colores de pixeles de una cara del cubemap. Esta funcin toma un array de color y cambia los colores de los pxeles de la cara completa del cubemap.

Apply: function Apply (updateMipmaps : boolean = true) : void Aplica en realidad todos los previos cambios de SetPixel y Setpixels.

20. CLASE RENDERTEXTURE

Al igual que Cubemap, la clase RenderTexture hereda directamente de Material. Hemos de advertir antes que nada que esta clase slo est disponible para Unity Pro, as que quien no tenga o confe en tener la versin de pago de Unity puede saltarse tranquilamente estas lecciones. Render textures son texturas que pueden ser renderizadas. Pueden ser usadas para implementar imgenes basadas en efectos de renderizado, sombras dinmicas, proyectores, reflexiones o cmaras de vigilancia. Como es posible que -como a m en su momento- esa definicin no nos diga nada, vamos a acercarnos por la va de los hechos a las rendertextures. Hemos de seguir los siguientes pasos: 1.- Eliminamos el script vinculado a la esfera. 2.- Al cubo, en scale, le damos los siguientes valores: 5,5,0.1, y en position: -2,2,0. 3.- En el men, nos vamos a Assets=>Create=>Render Texture. 4.- Asimismo en el men, le damos a Gameobject=>Create other=>camera. 5.- A esta nueva cmara le quitamos el componente Audio Listener, para que no nos d problemas de duplicidad. 6.- Con camera seleccionada, en el inspector veremos una variable denominada Target Texture. Arrastramos hasta ah la renderTexture creada antes y que est en Proyecto. 7.- Establecemos las siguientes coordenadas para camera: Position, 2,1,0, Rotation 90,0,0. (nos aseguramos de que la esfera est en 2,0,0.). Deberamos estar viendo en la vista previa de la nueva cmara la esfera muy de cerca. 8.-Arrastramos la Render Texture de Proyecto al cubo. 9.- Pulsamos play. Deberas estar viendo algo como esto:

Por lo tanto, observamos que render textures es un tipo especial de textura que se crea y actualiza en tiempo de ejecucin, y que convierte en textura el fruto del renderizado de una cmara. Para ello observamos que necesitamos crear (en la interfaz o a travs de un script) una nueva render textura y asignarla a una cmara para que la renderice. Acto seguido creamos o designamos una superficie que reciba esa textura as creada. Decimos que se crea y actualiza en tiempo de ejecucin. Para demostrar tal aseveracin, vamos a crear un pequeo script. Doble click en MiPrimerScript: var miTextura : Texture; function Update() { renderer.material.mainTexture = miTextura; transform.Rotate(0,20,0); } Si todava tenemos en Proyecto la textura que nos descargamos hace un par de lecciones, la arrastramos a miTextura. Si no, hacemos lo propio con cualquier textura no uniforme (para que se note el efecto de la rotacin de la esfera) que tengamos a mano. Le damos al play. Pensemos en las enormes posibilidades que nos abre esta clase, que nos permite convertir en textura o plasmar sobre cualquier superficie algo que est siendo grabado en ese momento en otro lugar (esto nos sirve tanto para implementar el contenido de una cmara de seguridad como para elaborar todo tipo de espejos o superficies reflectantes.) VARIABLES: width: var width : int La anchura de la textura renderizada en pxeles. A diferencia de Texture.width, esta variable no es de slo lectura, y permite establecer un valor para cambiar la anchura.

height: var height : int La altura de la textura renderizada en pxeles. Le es de aplicacin lo dicho para width.

depth: var depth : int La precisin en bits de la profundidad del bfer de la render texture (son soportados los valores 0, 16 y 24)

format: var format : RenderTextureFormat El formato de la render texture. RenderTextureFormat es una enumeracin que permite estos valores: RenderTextureFormat es una enum con estos valores: ARGB32 Depth ARGBHalf RGB565 ARGB4444 ARGB1555 Default Formato de color de la render texture, 8 bits por canal. Un formato de profundidad de la render texture. Formato de color de la render texture, 16 bit en punto flotante por canal. Formato de color de la render texture. Formato de color de la render textura, 4 bit por canal. Formato de color de la render texture, 1 bit para el canal Alpha, 5 bits para los canales del rojo, verde y azul. Formato de color por defecto de la render texture, dependiendo del formato de bufer por frame y la plataforma.

useMipMap: var useMipMap : boolean Por defecto, las render textures no tienen mipmaps. Si establecemos esta variable en true, se generarn niveles de mipmap asociados. Este flag puede ser usado slo en render textures que sean potencias de dos.

var isCubemap : boolean var isCubemap : boolean Si est habilitada, esta render texture ser usada como Cubemap.

FUNCIONES: RenderTextures: static function RenderTexture (width : int, height : int, depth : int, format : RenderTextureFormat) : RenderTexture

Crea un nuevo objeto RenderTexture, que es creado con anchura y altura, con un buffer de profundidad y en un determinado formato. Sera lo mismo que hicimos en el ejemplo de la leccin anterior, pero a travs de un script. Cuando invocamos a travs del constructor un nuevo objeto RenderTexture no estamos todava crendolo en realidad . El RenderTexture ser creado o bien la primera vez que se usa o bien llamando de manera expresa a la funcin Create. As que despus de construir la render texture, dado que an no ha tomado forma la representacin final de la misma, es posible establecer variables adicionales, como format, isCubemap y similares. static function RenderTexture (width : int, height : int, depth : int) : RenderTexture Este segundo prototipo del constructor es idntico al anterior, salvo que no se establece de manera expresa el formato de la rendertexture. La render texture es colocada para estar en color format por defecto.

Create: function Create () : boolean Tal como acabamos de indicar, es esta funcin la que crea en realidad la RenderTexture.

Release: function Release () : void Esta funcin libera los recursos de hardware usados por la render texture. La texture en s no es destruida, y ser automticamente creada otra vez cuando se use.

IsCreated: function IsCreated () : boolean Indica si la render texture se ha creado realmente o no.

DiscardContents: function DiscardContents () : void Descarta el contenido de la render texture.

SetGlobalShaderProperty: function SetGlobalShaderProperty (propertyName : String) : void Asigna esta render texture como la propiedad shader global llamada en el parmetro propertyName.

VARIABLES DE CLASE: active: static var active : RenderTexture

Se refiere a la render texture activa. Todos los renderings van dentro de la rendertexture activa. Si esta es null todo se renderiza en la ventana principal. Cuando una RenderTexture se convierte en activa su contexto de hardware de renderizado es automticamente creado si no se haba creado ya.

FUNCIONES DE CLASE: GetTemporary: static function GetTemporary (width : int, height : int, depthBuffer : int = 0, format : RenderTextureFormat = RenderTextureFormat.Default) : RenderTexture Asigna una render texture temporal. Esta funcin es optimizada para cuando necesitas una RenderTexture rpida para hacer algunos clculos temporales. Librala usando ReleaseTemporary tan pronto hayas hecho el trabajo, as podrs reusarla otra vez en una nueva llamada si la necesitas.

ReleaseTemporary: static function ReleaseTemporary (temp : RenderTexture) : void Libera una textura temporal asignada con GetTemporary.

21. CLASE PARTICLEEMITTER

Antes que nada, pediros disculpas porque esa clase se me haba pasado. Como podis ver en el grfico, ParticleEmitter deriva de Component (como Collider, Rigidbody, Transform...) y por lo tanto la debera haber explicado antes, pero bueno, subsanamos el error ahora. Vamos a preparar antes que nada nuestra escena para acoger los nuevos ejemplos de esta clase: 1.- Borramos la cmara que creamos en la clase RenderTexture 2.- Devolvemos el cubo a sus valores previos: position (-2,0,0) scale(1,1,1) 3.- Eliminamos el script vinculado a la esfera. 4.- Eliminamos la render texture en la carpeta Proyecto. 5.- Nos vamos al men Gameobject=>Create other=>Particle System. 6.- Ubicamos nuestro nuevo gameobject en 0,0,0 y lo renombramos como "Particulas". 7.- Salvamos la escena. Deberamos tener ahora una escena parecida a esta:

VARIABLES: emit: var emit : boolean Booleano que indica si deben las partculas ser automticamente emitidas cada frame o no. Podemos usar esta variable para "encender o apagar" la emisin de partculas. Editemos nuestro script de la siguiente manera: yield WaitForSeconds(5); particleEmitter.emit = false; yield WaitForSeconds(5); particleEmitter.emit = true; Observaremos que tras los cinco segundos iniciales, nuestro sistema de partculas comienza a extinguirse hasta desaparecer, y pasados otros cinco, vuelve a encenderse.

minSize: var minSize : float El tamao mnimo que cada partcula puede tener cuando se genera.

maxSize: var maxSize : float El tamao mximo que cada particular puede tener al tiempo de ser generada. Si tenemos el gameobject Particulas seleccionado, podemos comprobar que por defecto el tamao mnimo (y mximo) es 0.1. Veamos qu pasa si alteramos estos valores: particleEmitter.minSize = 0.2; particleEmitter.maxSize = 0.5;

minEnergy: var minEnergy : float El mnimo tiempo de vida de cada particular, medido en segundos.

maxEnergy: var maxEnergy : float El mximo tiempo de vida de cada partcula, medido en segundos.

En el inspector esta variable y la anterior est colocada en 3 por defecto. Aadamos al script anterior unos valores distintos. particleEmitter.minSize = particleEmitter.maxSize = particleEmitter.minEnergy particleEmitter.maxEnergy 0.2; 0.5; = 1; = 5;

Vemos que conseguimos as una mayor variedad en la persistencia de cada partcula, dndole mayor dinamismo a nuestro sistema de partculas.

minEmission: var minEmission : float El mnimo nmero de partculas que sern generadas cada segundo.

maxEmission: var maxEmission : float El mximo nmero de partculas que sern generadas cada segundo. Los valores por defecto en el inspector son 50. Editemos nuestro script para alterarlo. particleEmitter.minSize = 0.2; particleEmitter.maxSize = 0.5; particleEmitter.minEnergy = 1; particleEmitter.maxEnergy = 5; particleEmitter.minEmission = 70; particleEmitter.maxEmission = 110; Tenemos ahora un sistema de partculas ms denso y compacto, como vemos.

emitterVelocityScale: var emitterVelocityScale : float La cantidad de la velocidad de emisin que las partculas heredan. Por defecto 0.05.

worldVelocity: var worldVelocity : Vector3 La velocidad inicial de las partculas en el mundo global, a lo largo de x,y,z.

Incorporemos estas dos ltimas variables a nuestro ejemplo, dndole a nuestro sistema de partculas una mayor velocidad de emisin y haciendo que nuestras partculas se desplacen hacia arriba (en coordenadas globales): particleEmitter.minSize = 0.2; particleEmitter.maxSize = 0.5;

particleEmitter.minEnergy = 1; particleEmitter.maxEnergy = 5; particleEmitter.minEmission = 70; particleEmitter.maxEmission = 110; particleEmitter.emitterVelocityScale = 0.4; particleEmitter.worldVelocity = Vector3(0,3,0);

localVelocity: var localVelocity : Vector3 Es como la anterior, pero el desplazamiento se efecta en las coordenadas locales del propio sistema de partculas.

rndVelocity: var rndVelocity : Vector3 Una velocidad aleatoria con relacin a los ejes x,y,z que es aadida a la velocidad. En nuestro ejemplo: particleEmitter.minSize = 0.2; particleEmitter.maxSize = 0.5; particleEmitter.minEnergy = 1; particleEmitter.maxEnergy = 5; particleEmitter.minEmission = 70; particleEmitter.maxEmission = 110; particleEmitter.emitterVelocityScale = 0.4; particleEmitter.worldVelocity = Vector3(0,3,0); particleEmitter.rndVelocity = Vector3(1,0.5,0.5);

useWorldSpace: var useWorldSpace : boolean Si est habilitado, las partculas no se mueven cuando el emitter se mueve. Si est en false, cuando muevas el emitter, las partculas lo siguen.

rndRotation: var rndRotation : boolean Si est habilitado, las partculas sern generadas con rotaciones aleatorias. Por defecto est en false, as que observemos qu ocurre si lo habilitamos: particleEmitter.minSize = 0.2; particleEmitter.maxSize = 0.5; particleEmitter.minEnergy = 1; particleEmitter.maxEnergy = 5; particleEmitter.minEmission = 70; particleEmitter.maxEmission = 110; particleEmitter.emitterVelocityScale = 0.4; particleEmitter.worldVelocity = Vector3(0,3,0); particleEmitter.rndVelocity = Vector3(1,0.5,0.5); particleEmitter.rndRotation = true;

angularVelocity: var angularVelocity : float La velocidad angular de las nuevas partculas en grados por segundo.

rndAngularVelocity: var rndAngularVelocity : float Un modificador aleatorio de velocidad angular para nuevas partculas. Un valor aleatorio en el rango de [rndAngularVelocity,rndAngularVelocity] ser aplicado a todas las nuevas partculas, en adicin a ParticleEmitter. angularVelocity. particleEmitter.minSize = 0.2; particleEmitter.maxSize = 0.5; particleEmitter.minEnergy = 1; particleEmitter.maxEnergy = 5; particleEmitter.minEmission = 70; particleEmitter.maxEmission = 110; particleEmitter.emitterVelocityScale = 0.4; particleEmitter.worldVelocity = Vector3(0,3,0); particleEmitter.rndVelocity = Vector3(1,0.5,0.5); particleEmitter.rndRotation = true; particleEmitter.angularVelocity = 1; particleEmitter.rndAngularVelocity = 66;

particles: var particles : Particle[] Devuelve una copia de todas las partculas y asigna un array de todas las partculas. Hemos de tener en cuenta que despus de modificar el array de partculas debemos asignarlo de vuelta al particleEmitter para ver el cambio. Partculas con energa de cero o menos sern elmiminadas cuando se asignen las partculas. As cuando se crea un completo nuevo array de partculas, necesitaremos colocar la energa de todas las partculas explicitamente.

particleCount: var particleCount : int El corriente nmero de partculas. Variable de slo lectura.

enabled: var enabled : boolean Establece el ParticleEmitter en on o off. Un ParticleEmitter que no est habilitado no emitir ninguna partcula, y las partculas emitidas no se animarn. As, este valor nos permite pausar un sistema de partculas. Reutilicemos el ejemplo anterior para pausar nuestro sistema de partculas transcurridos cinco segundos. particleEmitter.minSize = 0.2; particleEmitter.maxSize = 0.5; particleEmitter.minEnergy = 1;

particleEmitter.maxEnergy = 5; particleEmitter.minEmission = 70; particleEmitter.maxEmission = 110; particleEmitter.emitterVelocityScale = 0.4; particleEmitter.worldVelocity = Vector3(0,3,0); particleEmitter.rndVelocity = Vector3(1,0.5,0.5); particleEmitter.rndRotation = true; particleEmitter.angularVelocity = 1; particleEmitter.rndAngularVelocity = 66; yield WaitForSeconds(5); particleEmitter.enabled = false;

FUNCIONES: ClearParticles: function ClearParticles () : void Borra todas las partculas del sistema de partculas.

Emit: function Emit () : void Emite un nmero de partculas. Hace que el emitter escupa un nmero aleatorio de partculas que se establecen entre las propiedades minEmission y maxEmission. Probemos: particleEmitter.minSize = 0.2; particleEmitter.maxSize = 0.5; particleEmitter.minEnergy = 1; particleEmitter.maxEnergy = 5; particleEmitter.minEmission = 20; particleEmitter.maxEmission = 150; particleEmitter.emitterVelocityScale = 0.4; particleEmitter.angularVelocity = 1; particleEmitter.rndAngularVelocity = 66; particleEmitter.Emit(); function Emit (count : int) : void Esta variante de la funcin emite el nmero count de partculas inmediatamente. Pasmosle el parmetro 300 a la funcin Emit del ejemplo anterior, por poner un caso muy exagerado. function Emit (pos : Vector3, velocity : Vector3, size : float, energy : float, color : Color) : void Este tercer prototipo de la funcin Emit emite una partcula individual con unos parmetros dados. Expliquemos brevemente qu representa cada parmetro: pos velocity size energy color La La El El El posicin de la partcula. velocidad de la partcula. tamao de la partcula. tiempo de vida restante de la partcula. color de la partcula.

particleEmitter.Emit(Vector3.zero, Vector3.up, 0.4, 4, Color.yellow); Cuando le damos al play veremos una partcula en la posicin central, con direccin hacia arriba, un tamao de 0.4 unidades, que tardar 4 segundos en desvanecerse y tendr color amarillo. function Emit (pos : Vector3, velocity : Vector3, size : float, energy : float, color : Color, rotation : float, angularVelocity : float) : void Y an tenemos una tercera variante de la funcin, que incluye la rotacin inicial de la partcula en grados y la velocidad angular por segundo. particleEmitter.Emit(Vector3.zero, Vector3.up, 0.4, 4, Color.yellow, 75, 150);

Simulate: function Simulate (deltaTime : float) : void Avanzado sistema de simulacin de partculas por un tiempo dado. Es til para precalentar un sistema de partculas, como si se estuviera gestando: particleEmitter.Simulate(5);

22. CLASE MESH

Esta clase permite crear o modificar mallas desde scripts. Las mallas contienen vrtices y mltiples arrays de tringulos. Los arrays de tringulos son meramente ndices dentro del array de vrtices, tres ndices para cada tringulo. Para cada vrtice puede haber un normal, dos coordenadas de texturas, color y tangentes. Toda la informacin de los vrtices es almacenada en arrays separados del mismo tamao, as que si tu malla tiene 10 vrtices, debe tener tamben arrays de 10 de tamao para normales y otros atributos.

VARIABLES: vertices: var vertices : Vector3[] Devuelve una copia de la posicin del vrtice o asigna un nuevo array de posiciones de vrtices. El nmero de vrtices en la malla es cambiado asignando un array de vrtices con un diferente nmero de vrtices. Debemos tener en cuenta que si redimensionamos el array de vrtices entonces todos los otros atributos (normales, colores, tangentes, Uvs) sern automticamente redimensionados tambin. RecalculateBounds automticamente ser invocado si no se han asignado vrtices a la malla cuando se establecieron los vrtices.

normals: var normals : Vector3[] Los normales de la malla. Si la malla no contiene normales un array vaco es retornado.

tangents: var tangents : Vector4[] Las tangentes de la malla. Las tangentes son mayormente usadas en bump-mapped shaders. Una tangente es un vector de una unidad de longitud que sigue la malla a lo largo de la direccin de textura horizontal. Las tangentes en Unity son representadas como Vector4 con componentes x,y,z definiendo el vector, y w usada para dar la vuelta a la binormal si es necesario. Unity calcula los otros vectores de supervicie (binormal) tomando un producto cruzado entre normal y tangente y multiplicando el resultado por la tangente w. As w debe ser siempre 1 o -1. Debes calcular tangentes por ti mismo si planeas usar bump-mapped shaders en la malla. Asigna tangentes despus de asignar normals o usando RecalculateNormals.

uv: var uv : Vector2[] Las coordenadas de la textura base de la malla.

rv2: var uv2 : Vector2[] El segundo conjunto de coordenadadas de textura de la malla, si lo hubiere.

bounds: var bounds : Bounds El volumen de bordes de la malla. Esto es la caja de bordes alineadas en el eje de la malla en el espacio local (esto es, no afectada por el transform). Existe por otro lado la propiedad Renderer.bounds que retorna los bordes en espacio global.

colors: var colors : Color[] Devuelve los colores del vrtice de la malla. Si no hay colores devuelve un array vaco.

triangles: var triangles : int[] Un array conteniendo todos los tringulos de la malla. El array es una lista de tringulos que contiene ndices dentro del array de vrtices. El tamao del array de tringulos debe siempre ser mltiplo de 3. Los vrtices pueden ser compartidos meramente indexando dentro del mismo vrtice. Si la malla contiene mltiples sub mallas (materiales) la lista de tringulos contendr todos los tringulos de todas las submallas. Cuando asignas un array de tringulos, subMeshCount es

colocado a 1. Si quieres tener mltiples submallas, usa subMeshCount y SetTriangles. Es recomendable asignar el array de tringulos despus de asignar el array de vrtices para evitar errores de fuera de lmite (out of bounds)

vertexCount: var vertexCount : int Variable de slo lectura que devuelve el nmero de vrtices en la malla.

subMeshCount: var subMeshCount : int El nmero de submallas. Cada material tiene una lista de tringulos separada.

boneWeights: var boneWeights : BoneWeight[] La pintura de pesos de cada vrtice. El tamao del array es o el mismo que vertexCount o vaco. Cada vrtice puede ser afectado por un mximo de 4 diferentes huesos. Las cuatro pinturas de peso deben sumar hasta 1.

FUNCIONES: Mesh: static function Mesh () : Mesh Crea una malla vaca.

Clear: function Clear () : void Limpia todos los datos de los vrtices y todos los ndices de los tringulos. Debes llamar esta funcin antes de reconstruir el array de tringulos.

RecalculateBounds: function RecalculateBounds () : void Recalcula el volumen de bordes de la malla desde los vrtices. Despus de modificar los vrtices debes llamar a esta funcin para asegurarte de que el volumen de bordes es correcto. Asignando tringulos automticamente se recalcula el volumen de bordes.

RecalculateNormals: function RecalculateNormals () : void Recalcula los normales de la malla desde los tringulos y vrtices. Despus de modificar los vrtices es a menudo til actualizar los normales para reflejar el cambio. Los normales son calculados desde todos los vrtices compartidos. Las mallas importadas a veces no comparten todos los vrtices. Por ejemplo un vrtice en una costura UV se partir en dos vrtices. En consecuencia la funcin RecalculateNormals crear normales que no son lisos en las costuras Uv. Notemos tambin que RecalculateNormals no genera tangentes automticamente, asi que los bumpmap shaders no trabajarn con la malla despus de llamar a esta funcin. Nosotros podemos sin embargo proveer nuestras propias tangentes.

Optimize: function Optimize () : void Optimiza la malla para mostrarla. Esta operacin podra tomar un rato pero hace que la geometra se muestre ms rpido. Debes usarla si generas una malla desde cero procedimentalmente y quieres un mayo rendimiento en tiempo de ejecucin en lugar de un mayor tiempo de carga. Para modelos importados no debes nunca llamarla porque el import pipeline ya lo hace por ti.

GetTriangles: function GetTriangles (submesh : int) : int[] Devuelve la lista de tringulos de la submalla. Una submalla es simplemente una lista de tringulos separada. Cuando el mesh renderer usa mltiples materiales, debes asegurarte de que hay tantas submallas como materiales.

SetTriangles: function SetTriangles (triangles : int[], submesh : int) : void Establece la lista de tringulos para la submalla. Es recomentable asignar el array de tringulos despus de asignar el array de vrtices para evitar el error de fuera de bordes.

CombineMeshes: function CombineMeshes (combine : CombineInstance[], mergeSubMeshes : boolean = true, useMatrices : boolean = true) : void Combina varias mallas dentro de la malla. Combinar mallas es til para optimizacin de rendimiento. Si mergeSubMeshes es true, todas las mallas sern combinadas en una nica submalla. En caso contrario cada malla ir dentro de una submalla diferente. Si todas las mallas comparten el mismo material, coloca esto a true. Si useMatrices es false, el transform matrices en la estructura CombineInstance ser ignorado.

23. CLASE GAMEOBJECT

Estamos en la clase central, en la clase con maysculas de Unity. De hecho, muchas de las clases que hasta la fecha hemos estudiado (y algunas que nos faltan) no son ms que diferentes mimbres cuya funcin primordial era confluir en esta clase. No deber sorprendernos, por tanto, que buena parte de las variables o propiedades de la clase GameObject no son sino instancias de las clases que ya hemos estudiado, de tal forma que cualquier gameobject en la escena (recordemos que todo lo que est en la escena son gameobjects) tenga la ms amplia funcionalidad.

VARIABLES: isStatic: var isStatic : boolean Variable slo utilizable va interface que especifica si un objeto es esttico. Esto es til cuando estemos trabajando con occlusion culling, para determinar si un objeto puede ser considerado un oclusor esttico. Para quien no sepa qu diantres es lo de occlusion culling, decir que es una caracterstica que deshabilita el renderizado de objetos cuando no estn siendo actualmente vistos por la cmara porque son oclusionados/tapados por otros objetos. El proceso de occlusion culling va a trav de la escena usando una cmara virtual construyendo una jerarqua de objetos potencialmente visibles. Estos datos sern usados en tiempo de ejecucin por cada cmara para identificar qu es visible y qu no. Necesitamos etiquetar todos los objetos de la escena que queramos que sean parte de la occlusion como Static en el inspector. La manera ms rpida de hacerlo es convertir todos los objetos que queramos marcar como estticos en hijos de un GameObject vaco y establecer ste como Static, eligiendo luego en la opcin de dilogo que la condicin de static

afecte tambin a todos sus hijos. Despus de eso, ya podemos tranquilamente desparentarlos del gameobject vaco, y seguirn teniendo la consideracin de static.

transform: var transform : Transform El transform del gameobject, si lo tiene. Null si no tiene ningn transform vinculado. Tal como explicaba antes, sta va a ser la tnica de la mayora de propiedades de la clase Gameobject: integrar objetos/instancias de diferentes clases para conformar la utilidad bsica de nuestro juego: los gameobjects. Podemos demostrar que todo lo que est en la escena es un gameobject: Eliminamos antes que nada el gameobject particulas que creamos en la clase anterior. Si tenemos algn script vinculado al cubo o la esfera, los eliminamos. Vamos a editar ahora MiPrimerScript: var unGameObject: GameObject; function Update() { unGameObject.transform.Rotate(0,5,0); } El script debera resultarnos fcil a estas alturas. Declaramos una variable expuesta de tipo Gameobject, de tal manera que posteriormente podamos acceder al transform de la que arrastremos y rotar el gameobject sobre el eje Y. Salvamos. Arrastramos el script a PortaScripts en la jerarqua. Con PortaScripts seleccionado, arrastramos el cubo a la variable expuesta. Play. Tal como era de esperar, el cubo comienza a girar. Pero vamos a ver qu otros elementos en la escena son considerados por Unity Gameobjects, y por tanto susceptibles de tener un transform. Si con PortaScripts seleccionado nos vamos al inspector, observaremos que a la derecha de la variable expuesta que hemos inicializado con el cubo hay una pequea flecha. Si hacemos click sobre ella, se nos abre un men emergente con TODOS los gameobjects de la escena. De hecho hasta nuestro PortaScripts -a pesar de no ser ni visible- es considerado un gameobject. As, si en ese mismo popup hacemos doble click en main camera y le damos al play, observaremos en la vista del juego que lo que empieza a girar es la cmara.

rigidbody: var rigidbody : Rigidbody El rigidbody vinculado a nuestro gameobject, o null si ste no tiene rigidbody.

camera: var camera : Camera La cmara vinculada a nuestro gameobject, o null si ste no tiene una cmara. Por ejemplo, nuestra main camera es un gameobject que tiene vinculado una cmara (y un transform).

light: var light : Light La luz vinculada al gameobject. Null si no tiene.

animation: var animation : Animation La animacin vinculada al gameobject. Null si no tiene. No hemos tratado an nada relacionado con animaciones, clips y sonidos, ya que he preferido reservarlo para ms adelante y tratarlo todo junto.

constantForce: var constantForce : ConstantForce la constantForce vinculada a este gameobject. Null si no tiene ninguna vinculada. No habamos tratado todava la miniclase ConstantForce, pero vamos a subsanar ese pequeo lapsus ahora mismo: La clase ConstantForce deriva de Behaviour (como camera, light, animation...) y cuenta slo con cuatro variables/propiedades (amn de las heredadas), que son: force: var force : Vector3 La fuerza aplicada al rigidbody cada frame. Esto ltimo es lo que la diferencia de rigidbody.AddForce(). En AddForce se aplica la fuerza al rigidbody una vez por frame, lo que obliga a llamar a la funcin varias veces (por ejemplo dentro de una funcin fixedUpdate). constantForce.force aplicar la fuerza indicada cada frame hasta que cambiemos el contenido de la variable force a un nuevo valor. Esto es aplicable a las cuatro variables de esta clase. relativeForce: var relativeForce : Vector3 La fuerza -relativa al sistema de coordenadas local del rigidbody- aplicada cada frame. torque: var torque : Vector3 La torsin aplicada al rigidbody cada frame. relativeTorque: var relativeTorque : Vector3 La torsin -relativa al sistema de coordenadas local del rigidbody- aplicada cada frame. Pongamos un ejemplo global: Antes que nada seleccionamos el cubo, y nos vamos al men=>Component=>Physics=>Constant Force. Editamos una vez ms MiPrimerScript: var unGameObject: GameObject; unGameObject.constantForce.force = Vector3(3,10,0); unGameObject.constantForce.torque = Vector3(0,8,0);

Salvamos. Recordemos que este script lo tenemos vinculado al gameobject PortaScripts, as que lo seleccionamos. Arrastramos el cubo a la variable expuesta. Observemos que ambos atributos estn fuera de toda funcin o bucle, esto es, que tal como hemos dicho, tanto la fuerza (hacia la derecha y hacia arriba) como la torsin (sobre el eje Y) que le aplicamos tendrn carcter peridico debido nica y exclusivamente a las propias caractersticas de la clase constantForce. Play.

renderer: var renderer : Renderer El renderer vinculado al gameobject. Null si no tiene.

audio: var audio : AudioSource el audiosource vinculado al gameobject. Null si no tiene.

guiText: var guiText : GUIText El guiText (de prximo estudio) vinculado al gameobject. Nulo si no existe.

networkView: var networkView : NetworkView El networkView (a estudiar mucho ms adelante) vinculado al gameobject. Nulo si no existe.

guiTexture: var guiTexture : GUITexture El guiTEXture (en breve) vinculado al gameobject. Null si carece de l.

collider: var collider : Collider El collider vinculado al gameobject, si lo tiene. Null en caso contrario.

hingeJoint: var hingeJoint : HingeJoint El hingeJoint vinculado al gameobject, o null.

particleEmitter: var particleEmitter : ParticleEmitter El particleEmitter vinculado al gameobject, null si no tiene.

layer: var layer : int Es una variable de tipo int comprendida entre el rango 0 y 31 que indica/coloca la capa en la que el gameobject se encuentra. El layer sirve entre otras cosas para realizar un renderizado selectivo de lo que una cmara debe mostrar o para determinar si a un determinado gameobject les afectar o no un raycast.

active: var active : boolean Est el gameobject activo?. Podemos habilitarlo/deshabilitarlo cambiando a true o false este booleano.

tag: var tag : String El tag (etiqueta) de este game object. Puede ser usado para identificar a un gameobject. Hemos de recordar que antes de poder usar esta variable debemos haber declarado el tag en el inspector.

FUNCIONES: GameObject: static function GameObject (name : String) : GameObject La funcin constructora de gameobject tiene tres prototipos diferentes. El primero, como vemos, nos permite crear un nuevo gameobject y pasarle un parmetro que constituir el nombre de dicho gameobject. Veamos un ejemplo sencillo. Editamos MiPrimerScript: var nuevoGameObject: GameObject; nuevoGameObject = new GameObject("miNuevoObjeto"); Lo salvamos. Si no lo estaba, lo arrastramos a PortaScripts. Le damos al play. Aparentemente no ocurre nada. No aparece ningn objeto en la escena ni en la ventana del juego. Esto es porque nuestro nuevo gameobject est vaco, como podremos comprobar si -con el juego reproducindose- seleccionamos el nuevo gameobject de nombre miNuevoObjeto que aparece en la jerarqua. Observamos que tan slo tiene un elemento transform (que se crea por defecto).

Pero, ya teniendo un gameobject creado en tiempo de ejecucin (y volveremos sobre este concepto pasado no demasiado tiempo), podemos de la misma forma aadirle componentes: var nuevoGameObject: GameObject; nuevoGameObject = new GameObject("miNuevoObjeto"); nuevoGameObject.AddComponent ("BoxCollider"); nuevoGameObject.AddComponent ("MeshRenderer"); En este caso le aadimos un collider de cubo y una meshrenderer. Seguir sin verse nuestro nuevo gameobject -salvo que lo seleccionemos en la jerarqua, en cuyo caso veremos la malla) porque para ello le deberamos haber creado una malla desde cero, pero a los efectos de este ejemplo con esto debera bastar. static function GameObject () : GameObject Crea un gameobject, pero sin nombre nombre, lo cual no obsta para que luego se le pueda asignar uno. static function GameObject (name : String, params components : Type[]) : GameObject Esta variante del constructor crea un gameobject con nombre y ya vinculado a una serie de componentes prefijados.

GetComponent: function GetComponent (type : Type) : Component Esta funcin devuelve el componente de tipo Type que tenga el gameobject. En caso de que el gameobject que lanza el mensaje no tenga ningn componente de ese tipo, devuelve null. Adems de acceder a componentes Standard de unity, puedes acceder a scripts por esta va. En este caso, el nombre del script equivaldr al Type del parmetro de bsqueda. Ojo, porque aunque pongamos el nombre del script, como en realidad sustituye y equivale a un tipo de componente, lo escribiremos sin comillas (no es un string) Es decir, si por ejemplo quisiramos -no hace falta que realicis este ejemplo, es slo para aclarar conceptos- hacer algo en caso de que un determinado gameobject tenga un determinado script, haramos algo como esto: var unObjetoCualquiera : GameObject; if(unObjetoCualquiera.GetComponent(miPrimerScript) { HazAlgunaCosa(); } Arrastraramos luego el gameobject que quisiramos consultar, y si ste tuviera vinculado un script de nombre miPrimerScript -en caso contrario devolvera null- se ejecuta la funcin HazAlgunaCosa. Esta funcin nos permite adems acceder a variables pblicas (no private ni dentro de funciones) y funciones que se hallen en otro script que est vinculado al mismo gameobject. Pongamos que el script del ejemplo lo vinculamos directamente a un gameobject (no como el anterior, en que arrastramos el gameobject a la variable expuesta) y dicho gameobject a su vez tiene vinculado otro script llamado otroScript. Podemos capturarlo con esta funcin y asignarlo a una variable de tipo ScriptName. var unSegundoScript : ScriptName = gameObject.GetComponent(otroScript); // Una vez ya hemos capturado ese script, como decimos, podemos acceder a sus //funciones y variables pblicas.

unSegundoScript.HazOtraCosa (); unSegundoScript.tengoUnaVariable = 5; } function GetComponent (name : String) : Component Es identica a la anterior, pero en lugar de acceder a un componente por su tipo, lo hacemos por su nombre a travs de un string (aqu s colocaremos comillas). Es preferible la primera firma por motivos de rendimiento, pero si no recordamos el tipo del componente, podemos buscar por el nombre. Recordemos que el nombre de un script ajeno pero vinculado al gameobject que hace la consulta es tambin su tipo, lo cual no obsta a que siga siendo su nombre y podamos consultarlo por l, aunque con comillas (otroScript, sera en este caso la manera de escribir el parmetro de bsqueda).

GetComponentInChildren: function GetComponentInChildren (type : Type) : Component Devuelve un componente activo de tipo que le pasamos como parmetro que pueda tener o bien el Gameobject que lanza el mensaje o bien sus hijos. La bsqueda empieza por los hijos.

GetComponents: function GetComponents (type : Type) : Component[] Esta funcin devuelve todos los componentes del tipo Type y los devuelve en forma de array del tipo de componente solicitado. Esto nos permitira hacer cosas como las del ejemplo que nos brinda el manual de referencia (no es preciso seguir el ejemplo, es slo a modo oritentativo): //Vamos a desconectar la variable spring de todos los HingeJoints que tenga este //gameobject. Primero crearemos un array de tipo HingeJoint y lo almacenamos //en la variable bisagras. var bisagras : HingeJoint[]; //Y colocamos todos los HingeJoint que encontremos en el array. bisagras = gameObject.GetComponents (HingeJoint); //Recorremos ahora en un bucle for in todos los componentes hallados y les //desactivamos la variable spring. for (var joint : HingeJoint in bisagras) { joint.useSpring = false; }

GetComponentsInChildren: function GetComponentsInChildren (type : Type, includeInactive : boolean = false) : Component[] Devuelve todos los componentes del tipo pasado como primer parmetro que tenga ese gameobjects y sus hijos. La

peculiaridad es que la funcin incluye un segundo parmetro opcional de tipo booleano que si establecemos en true nos permite recuperar tambin los componentes inactivos de ese tipo.

SetActiveRecursively: function SetActiveRecursively (state : boolean) : void Funcin que activa o desactiva el estado del gameobject que la invoca y de todos sus hijos, en funcin de si el bolean que tiene como parmetro est en true o false.

CompareTag: function CompareTag (tag : String) : boolean Esta funcin nos permite averiguar si un determinado gameobjet tiene como tag el string colocado como parmetro de la funcin. Si lo tiene, la funcin devuelve true.

SendMessageUpwards: function SendMessageUpwards (methodName : String, value : object = null, options : SendMessageOptions = SendMessageOptions.RequireReceiver) : void Esta funcin llama a una funcin cuyo nombre pasamos en el parmetro methodName y que se encuentre en cualquier script que tengamos vinculado al gameobject que hace la llamada o en los "padres" de dicho gameobject. Le podemos, si procede, pasar un valor a dicho mtodo (value). El parmetro options es del tipo SendMessageOptions, que es un enum con dos valores = requireReceiver (que necesita respuesta) y dontRequireReceiver, que no la requiere. Por defecto la funcin requiere respuesta, lo cual quiere decir que si se le pasa un argumento a la funcin receptora y sta no precisa ninguno, imprimir un mensaje de error. Si no lo requiriera (dontRequireReceiver), puede optar por ignorar dicho argumento sin ms. Vamos a intentar aclararlo un poco ms con un ejemplo. Previamente eliminemos el script que tenemos vinculado en PortaScripts. Acto seguido, editamos miPrimerScript y lo dejamos como sigue: function DameColor (tono : Color) { renderer.material.color= tono; } DameColor(Color.black); La funcin no requiere ms explicacin. La arrastramos al cubo y al darle al play ste se torna de color negro. Ahora vamos a editar el script miSegundoScript, que si hemos seguido las lecciones debemos tener en Proyecto. (y si no creamos uno, tampoco nos volvamos locos). Tecleamos: function OnMouseEnter() { gameObject.SendMessageUpwards ("DameColor", Color.cyan); } Arrastramos tras salvar este script tambin al cubo. De esta manera y a travs de SendMessageUpwards podemos acceder a la funcin DameColor de miPrimersScript y usarla a nuestro gusto. En este caso nos limitamos a cambiar el color del cubo al pasar el ratn por ste, pero obviamente y en caso de gameobjects con un montn de scripts vinculados (que a eso llegaremos) esta posibilidad de acceder desde un scripts a las funciones que hay en otros es toda una ventaja.

SendMessage: function SendMessage (methodName : String, value : object = null, options : SendMessageOptions = SendMessageOptions.RequireReceiver) : void Igual que la funcin anterior, con la diferencia de que en esta slo podemos llamar a funciones que estn en scripts vinculados al gameobject, pero no en sus ancestros.

BroadcastMessage: function BroadcastMessage (methodName : String, parameter : object = null, options : SendMessageOptions = SendMessageOptions.RequireReceiver) : void Llama a un mtodo con nombre methodName que est en cualquier script vinculado a ese game object o a cualquiera de sus hijos, a diferencia de las funciones anteriores.

AddComponent: function AddComponent (className : String) : Component Aade un componente a nuestro gameobject. Ese componente ha de ser una instancia de la clase que ponemos en el parmetro className, o bien puede ser el nombre de un script. Es til para aadir componentes en tiempo de ejecucin. Algunos componentes requieren de la presencia de otros para existir, as que al aadir aqullos automticamente se nos aadirn estos. Pej, si aadimos un HingeJoint automticamente se nos aadir un Rigidbody. function AddComponent (componentType : Type) : Component La nica variacin es que en lugar de string, introducimos el tipo de componente o el nombre del script sin comillas. Ntese que no existe la funcin RemoveComponent o similar. Para destruir un componente al vuelo, usad Object.Destroy

FUNCIONES DE CLASE: CreatePrimitive: static function CreatePrimitive (type : PrimitiveType) : GameObject Crea un gameobject con una malla de tipo primitivo y el apropiado collider. Los tipos primitivos son sphere, capsule, cylinder, cube y plane. Veamos algn ejemplo (recordemos que es una funcin de clase, no vinculada a un objeto concreto) Eliminemos antes que nada los dos scripts vinculados al cubo. Y luego editamos miPrimerScript: function Start() { var miCilindro : GameObject = GameObject.CreatePrimitive(PrimitiveType.Cylinder); miCilindro.transform.position = Vector3(0,0,-2); }

Salvamos y arrastramos a PortaScripts. Vemos que hemos creado en ejecucin un tipo primitivo (un cilindro en este caso) de entre los que la enum PrimitiveType nos permite), con su malla y su collider. Este cilindro lo almacenamos en una variable de tipo Gameobject que a partir de ah podemos tratar como un gameobject ms, cambindole, por ejemplo, de ubicacin.

FindWithTag: static function FindWithTag (tag : String) : GameObject Devuelve un gameobject con el tag que le pasamos a la funcin como string en su nico parmetro. Si no existe ninguno. Devuelve null. Dado que es una funcin de clase y no va vinculada a ningn objeto, ha de quedar claro que el gameobject con el tag que buscamos no tiene por qu hacer referencia a ningn gameobject vinculado al script, sino a cualquier gameobject del juego que est activo. El tag, eso s, previamente debe estar declarado en el tag manager del inspector.

FindGameObjectWithTag: static function FindGameObjectsWithTag (tag : String) : GameObject[] Esta funcin de clase devuelve una lista de gameobjects activos que tengan el tag requerido.

Find: static function Find (name : String) : GameObject Busca un gameobject por nombre y lo devuelve. Aqu no buscamos por tag, sino por nombre. Hemos de reiterar que es una funcin de clase, no vinculada a un determinado gameobject, o sea, podemos buscar con esta funcin cualquier gameobject activo del juego.

Se puede usar el slash (/) para buscar a travs de una jerarqua. Por motivos de rendimiento es aconsejable no usar esta funcin cada frame. Es mejor o, una vez hallado el gameobject, almacenarlo en una variable, o bien usar la funcin gameobject.findwithtag. Por poner un ejemplo sencillo, reeditemos una vez ms miPrimerScript: var buscaLaEsfera : GameObject; buscaLaEsfera = GameObject.Find("Esfera"); Debug.Log(buscaLaEsfera.name.ToString()); buscaLaEsfera.renderer.material.color = Color.green; Tal como indicbamos en la definicin, buscamos con Find un gameobject de nombre Esfera, lo almacenamos en una variable de tipo gameobject, y ya a partir de ah podemos, por ejemplo, imprimir su nombre o cambiarle el color.

24. CLASE SHADER

Abordamos esta clase pequea y poco importante ms por seguir un orden en la jerarqua de clases que por otra cosa. No obstante, aunque ser raro que nos topemos a menudo con la misma, no est de ms tener una idea bsica de su funcionalidad. Creo que ya indicamos en otro lugar que un shader es en 3d el algoritmo que especifica cmo una superficie reaccionar ante la luz. Muchos de los renders avanzados son controlados va la clase Material. La clase Shader es ms usada para comprobar si un shader puede correr en el hardware del usuario (propiedad isSupported) y para encontrar shaders por el nombre (mtodo Find).

VARIABLES: isSupported: var isSupported : boolean Bool de slo lectura que indica si un determinado shader puede correr en la tarjeta grfica del usuario. Se usa a veces cuando se implementan efectos especiales. Por ejemplo, image effects en Unity Pro automticamente se deshabilitan si el shader no es soportado.

FUNCIONES DE CLASE: Find: static function Find (name : String) : Shader Encuentra un shader con el nombre dado. Name es el nombre que vemos en el popup del shader de cualquier material. Son nombres comunes: "Diffuse", "Bumped Diffuse", "VertexLit", Transparent/Diffuse" etc.

25. CLASE PHYSICMATERIAL

Esta clase describe cmo manejar los objetos que chocan (friccin, capacidad de rebotar, etc). Es posible que recordemos cuando estudibamos la clase Collider, que sta tena dos variables/atributos -material y sharedMaterial- de tipo PhysicMaterial. Por norma general para crear/modificar las capacidades de friccin y rebote de un gameobject, pues, lo haremos a travs de la propiedad collider.material de dicho gameobject. VARIABLES: dynamicFriction: var dynamicFriction : float La friccin usada cuando ya hay movimiento. Este valor ha de estar entre 0 y 1, siendo 0 la friccin del hielo y 1 la del caucho. Probemos un ejemplo. Para ello empecemos por eliminar el script vinculado a PortaScripts. Luego editamos miPrimerScript, de esta guisa: collider.material.dynamicFriction = 0; function FixedUpdate() { rigidbody.AddForce(0,0,-9); } Salvamos y le asignamos el script al cubo. Como vemos, le hemos dado al material la mnima friccin. Le damos al play y observamos que la fuerza arrastra el cubo sin problemas. Pero ahora probad a darle a dynamicFriction un valor de 0.4.

staticFriction: var staticFriction : float La friccin usada cuando un objeto est reposando en una superficie. Usualmente un valor de 0 a 1. Siguiendo con nuestro ejemplo, podemos teclear:

collider.material.staticFriction = 0; collider.material.dynamicFriction = 0.2; function FixedUpdate() { rigidbody.AddForce(0,0,-9); } Aqu nuestro cubo tendra una friccin en reposo nula y una en movimiento baja. Podemos tratar de invertir las tornas entre ambos valores e ir experimentando.

bounciness: var bounciness : float Qu capacidad de rebote tiene la superficie. 0 es no rebote. Un valor de 1 implica rebote sin prdida de energa. Para verlo con un ejemplo, eliminamos el script vinculado a nuestro cubo, primero, y luego colocamos la esfera en la posicin (2,5,0). Editamos entonces miPrimerScript: collider.material.bounciness = 0.7; Lo vinculamos a la esfera. Observamos que sta rebota un poco, sobre todo si comparamos el comportamiento de la esfera si establecemos esta propiedad en cero. No obstante, nos puede sorprender que a un valor tan alto como 0.7 la capacidad de rebote de nuestra esfera no sea superior. Dicha sorpresa se acrecienta si le asignamos el valor mximo (1) a bounciness. Lo que sucede es que Unity establece una media entre los valores de rebote de las dos superficies en contacto. Probad a arrastrar miPrimerScript tambin al Suelo y veris la diferencia.

frictionDirection2: var frictionDirection2 : Vector3 Se refiere a la direccin de anisotropa. La friccin anisotrpica est habilitada salvo que su vector est a cero. La anisotropa es aquella cualidad (forma, tamao, temperatura, etc) que cambia en un objeto cuando se mueve. DynamicFriction2 y staticFriction2, que estudiaremos a continuacin, sern aplicadas a lo lardo de frictionDirection2. La direccin de anisotropa es relativa al sistema de coordenadas local del collider. Utilizaremos un pequeo ejemplo para entender cmo funciona esto. Previamente devolvemos a la esfera al suelo (position.y=0) y luego eliminamos el script miPrimerScript que tenemos vinculado al suelo y la esfera. Editamos despus de nuevo miPrimerScript: collider.material.dynamicFriction = 1; collider.material.frictionDirection2 = Vector3.forward; collider.material.dynamicFriction2 = 0; function FixedUpdate() { rigidbody.AddForce(5,0,0); } Arrastramos tras salvar el script al cubo. Bien. Vamos a tratar de explicar qu tenemos aqu. En primer lugar establecemos la friccin dinmica del cubo al mximo, esto es, 1. De esta manera debera resultar difcil poderlo arrastrar. Pero, a continuacin, le damos a frictionDirection2 un valor distinto a 0,0,0, esto es, lo activamos. Lo que le estamos diciendo aqui a Unity es que a lo

largo del eje Z (forward) la friccin del cubo ser distinta que cuando se mueva a lo largo de los otros dos ejes (esto es la anisotropa). Concretamente, en la tercera declaracin le indicamos a Unity que la friccin dinmica en ese eje Z dynamicFriction2 ser nula (0). En consecuencia, el resultado de este script debera hacer que el cubo se resistiera a moverse en los ejes X e Y pero en cambio no tuviera problemas en hacerlo en el eje Z. Para abrir boca, le aplicamos al script acto seguido una fuerza en el eje X. Pulsemos el play y comprobemos que el cubo si se mueve. Pero ahora cambiemos los parmetros de AddForce a (5,0-5), esto es, aplicndole la misma fuerza en el eje Z (que no debera tener resistencia) que al X. Si funciona como debiera, el cubo empezar a moverse hacia delante, pero seguir negndose a hacerlo hacia la derecha, aunque la presin en un eje y otro es la misma. Probad.

dynamicFriction2: var dynamicFriction2 : float Si la friccin anisotrpica est habilitada (frictionDirection2 no vale cero), dynamicFriction2 ser aplicada a lo largo del eje/s de frictionDirection2 que no valga cero.

staticFriction2: var staticFriction2 : float Si la friccin anisotrpica est habilitada, staticFriction2 ser aplicada a lo largo de frictionDirection2.

frictionCombine: var frictionCombine : PhysicMaterialCombine Determina cmo se combina la friccin. Tal como explicaba hace unas lneas en relacin con el rebote, asimismo las propiedades de friccin son dependientes de la combinacin de los dos materiales en contacto. PhysicMaterialCombine (el tipo de este atributo) es una enumeracin con las diferentes posibilidades de combinacin de fricciones y capacidades de rebote. Average Multiply Minimum Maximum La media de la friccin o rebote de los materiales de los dos colliders. Multiplica la friccin o rebote de los materiales de los dos colliders. Usa el valor ms bajo de friccin o rebote de los dos colliders. El valor ms alto de los dos.

As, la sintaxis para establecer la friccin entre dos colliders en el valor ms alto de los dos sera as (a modo indicativo, nada ms): collider.material.frictionCombine = PhysicMaterialCombine.Maximum;

bounceCombine: var bounceCombine : PhysicMaterialCombine

Determina cmo la capacidad de rebote es combinada. Al igual que la anterior, recurriremos al enum PysicMaterialCombine.

FUNCIONES: PhysicMaterial: static function PhysicMaterial () : PhysicMaterial La funcin constructora crea un nuevo material. Es normalmente ms fcil, sin embargo, usar meramente un collider.material y modificar el material vinculado directamente. static function PhysicMaterial (name : String) : PhysicMaterial Crea un nuevo material con un nombre dado.

26. CLASE COMPONENT

Si realizamos un vistazo ms o menos fugaz a las variables y funciones contenidas en esta clase, ms de uno llegar a la conclusin de que guardan mucha similitud con las de la clase GameObject. Tras compararlas ms detenidamente, podemos hacer la siguiente afirmacin: la clase Component no tiene ningn atributo ni propiedad que no tenga la clase GameObject. En aras de ser exactos, podemos decir que la clase Component es igual que la clase GameObject, sin las propiedades isStatic, layer y active y sin los mtodos SetActiveRecursively, AddComponent, y obviamente su constructor. Esto es as porque Component no est pensada para ser usada directamente (para ello ya tenemos Gameobject) sino para que sus mtodos y atributos sean heredados por buena parte de clases (de rigidbody a camera y de joint a light pasando por transform).

27. CLASE GUIELEMENT

Volvemos a bajar de nuevo en nuestra jerarqua de clases para buscar otra heredera de Behaviour. GUIElement es a su vez una clase base, que establece la funcionalidad mnima para todos los elementos de la GUI (Interfaz Grfica de Usuario), entendiendo "elementos" como las imgenes y cadenas de texto mostradas en la GUI.

FUNCIONES: HitTest: function HitTest (screenPosition : Vector3, camera : Camera = null) : boolean Es un punto en la pantalla dentro del elemento. Devuelve true si la posicin pasada como parmetro screenPosition est contenida en este GUIElement. La screenPosition es especificada en coordenadas de pantalla, a semejanza de los valores retornados por Input.mousePosition property. Si no se proporciona a la funcin una cmara en concreto, se asumir por esta una cmara cubriendo la ventana del juego entera. Hemos de tener en cuenta que si la posicin est dentro del elemento, esta funcin devolver true incluso si el gameobject pertenece al layer Ignore Raycast.

GetScreenRect: function GetScreenRect (camera : Camera = null) : Rect Devuelve lo bordes del rectngulo del GUIElement en coordenadas de pantalla. Si no se proporciona a la funcin una cmara en concreto, se asumir por esta una cmara cubriendo la ventana del juego entera.

28. CLASE GUITEXT

La clase GUIText es una de las dos que derivan de GUIElement (vista en la leccin anterior). En concreto, la clase GUIText es la que se ocupa de los string de texto mostrados en un GUI (de las imgenes se ocupa GUITexture, que veremos luego).

VARIABLES: text: var text : String Variable que contiene el texto que se muestra en el GUI. Empecemos con la habitual tanda de ejemplos. Para empezar, eliminamos el script que tenemos en el cubo. Luego vamos a crear un gameobject de tipo GUIText, para lo que nos vamos al men=>Gameobject=>Create other=>Gui Text. Renombramos a nuestro nuevo gameobject como "miTexto". Observaremos que en la ventana Game nos aparece un texto ("gui text") por defecto. Editamos miPrimerScript: guiText.text = "Bienvenidos a unityscripts"; Arrastramos tras salvar el script a miTexto. Play. Observamos que el texto que hemos introducido se nos muestra en la ventana Game, tal como se ve en esta captura:

material: var material : Material El material usado para renderizar el texto. Esta variable nos permite acceder a l para modificarlo o crear uno. Si le damos un valor null se mostrar la fuente por defecto. Podemos por ejemplo completar un poco ms nuestro anterior script: guiText.text = "Bienvenidos a unityscripts"; guiText.material.color = Color.magenta; Y habremos alterado el color de nuestras letras de bienvenida.

pixelOffset: var pixelOffset : Vector2 El desplazamiento en pxeles del texto desde su posicin inicial (marcada por su transform) en base a los valores contenidos en un Vector2. Un ejemplo sencillo que no merece ms comentario: guiText.text = "Bienvenidos a unityscripts"; guiText.material.color = Color.magenta; guiText.pixelOffset = Vector2 (-150, 100);

font: var font : Font La fuente usada para el texto. Podemos asignar una de entre las que tengamos disponibles.

alignment: var alignment : TextAlignment La alineacin del texto. TextAlignment es una estructura con los valores Left, Center y Right. Para probar esto hemos de aadir ms texto a nuestro ejemplo del captulo con algunos saltos de linea: guiText.text = "Bienvenidos a unityscripts. \nAadimos una \nsegunda y tercera linea"; guiText.material.color = Color.magenta; guiText.alignment = TextAlignment.Center; Podemos comprobar que el texto se alinea centrado.

anchor: var anchor : TextAnchor El ancla del texto. TextAnchor es una enumeracin que permite indicar dnde se colocar el ancla o fijacin del texto. Tiene estas posibilidades: UpperLeft El texto se fija en la esquina superior izquierda. Para entendernos, la parte superior de la B de nuestro "Bienvenidos" del ejemplo estar ubicada en el punto marcado por las coordenadas de posicin del transform del GUIText. El texto se fija en el lado central superior, esto es, la mitad de nuestra frase, medida horizontalmente, en su lado superior, coincidir con la ubicacin marcada por el transform. El texto se fija en la esquina superior derecha. El texto se fija en el lado izquierdo, centrado verticalmente. El texto se centra tanto vertical como horizontalmente respecto de su transform. El texto se ancla en el lado derecho, centrado verticalmente. El texto se fija en la esquina inferior izquierda. El texto se ancla en la parte inferior, centrada horizontalmente. El texto se fija en la esquina inferior derecha.

UpperCenter UpperRight MiddleLeft MiddleCenter MiddleRight LowerLeft LowerCenter LowerRight

Vamos a centrar nuestra frase respecto la posicin del transform del GUIText. Aadimos al script: guiText.text = "Bienvenidos a unityscripts. \nAadimos una \nsegunda y tercera linea"; guiText.material.color = Color.magenta; guiText.alignment = TextAlignment.Center; guiText.anchor = TextAnchor.MiddleCenter; lineSpacing: var lineSpacing : float El multiplicador del espacio de interlineado. Esta cantidad ser multiplicada por el espacio de lnea definido en la fuente.

tabSize: var tabSize : float

El multiplicador de la anchura del tab. Esta cantidad se multiplicar con la anchura de tab definida en la fuente.

fontSize: var fontSize : int El tamao de fuente a usar (para fuentes dinmicas). Si lo establecemos en una cantidad distinta de cero, el tamao de fuente especificado en la fuente importada es sobreescrito con un tamao personalizado. Esto slo es soportado para fuentes que usen fuentes dinmicas de renderizado. Otras fuentes siempre usarn el tamao de fuente por defecto.

fontStyle: var fontStyle : FontStyle Lo mismo que la anterior para el estilo de Fuentes dinmicas.

29. CLASE GUITEXTURE

Clase "hermana" de GUIText, GUITexture se encarga de manejar las imgenes que compondrn nuestra GUI en 2d. Para una mejor comprensin, no tenis ms que hacer lo siguiente: eliminad el gameobject "miTexto" y acto seguido ir al men=>gameobject=>create other=>GUI texture. Aparecer por defecto el icono de Unity en nuestra escena. Llamemos a nuestro nuevo gameobject "logoUnity".

VARIABLES: color: var color : Color El color de la textura de la GUI. Un ejemplo muy sencillo. Editamos miPrimerScipt: guiTexture.color = Color.blue; Lo arrastramos a logoUnity, play, y nuestra imagen/textura pasa a ser de color azul.

texture: var texture : Texture La textura usada para dibujar. Es posible que conservemos todava en Proyecto la imagen que llamamos "multicolor" que usamos para que diera vueltas alrededor de la esfera. Si la tenis ah, perfecto, y si no arrastrad hasta la carpeta assets donde tengis guardado vuestro proyecto cualquier imagen. Luego editamos miPrimerScript como sigue:

var unaTextura : Texture; guiTexture.texture = unaTextura; Salvamos y arrastramos la textura a la variable expuesta. Al darle al play observamos que la misma sustituye al logo de Unity.

pixelInset: var pixelInset : Rect Insercin de pixels usada para ajustar pxeles para tamao y posin. Pueder poner el transform.localScale a Vector3.zero para hacer que la GUI texture siempre tenga el mismo tamao de pxeles. Reeditemos una vez ms nuestro script: transform.position = Vector3.zero; transform.localScale = Vector3.zero; guiTexture.pixelInset = Rect (100, 25, 180, 180); Antes de darle al play expliquemos lo que hemos hecho. Primero colocamos el transform de nuestra GUITexture en el centro de la escena. Acto seguido colocamos la escala del transform a cero para que tenga el tamao que posteriormente le indiquemos, sin ningn tipo de variacin. Acto seguido encuadramos la textura dentro de un rectngulo situado a 100 pxeles desde la izquierda y 25 desde arriba, con una anchura y altura de 180 pxeles. Dadle al play.

30. CLASE GUI

Bueno. Hasta ahora nos hemos centrado en estudiar las clases que conformaban el rbol de herencia que ocupa buena parte de la API de Unity. Hemos ido repasndolas (casi) todas, ms o menos en orden. A partir de ahora, en cambio, vamos a recorrer clases que no estn vinculadas por relacin de herencia alguna con las ya explicadas (salvo alguna excepcin, que anunciaremos como tal cuando corresponda). Por tanto la cuestin del orden en su estudio obedecer a criterios un poco ms liviamos, como su mayor o menor importancia o su vinculacin funcional con la clase que se haya estudiado con anterioridad. En base a ese ltimo criterio, y dado que las tres ltimas clases estaban relacionadas con la inferfaz grfica de usuario, vamos a dedicar las siguientes lecciones a darle unas vueltas a diferentes clases que de una manera u otra estn vinculadas con la GUI. Y, como no poda ser de otra forma, empezamos por la clase GUI, que representa la interfaz de Unity:

VARIABLES DE CLASE: skin: static var skin : GUISkin La skin (que podemos traducir por "piel" o "aspecto") en uso. Cambiando esta variable podemos cambiar el look de nuestra GUI. Si su valor es null, se muestra la skin que est por defecto. Es una instancia de la clase GUISkin, que estudiaremos a continuacin de sta.

color: static var color : Color Color del tintero global de la GUI. Afectar tanto a la parte trasera de los elementos (background) como a los colores del texto que escribamos sobre cualquier superficie. Vamos con el primer ejemplo. Empezamos por eliminar el objeto logoUnity. A continuacin editamos miPrimerScript: function OnGUI() { GUI.color = Color.yellow; GUI.Label (Rect (10, 10, 200, 20), "Esto es una etiqueta"); GUI.Box(Rect(10, 50, 100, 50), "Una caja"); GUI.Button(Rect(10,110,90,50), "Un botn"); } Salvamos y la arrastramos a PortaScripts. Si pulsamos play observaremos algo como esto:

Aqu hemos de explicar varias cosas. Empezando por el final, comprobamos en la imagen que el texto de la GUI, sobre las diferentes superficies, es del color que le hemos indicado a la variable color. Asimismo, los bordes de elementos como el botn adquieren en su parte posterior (background) ese color amarillo. Esa declaracin y las anteriores estn contenidas dentro de una funcin que vimos un poco de puntillas cuando estudiamos la clase MonoBehaviour: la funcin OnGUI renderiza y maneja eventos GUI. Dicho de otra manera, al llamar a esta funcin activamos un evento GUI, que en este caso asigna un color a la letra y luego crea una etiqueta, una caja y un botn.

backgroundColor: static var backgroundColor : Color Color del tintero para todas las partes traseras (background) de los elementos renderizados para la GUI. Dicho de otra manera, esta variable de clase hace parte del trabajo que efectuaba color, ya que colorea el background pero no el texto. Reeditamos miPrimerScript como sigue: function OnGUI() { GUI.backgroundColor = Color.red; GUI.Button(Rect(10,10,70,30), "Mi botn"); } Al darle al play podemos observar que los bordes del botn que hemos creado son de color rojo, color que se acrecienta cuando colocamos el ratn encima. En cambio, el color del texto sigue siendo blanco (el color por defecto) contentColor: static var contentColor : Color

Color de tinta para todo el texto renderizado en la GUI. Esta funcin es la complementaria de la anterior con relacin a color, ya que no afecta al color del background, sino al del texto. Por ejemplo: function OnGUI() { GUI.contentColor = Color.yellow; GUI.backgroundColor = Color.red; GUI.Button(Rect(10,10,70,30), "Mi botn"); } Vemos aqu claramente las diferencias entre ContentColor (amarillo) y backgroundColor (rojo).

changed: static var changed : boolean Devuelve true si algn control cambia el valor de los datos de entrada de la GUI. Podemos aprovechar el ejemplo que aparece en el manual de referencia para ilustrarnos. Editamos miPrimerScript como sigue: var miTexto : String = "Cambiame"; function OnGUI () { miTexto = GUI.TextField (Rect (10, 10, 200, 20), miTexto, 25); if (GUI.changed) Debug.Log("El campo de texto se modific"); } El contenido del script es bastante intuitivo: creamos un campo de texto editable con la funcin TextField, que en breve estudiaremos, y, si procedemos a cambiar su contenido inicial se nos imprimir en pantalla un texto avisndonos de dicha modificacin.

enabled: static var enabled : boolean Habilita/deshabilita la GUI. Si establecemos esta variable en false se deshabilitan todas las interacciones de la GUI. Todos los controles se dibujarn semitransparentes, y no responern a las entradas del usuario.

tooltip: static var tooltip : String Un tooltip es ese pequea nota emergente que aparece a veces con determinada informacin cuando colocamos un ratn sobre un control, o dicho control tiene el foco del teclado. Vamos con el pertinente ejemplo. Abrimos nuestro script y:

function OnGUI () { GUI.Button (Rect (10,10,100,20), GUIContent ("Pulsame", "Este es el tooltip")); GUI.Label (Rect (10,40,100,40), GUI.tooltip); } El script funciona de la siguiente manera: Como viene siendo habitual, empezamos creando un evento GUI con la funcin OnGUI. Acto seguido creamos un botn con una determinada ubicacin y dimensiones, y le pasamos como segundo parmetro la funcin constructora de la clase GUIContent (de cercano estudio), que a su vez admite como parmetros el texto del botn, una imagen (en este caso no) y en su caso el texto del tooltip que se deba activar al pasarle el ratn por encima. Acto seguido hemos de crear propiamente la etiqueta del tooltip, indicando su ubicacin y dimensiones. Al darle al play y colocar el ratn sobre el botn, automticamente nos aparecer un tooltip con el texto indicado, que desaparecer al retirar el ratn de dicho control.

depth: static var depth : int El orden de profundidad que tendr cada actividad GUI en ejecucin. Quiere esto decir que cuando tengamos varios scripts ejecutndose simultneamente, los elementos GUI que tengan valores de profundidad ms bajos aparecern en la pantalla encima de los que lo tengan ms altos.

FUNCIONES DE CLASE: label: static function Label (position : Rect, text : String) : void static function Label (position : Rect, image : Texture) : void static function Label (position : Rect, content : GUIContent) : void static function Label (position : Rect, text : String, style : GUIStyle) : void static function Label (position : Rect, image : Texture, style : GUIStyle) : void static function Label (position : Rect, content : GUIContent, style : GUIStyle) : void Crea una etiqueta (label) de texto o de imagen en la pantalla. Como podemos observar, esta funcin tiene varios prototipos, permitindonos pasarle distintos parmetros en base a la necesidad y datos que tengamos en cada momento. Dichos parmetros seran: position text image content style Rectangulo en la pantalla a usar para la etiqueta. Texto a mostrar en la etiqueta. Textura/imagen a mostrar en la etiqueta. Texto, imagen y tooltip para esta etiqueta. El estilo a usar. Si no se indica, se aplicar el estilo para etiquetas que tenga el GUISking que se est usando.

En base al significado de estos parmetros, podemos fcilmente deducir la diferencia entre los distintos prototipos de esta funcin. Las etiquetas o labels en s no implican ningn tipo de interaccin con el usuario, no captan clicks del ratn y son siempre renderizadas en un estilo normal (no por ejemplo como los botones, que aparte del estilo normal tienen otro para cuando se pasa el ratn por encima, otro cuando se presionan, o cuando se activan, etc). Pongamos el ms sencillo de los ejemplos: mostremos en pantalla el famoso hello world.

function OnGUI () { GUI.Label (Rect (10, 10, 100, 20), "Hello World"); } Como vemos, hemos optado por el primer prototipo de la funcin de los que mostramos al inicio. Meramente el rectngulo con la posicin (10,10) y tamao (100,20) del rectngulo donde ubicaremos la etiqueta, y como segundo parmetro un string con el texto. Si en lugar de mostrar un texto quisiramos hacer lo propio con una imagen, modificaramos la funcin como sigue: var unaTextura : Texture2D; function OnGUI () { GUI.Label (Rect (10, 40, unaTextura.width, unaTextura.height), unaTextura); } Salvamos y arrastramos la textura que tenamos en la carpeta assets de ejemplos anteriores a la variable expuesta de este script que tenemos vinculado a PortaScripts. En este prototipo de nuevo pasamos como parmetro primero un rectngulo con la posicin del rectngulo (10,40) y, en lugar de indicar directamente las dimensiones que ha de tener dicho rectngulo, aprovechamos la anchura y altura originales de la imagen arrastrada para no recortarla (aunque por supuesto podemos sentirnos libres de establecer unas dimensiones fijas). El segundo parmetro es donde difiere este prototipo del anterior, ya que en lugar de suministrar un string pasamos una textura.

DrawTexture: static function DrawTexture (position : Rect, image : Texture, scaleMode : ScaleMode = ScaleMode.StretchToFill, alphaBlend : boolean = true, imageAspect : float = 0) : void Dibuja una textura dentro de un rectngulo. Tiene los siguientes parmetros: position image scaleMode alphaBlend imageAspect Rectngulo en la pantalla para dibujar la textura dentro. Textura a mostrar. Cmo escalar la imagen cuando la proporcin hace que no encaje bien dentro del rectngulo. Si el canal alfa es mezclado en la imagen (por defecto) Proporcin a usar para la imagen fuente. Si vale 0 (por defecto), es usada la proporcin de la imagen. Pasad un w/h para la deseada proporcin, lo cual permite cambiar la proporcin de la imagen original sin cambier la anchura y altura de pxeles.

El parmetro scaleMode es a su vez una enumeracin que acepta los siguientes valores: StretchToFill ScaleAndCrop ScaleToFit Estira la textura para rellenar el rectangulo entero. Escala la textura, manteniendo la proporcin, hasta cubrir completamente el rectngulo. Si la textura se dibuja en un rectngulo con una proporcin diferente, la imagen se recorta. Escala la textura, manteniendo la proporcin, hasta encajar completamente dentro del rectngulo.

Vamos ahora a dibujar una textura en la esquina izquierda de la pantalla, textura que se dibujar en una ventana de 60 x 60 pxeles. A la textura original le daremos una proporcin de 10 x 1 y la haremos encajar luego en el rectngulo anterior con el Scalemode.ScaleToFit, de tal manera que la textura se escalar hasta encajar horizontalmente con el rectngulo, manteniendo la proporcin de 10/1. function OnGUI() { }

GUI.DrawTexture(Rect(10,10,60,60), aTexture, ScaleMode.ScaleToFit, true, 10.0f); }

Box: static function Box (position : Rect, text : String) : void static function Box (position : Rect, image : Texture) : void static function Box (position : Rect, content : GUIContent) : void static function Box (position : Rect, text : String, style : GUIStyle) : void static function Box (position : Rect, image : Texture, style : GUIStyle) : void static function Box (position : Rect, content : GUIContent, style : GUIStyle) : void Como su nombre indica, crea un cuadro o caja. Sus diferentes prototipos cuentan con estos parmetros: Position text image content style Rectngulo en la pantalla a usar para la caja. Texto a mostrar en la caja. Textura a mostrar en la caja. Texto, imagen y tooltip para la caja. El estilo a usar. Si no se indica expresamente, el estilo de la caja ser el del GUISkin en uso.

Pongamos un ejemplo sencillo: function OnGUI() { GUI.Box(Rect(10,20,100,40),"Hola, mundo"); }

Button: static function Button (position : Rect, text : String) : boolean static function Button (position : Rect, image : Texture) : boolean static function Button (position : Rect, content : GUIContent) : boolean static function Button (position : Rect, text : String, style : GUIStyle) : boolean static function Button (position : Rect, image : Texture, style : GUIStyle) : boolean static function Button (position : Rect, content : GUIContent, style : GUIStyle) : boolean Funcin que crea un botn que, al ser pulsado por un usuario, dispara algn tipo de evento. Una cosa que puede llamar la atencin inicialmente, y que tiene mucho que ver con la manera un poco atpica de usar esta funcin, es que retorna un booleano que es establecido en true cuando el usuario hace click sobre el botn. De esta suerte, la funcin devolver false hasta que se pulse el botn, lo que implica en la prctica que esta funcin se suele usar tras una declaracin if, como enseguida veremos. Antes detengmonos un momento en los parmetros, que ya nos deberan sonar: position text image content style Rectangulo en la pantalla a usar para el botn. Texto a mostrar en el botn. Textura/imagen a mostrar en el botn. Texto, imagen y tooltip para este botn. El estilo a usar. Si no se indica, se aplicar el estilo para botones que tenga el GUISking que se est usando.

Y ahora es el momento de entender con un ejemplo lo que os comentaba antes sobre la peculiar manera de usar la funcin button:

var unaTextura : Texture; function OnGUI() { if (!unaTextura) { Debug.LogError("Asigne por favor una textura en el inspector"); return; } if (GUI.Button(Rect(10,10,50,50),unaTextura)) Debug.Log("Has hecho click en el botn que tiene una imagen"); if (GUI.Button(Rect(10,70,50,30),"Click")) Debug.Log("Has hecho click en el botn con texto"); } Vamos por partes. Salvamos el script y, sin arrastrar ninguna textura a la variable expuesta que nos debera aparecer en el inspector al tener PortaScripts seleccionado, pulsamos play. Nos aparecer un mensaje de error avisndonos de que debemos arrastrar dicha textura. Es esta una variande de Debug.Log llamada Debug.LogError, que hace que el mensaje aparezca en rojo. Detenemos el reproductor, arrastramos la textura y volvemos a pulsar play. Observaremos que nos aparecen dos botones, uno con la textura arrastrada por nosotros, otros con el texto indicado, y que al pulsarlos aparecen en pantalla sendos textos. Lo que personalmente me parece ms interesante de todo esto es la manera de utilizar la funcin: if (GUI.Button(Rect(10,70,50,30),"Click")) Pensemos que con esta declaracin estamos haciendo dos cosas: primero, al pasarla como condicin de if nos aseguramos de que una vez el user clicke el botn y por ende la funcin Button devuelva true, se ejecutar las declaraciones que se vean afectadas por ese if. Pero, adems, previo a devolver true o false, Unity ejecuta la funcin, y por consiguiente se renderiza el botn en la pantalla.

RepeatButton: static function RepeatButton (position : Rect, text : String) : boolean static function RepeatButton (position : Rect, image : Texture) : boolean static function RepeatButton (position : Rect, content : GUIContent) : boolean static function RepeatButton (position : Rect, text : String, style : GUIStyle) : boolean static function RepeatButton (position : Rect, image : Texture, style : GUIStyle) : boolean static function RepeatButton (position : Rect, content : GUIContent, style : GUIStyle) : boolean Funcin que crea un botn que est activo mientras el usuario lo presiona.

TextField: static function TextField (position : Rect, text : String) : String static function TextField (position : Rect, text : String, maxLength : int) : String static function TextField (position : Rect, text : String, style : GUIStyle) : String static function TextField (position : Rect, text : String, maxLength : int, style : GUIStyle) : String Crea un campo de texto de una lnea donde el usuario puede editar un string. Devuelve un string con el texto editado. Tiene estos parmetros:

position text maxLength style

Rectngulo en la pantalla a usar para el campo de texto. Texto a editar. El valor de retorno debe ser reasignado de vuelta al string tal como se ensea en el prximo ejemplo. La longitud mxima del string. Si no se indica, el usuario puede escribir sin ningn tipo de lmite. El estilo a usar. Si no se indica, se aplicar el estilo para textField que tenga el GUISkin en uso.

Esta funcin es importante porque permite una mayor interactividad con el usuario que meramente pulsar determinamos botones. Por ello es importante que el texto que dicho usuario introduce se almacene debidamente. Tal como indica el manual de referencia al hablar del parmetro text, la solucin ideal es inicializar una variable string con el valor que le damos por defecto, y reutilizar dicha variable para posteriormente contener el string ya modificado y devuelto por la funcin. En definitiva: var mensaje : String = "Escribe algo"; function OnGUI () { mensaje = GUI.TextField (Rect (10, 10, 200, 20), mensaje, 25); Debug.Log(mensaje); } Como veis, la idea es que "mensaje" sirva tanto para contener el string inicial como el modificado. Le he aadido a continuacin un Debug.Log para que comprobis en tiempo real cmo va cambiando el contenido de la variable.

PasswordField: static function PasswordField (position : Rect, password : String, maskChar : char) : String static function PasswordField (position : Rect, password : String, maskChar : char, maxLength : int) : String static function PasswordField (position : Rect, password : String, maskChar : char, style : GUIStyle) : String static function PasswordField (position : Rect, password : String, maskChar : char, maxLength : int, style : GUIStyle) : String Crea un campo de texto donde el usuario puede introducir una contrasea. Devuelve un string con la contrasea editada. Cuenta con los siguientes parmetros: position password maskChar maxLength style Rectngulo en la pantalla a usar para el campo de texto. Contrasea a editar. El valor de retorno de esta funcin debe ser reasignado al string que contena el valor original. El carcter con el que queremos enmascarar la contrasea. La longitud mxima del string. Si no se indica, el usuario no tendr lmite para escribir. El estilo a usar. Si no se indica, se usar el estilo para textfield que tenga el GUISkin que se est usando.

Podemos apreciar que en definitiva esta funcin es como la anterior, con la salvedad de que en la presente le aadimos un carcter (tradicionalmente un asterisco) que queremos que aparezca en pantalla cuando el usuario teclee su contrasea. var miPin : String = ""; function OnGUI () { miPin = GUI.PasswordField (Rect (10, 10, 200, 20), miPin, "*"[0], 25); }

TextArea: static function TextArea (position : Rect, text : String) : String static function TextArea (position : Rect, text : String, maxLength : int) : String static function TextArea (position : Rect, text : String, style : GUIStyle) : String static function TextArea (position : Rect, text : String, maxLength : int, style : GUIStyle) : String Crea un rea de texto de varias lneas donde el usuario puede editar un string. Devuelve el string editado.

SetNextControlName: static function SetNextControlName (name : String) : void Funcin que establece el nombre del siguiente control. Esto hace que el siguiente control sea registrado con un nombre dado.

GetNameOfFocusedControl: static function GetNameOfFocusedControl () : String Obtiene el nombre del control que tiene el foco. El nombre de los controles es asignado usando SetNextControlName. Cuando un control tiene el foco, esta funcin devuelve su nombre. GetNameOfFocusedControl funciona especialmente bien cuando tratamos con ventanas para loguearse.

FocusControl: static function FocusControl (name : String) : void Mueve el foco del teclado a un control nombrado.

Toggle: static function Toggle (position : Rect, value : boolean, text : String) : boolean static function Toggle (position : Rect, value : boolean, image : Texture) : boolean static function Toggle (position : Rect, value : boolean, content : GUIContent) : boolean static function Toggle (position : Rect, value : boolean, text : String, style : GUIStyle) : boolean static function Toggle (position : Rect, value : boolean, image : Texture, style : GUIStyle) : boolean static function Toggle (position : Rect, value : boolean, content : GUIContent, style : GUIStyle) : boolean Crea un botn de tipo interruptor (on/off). Devuelve el nuevo valor del botn(true/false).

Toolbar: static function Toolbar (position : Rect, selected : int, texts : string[]) : int static function Toolbar (position : Rect, selected : int, images : Texture[]) : int static function Toolbar (position : Rect, selected : int, content : GUIContent[]) : int static function Toolbar (position : Rect, selected : int, texts : string[], style : GUIStyle) : int static function Toolbar (position : Rect, selected : int, images : Texture[], style : GUIStyle) : int static function Toolbar (position : Rect, selected : int, contents : GUIContent[], style : GUIStyle) : int

Funcin que crea una barra de herramientas. Devuelve -un int- el ndice de la toolbar seleccionado. Tiene estos parmetros: position selected texts images contents style Rectngulo en la pantalla a usar para la barra de herramientas. El ndice del botn seleccionado. Un array de strings a ensear en los botones de la barra. Un array de textras para los botones de la barra de herramientas. Un array de texto, imgenes y tooltips para los botones del toolbar. El estilo a usar. Si no se indica, se usar el estilo para botones que tenga la GUISkin que se est usando.

Vemoslo con un ejemplo: var toolbarIndice : int = 0; var toolbarStrings : String[] = ["Toolbar1", "Toolbar2", "Toolbar3"]; function OnGUI () { toolbarIndice = GUI.Toolbar (Rect (25, 25, 250, 30), toolbarIndice, toolbarStrings); Debug.Log("El ndice pulsado es " + toolbarIndice); } Observaremos que nos aparece en pantalla al pulsar play una barra con tres botones, estando por defecto activado el primero, que corresponde con el ndice cero que le hemos pasado como parmetro. Le hemos aadido la funcin Debug.Log para acreditar que al presionar los distintos botones se le asigna a la variable el ndice de cada botn.

SelectionGrid: static function SelectionGrid (position : Rect, selected : int, texts : string[], xCount : int) : int static function SelectionGrid (position : Rect, selected : int, images : Texture[], xCount : int) : int static function SelectionGrid (position : Rect, selected : int, content : GUIContent[], xCount : int) : int static function SelectionGrid (position : Rect, selected : int, texts : string[], xCount : int, style : GUIStyle) : int static function SelectionGrid (position : Rect, selected : int, images : Texture[], xCount : int, style : GUIStyle) : int static function SelectionGrid (position : Rect, selected : int, contents : GUIContent[], xCount : int, style : GUIStyle) : int Hace una cuadrcula (grid) de botones. Devuelve un int con el ndice del botn seleccionado. Permite los siguientes parmetros: position selected texts images contents xCount style Rectndulo de la pandalla a usar para la cuadrcula. El ndice del botn seleccionado de la cuadrcula. Un array de strings que mostrar en los botones de la cuadrcula. Un array de texturas en los botones de la cuadrcula. Un array de texto, imgenes y tooltips para los botones de la cuadrcula Cuntos elementos caben en la direccin horizontal. Los controles sern escalados para encajar a meno que el estilo elegido para usar sea fixedWidth. El estilo a usar. Si no se indica, se usa el estilo de botn marcado por el GUISkin que se est usando.

Veamos un breve ejemplo: var selGridInt : int = 0; var selStrings : String[] = ["Grid 1", "Grid 2", "Grid 3", "Grid 4"];

function OnGUI () { selGridInt = GUI.SelectionGrid (Rect (25, 25, 100, 30), selGridInt, selStrings, 2); }

HorizontalSlider: static function HorizontalSlider (position : Rect, value : float, leftValue : float, rightValue : float) : float static function HorizontalSlider (position : Rect, value : float, leftValue : float, rightValue : float, slider : GUIStyle, thumb : GUIStyle) : float Crea una barra de desplazamiento horizontal que el usuario puede arrastrar para cambiar un valor entre un mnimo y un mximo. Devuelve un float con el valor que ha sido elegido por el usuario. Parmetros: position value leftValue rightValue slider thumb Rectngulo en la pantalla a usar para la barra. El valor que muestra la barra. Esto determina la posicin del deslizable mvil. El valor del extremo izquierdo de la barra. El valor del extremo derecho de la barra. El GUIStyle a usar para mostrar el rea de arrastre. Si no se utiliza, se usar el estilo de horizontalSlider que tenga por defecto el GUISkin que se est usando. El GUIStyle a usar para mostrar el deslizable mvil. Si no se usa, se usar el estilo de horizontalSliderThumb style que tenga por defecto el GUISkin que se est usando.

Y por ltimo el ejemplo: var valorDelSlider : float = 0.0; function OnGUI () { valorDelSlider = GUI.HorizontalSlider (Rect (25, 25, 100, 30), valorDelSlider, 0.0, 10.0); }

VerticalSlider: static function VerticalSlider (position : Rect, value : float, topValue : float, bottomValue : float) : float static function VerticalSlider (position : Rect, value : float, topValue : float, bottomValue : float, slider : GUIStyle, thumb : GUIStyle) : float Crea una barra de deslizamiento vertical que el usuario puede arrastrar para cambiar un valor entre un mnimo y un mximo. Devuelve un float con el valor que ha sido escogido por el usuario. Tiene los siguientes parmetros: position: value: topValue: bottomValue: slider: Rectngulo en la pantalla a usar para la barra. El valor que muestra la barra. Esto determina la posicin del deslizable mvil. El valor en lo alto de la barra El valor en lo bajo de la barra El GUIStyle a usar para mostrar el rea de arrastre. Si no se utiliza, se usar el estilo de verticalSider que tenga por defecto el GUISkin que se est usando.

thumb:

El GUIStyle a usar para mostrar el deslizable mvil. Si no se usa, se usar el estilo de verticalSliderThumb que tenga por defecto el GUISkin que se est usando.

HorizontalScrollbar: static function HorizontalScrollbar (position : Rect, value : float, size : float, leftValue : float, rightValue : float) : float static function HorizontalScrollbar (position : Rect, value : float, size : float, leftValue : float, rightValue : float, style : GUIStyle) : float Crea una barra de desplazamiento (scrollbar) horizontal. Un scrollbar es lo que usamos para desplazarnos por un documento. Por norma general en lugar de scrollbar usaremos scrolliews. Devuelve un float con el valor modificado. Este puede ser cambiado por el usuario arrastrando el scrollbar o clickando en las flechas de los extremos.

Un breve ejemplo: var valorDeBarra : float; function OnGUI () { valorDeBarra = GUI.HorizontalScrollbar (Rect (25, 25, 100, 30), valorDeBarra, 1.0, 0.0, 10.0); }

VerticalScrollbar: static function VerticalScrollbar (position : Rect, value : float, size : float, topValue : float, bottomValue : float, style : GUIStyle) : float Crea una barra de desplazamiento (scrollbar) vertical.

BeginGroup: static function BeginGroup (position : Rect) : void static function BeginGroup (position : Rect, text : String) : void static function BeginGroup (position : Rect, image : Texture) : void static function BeginGroup (position : Rect, content : GUIContent) : void static function BeginGroup (position : Rect, style : GUIStyle) : void static function BeginGroup (position : Rect, text : String, style : GUIStyle) : void static function BeginGroup (position : Rect, image : Texture, style : GUIStyle) : void static function BeginGroup (position : Rect, content : GUIContent, style : GUIStyle) : void Comienza un grupo. Esta funcin debe emparejarse con una llamada a EndGroup. Cuando comenzamos un grupo, el sistema de coordenadas para los controles GUI ser tal que coincidir la coordenada (0,0) con la esquna superior izquierda del grupo. Los grupos pueden ser anidados, estando lo hijos agrupados respecto de sus padres. Esto es muy til cuando movemos un montn de elementos GUI a lo largo de la pantalla. Un caso de uso comn es disear nuestros mens para que encajen en un especfico tamao de pantalla, centrando la GUI en pantallas ms amplias.

Los distintos prototipos de funcin usan estos parmetros: position: text: image: content: Rectngulo en la pantalla a usar para el grupo. Texto a mostrar en el grupo. Textura a mostrar en el grupo. Texto, imagen y tooltip para este grupo. Si el parmetro es proporcionado, cualquier click de ratn es capturado por el grupo y si no se proporciona, no se renderiza ingn bacground y los clicks del ratn son renderizados. El estilo a usar para el background.

style:

Veremos muy claramente la funcionalidad de este mtodo con un ejemplo: function OnGUI () { GUI.BeginGroup (new Rect (Screen.width / 2 -200 , Screen.height / 2 - 150, 400, 300)); GUI.Box (new Rect (0,0,400,300), "Este cuadrado est ahora centrado, y dentro del mismo podemos colocar nuestro men"); GUI.EndGroup (); } Expliquemos pso a paso en qu consiste lo que hemos hecho. Para empezar usamos la funcin BeginGroup para crear un grupo en un rectngulo que se iniciar en el centro de la pantalla. Si lo ubicramos en width/2 el rectngulo quedara desplazado, pues no se estara teniendo en cuenta en este caso la anchura del propio rectngulo. De esta manera, le hemos de restar al centro de la pantalla la mitad de la anchura del rectngulo, asegurndonos as que queda justo en el centro. Hacemos lo propio con la altura. Una vez ya tenemos definido para el grupo un rectngulo centrado con unas dimensiones de 400 X 300, ahora para los controles dentro de dicho grupo la esquina superior izquierda del rectngulo pasa a ser la coordenada 0,0. As, cuando a continuacin invocamos una caja con un texto y la ubicamos en las coordenadas 0,0, sta se nos viene a colocar al inicio del rectngulo del grupo. No hemos de olvidarnos, por ltimo, que si usamos una funcin BeginGroup hemos de usar cuando acabemos de disear el grupo una funcin EndGroup obligatoriamente, para indicarle a Unity que las instrucciones referidas al grupo ya se han acabado.

EndGroup: static function EndGroup () : void Finaliza un grupo.

BeginScrollView: static function BeginScrollView (position : Rect, scrollPosition : Vector2, viewRect : Rect) : Vector2 static function BeginScrollView (position : Rect, scrollPosition : Vector2, viewRect : Rect, alwaysShowHorizontal : boolean, alwaysShowVertical : boolean) : Vector2 static function BeginScrollView (position : Rect, scrollPosition : Vector2, viewRect : Rect, horizontalScrollbar : GUIStyle, verticalScrollbar : GUIStyle) : Vector2 static function BeginScrollView (position : Rect, scrollPosition : Vector2, viewRect : Rect, alwaysShowHorizontal : boolean, alwaysShowVertical : boolean, horizontalScrollbar : GUIStyle, verticalScrollbar : GUIStyle) : Vector2

Inicia una vista de desplazamiento (scrollview) dentro de la GUI. Un scrollview nos permite poner una rea ms pequea en la pantalla dentro de un rea mucho mayor, usando barras de desplazamiento (scrollbars) a los lados. Esta funcin devuelve la posicin del scroll modificada. Al igual que con otras variables, se recomienda reintroducir en la variable que se le pasa a la funcin los datos nuevos que sta devuelve. Tiene estos parmetros: position: scrollPosition: Rectngulo en la pantalla a usar para el ScrollView. La distancia en pxeles que la vista es desplazada en las direcciones X e Y. viewRect: El rectngulo usado dentro del scrollview. alwayShowHorizontal: Parmetro opcional para ensear siempre el scrollbar horizontal. Si lo establecemos en falso o no lo aportamos a la funcin, slo se ensear cuando clientRect sea ms ancho que la posicin. alwayShowVertical: Lo mismo para el scrollbar vertical. horizontalScrollbar: GUIStyle opcional a usar por el scrollbar horizontal. Si no se aporta, se usar el estilo horizontalScrollbar del GUISkin que se est usando. verticalScrollbar: Lo mismo para el scrollbar vertical

EndScrollView: static function EndScrollView () : void Acaba un scrollview iniciado con una llamada a BeginScrollView.

ScrollTo: static function ScrollTo (position : Rect) : void Desplaza todos los scrollviews incluidos para tratar de hacer visible una determinada posicin.

Window: static function Window (id : int, clientRect : Rect, func : WindowFunction, text : String) : Rect static function Window (id : int, clientRect : Rect, func : WindowFunction, image : Texture) : Rect static function Window (id : int, clientRect : Rect, func : WindowFunction, content : GUIContent) : Rect static function Window (id : int, clientRect : Rect, func : WindowFunction, text : String, style : GUIStyle) : Rect static function Window (id : int, clientRect : Rect, func : WindowFunction, image : Texture, style : GUIStyle) : Rect static function Window (id : int, clientRect : Rect, func : WindowFunction, title : GUIContent, style : GUIStyle) : Rect Crea una ventana emergente y devuelve el rectngulo en el que dicha ventana se ubica. Las ventanas flotan sobre los controles GUI normales, Windows float above normal GUI controls, y pueden ser opcionalmente arrastrados por los usuarios finales. A diferencia de otros controles, necesitamos pasarles una funcin separada para los controles GUI para colocarlos dentro de la ventana. Nota: Si usamos GUILayout (de prxima explicacin) para colocar nuestros componentes dentro de la ventana, debemos usar GUILayout.Window. Parmetros:

id: clientRect: func: text: image: content: style:

Una ID nica a usar para cada ventana. Rectngulo en la pantalla a usar por el grupo. La funcin que crea el GUI dentro de la ventana. Esta funcin debe tomar un parmetro, que ser la ID de la ventana para la que se est creando la GUI. Texto a mostrar como ttulo para la ventana. Textura que muestra una imagen en la barra del ttulo. Texto, imagen y tooltip para esta ventana. Un estilo opcional a usar por la ventana. Si no se aporta, se usar el estilo de ventana del GUISkin corriente.

Y vamos con un ejemplo: var windowRect : Rect = Rect (20, 20, 120, 50); function OnGUI () { windowRect = GUI.Window (0, windowRect, CreaMiVentana, "Mi ventana"); } function CreaMiVentana (windowID : int) { if (GUI.Button (Rect (10,20,100,20), "Hola mundo")) print ("Recib un click"); } Creamos una ventana con ID 0, que ubicamos en un rectngulo cuyas coordenadas y dimensiones estn almacenadas en una variable, variable en la cual almacenaremos el rectngulo retornado por la funcin. Como tercer parmetro le pasamos una funcin que es la que crea los controles que irn dentro de la ventana, y por ltimo el ttulo de dicha ventana. La funcin que crea los controles toma como parmetro a su vez el primer parmetro de GUI.Window, que es la id de la ventana, y en este caso meramente creamos un botn con un texto, que al ser pulsado imprime un mensaje en plantalla.

DragWindow: static function DragWindow (position : Rect) : void Crea una ventana que puede arrastrarse. Si llamamos a esta funcin dentro del cdigo de la ventana, automticamente sta podr arrastrarse. Le hemos de pasar a la funcin un parmetro que indica la parte de la ventana que puede ser arrastrada, dando un rectngulo que recorta la ventana original. Para constatar lo que estoy diciendo, slo tenis que aadir esta lnea a la funcin CreaMiVentana del ejemplo anterior: GUI.DragWindow (Rect (0,0, 100, 20)); Pensad que 0,0 viene referido a la ventana emergente, no a las coordenadas generales. static function DragWindow () : void Esta funcin tiene un segundo prototipo que no requiere parmetros. Si queremos que nuestra ventana pueda ser arrastrada desde cualquier parte del background de la misma, es preferible utilizar esta forma de la funcin y colocarla al final de las funciones de la ventana. As, si modificamos esta parte del script: function CreaMiVentana (windowID : int) { if (GUI.Button (Rect (10,20,100,20), "Hola mundo"))

print ("Recib un click"); GUI.DragWindow (); } podremos arrastrar nuestra ventana emergente desde cualquier punto de sta.

BringWindowToFront: static function BringWindowToFront (windowID : int) : void Trae una ventana determinada al frente del resto de ventanas flotantes. Tiene como nico parmetro la ID de la ventana que queremos poner en primer plano.

BringWindowToBack: static function BringWindowToBack (windowID : int) : void Coloca una ventana determinada al fondo de las ventanas flotantes.

FocusWindow: static function FocusWindow (windowID : int) : void Hace que una ventana se convierta en la ventana activa. Se le pasa como parmetro la ID de dicha ventana.

UnFocusWindow: static function UnfocusWindow () : void Quita el foco de todas las ventanas.

31. CLASE GUILAYOUT

Esta clase es la interfaz para la gui de Unity con distribucin automtica. Me explico: Hay dos maneras que podemos usar para organizar y distribuir nuestras interfaces grficas de usuario: fija y automtica. Hasta ahora hemos trabajado con la clase GUI, que es la forma fija de distribucin. Esto entraa que cada vez que se crea un nuevo elemento o control, se le ubica en un punto concreto (casi siempre a travs de un Rect). En cambio, con la forma automtica de distribucin (que es la que permite la clase GUILayout) esto no es necesario. Se pueden usar ambos modos en la misma funcin OnGUI(). El modo fijo de distribucin se suele usar cuando tenemos una interfaz prediseada con la que trabajamos. El modo automtico en cambio se suele usar cuando no sabemos cuntos elementos acabaremos necesitando, o no queremos preocuparnos de colocar a mano cada control. Hay dos diferencias a tener en cuenta cuando usamos distribucin automtica: 1.- Hemos de usar GUILayout en lugar de GUI. 2.- Para la distribucin automtica no se usa la funcin Rect().

FUNCIONES DE CLASE: Label: static function Label (image : Texture, params options : GUILayoutOption[]) : void static function Label (text : String, params options : GUILayoutOption[]) : void static function Label (content : GUIContent, params options : GUILayoutOption[]) : void static function Label (image : Texture, style : GUIStyle, params options : GUILayoutOption[]) : void static function Label (text : String, style : GUIStyle, params options : GUILayoutOption[]) : void static function Label (content : GUIContent, style : GUIStyle, params options : GUILayoutOption[]) : void Hace una etiqueta de distribucin automtico. Las etiquetas no proveen interacin con el usuario, no capturan clicks de ratn y son siempre renderizadas en estilo normal. Si quieres tener un control que responda visualmente a las entradas de usuario usa un box control. Todos los parmetros menos uno son idnticos a los de la funcin homnima de la clase GUI, as que a ellos me remito. Pero quiero detenerme en ese parmetro distinto, que de hecho es el que marca la diferencia entre la distribucin fija (mediante Rect() y la automtica. Me estoy refiriendo al parmetro params option, que es de tipo GUILayoutOption. GUILayoutOption es una clase internamente usada por Unity para pasar diferentes opciones de distribucin en las funciones de la clase GUILayout. No se usa directamente, sino a travs de funciones de tipo GUILayout, como por ejemplo: GUILayout.Width, GUILayout.Height, GUILayout.MinWidth, GUILayout.MaxWidth, GUILayout.MinHeight, GUILayout.MaxHeight, GUILayout.ExpandWidth y GUILayout.ExpandHeight. Ms adelante en esta clase estudiaremos dichas funciones.

Box: static function Box (image : Texture, params options : GUILayoutOption[]) : void static function Box (text : String, params options : GUILayoutOption[]) : void static function Box (content : GUIContent, params options : GUILayoutOption[]) : void static function Box (image : Texture, style : GUIStyle, params options : GUILayoutOption[]) : void static function Box (text : String, style : GUIStyle, params options : GUILayoutOption[]) : void static function Box (content : GUIContent, style : GUIStyle, params options : GUILayoutOption[]) : void crea una caja de distribucin automtica. Si queremos crear una caja con algn contenido dentro, hemos de usar el parmetro de estilo de uno de los subgrupos de funciones (BeginHorizontal, BeginVertical, etc...).

Button: static function Button (image : Texture, params options : GUILayoutOption[]) : boolean static function Button (text : String, params options : GUILayoutOption[]) : boolean static function Button (content : GUIContent, params options : GUILayoutOption[]) : boolean static function Button (image : Texture, style : GUIStyle, params options : GUILayoutOption[]) : boolean static function Button (text : String, style : GUIStyle, params options : GUILayoutOption[]) : boolean static function Button (content : GUIContent, style : GUIStyle, params options : GUILayoutOption[]) : boolean Crea un botn con distribucin automtica qevuelve true cuando el usuario lo presiona.

RepeatButton: static function RepeatButton (image : Texture, params options : GUILayoutOption[]) : boolean static function RepeatButton (text : String, params options : GUILayoutOption[]) : boolean static function RepeatButton (content : GUIContent, params options : GUILayoutOption[]) : boolean static function RepeatButton (image : Texture, style : GUIStyle, params options : GUILayoutOption[]) : boolean static function RepeatButton (text : String, style : GUIStyle, params options : GUILayoutOption[]) : boolean static function RepeatButton (content : GUIContent, style : GUIStyle, params options : GUILayoutOption[]) : boolean Crea un botn que devuelve true tanto tiempo como el usuario lo mantiene pulsado.

TextField: static function TextField (text : String, params options : GUILayoutOption[]) : String static function TextField (text : String, maxLength : int, params options : GUILayoutOption[]) : String static function TextField (text : String, style : GUIStyle, params options : GUILayoutOption[]) : String static function TextField (text : String, maxLength : int, style : GUIStyle, params options : GUILayoutOption[]) : String Crea un campo de texto de una linea donde el usuario puede editar un string.

PasswordField: static function PasswordField (password : String, maskChar : char, params options : GUILayoutOption[]) : String static function PasswordField (password : String, maskChar : char, maxLength : int, params options : GUILayoutOption[]) : String static function PasswordField (password : String, maskChar : char, style : GUIStyle, params options : GUILayoutOption[]) : String

static function PasswordField (password : String, maskChar : char, maxLength : int, style : GUIStyle, params options : GUILayoutOption[]) : String Crea un campo de texto donde el usuario puede entrar una contrasea. Devuelve la contrasea editada.

TextArea: static function TextArea (text : String, params options : GUILayoutOption[]) : String static function TextArea (text : String, maxLength : int, params options : GUILayoutOption[]) : String static function TextArea (text : String, style : GUIStyle, params options : GUILayoutOption[]) : String static function TextArea (text : String, maxLength : int, style : GUIStyle, params options : GUILayoutOption[]) : String Crea un campo de texto multilnea donde el user puede editar un string, y devuelve dicho string.

Toggle: static function Toggle (value : boolean, image : Texture, params options : GUILayoutOption[]) : boolean static function Toggle (value : boolean, text : String, params options : GUILayoutOption[]) : boolean static function Toggle (value : boolean, content : GUIContent, params options : GUILayoutOption[]) : boolean static function Toggle (value : boolean, image : Texture, style : GUIStyle, params options : GUILayoutOption[]) : boolean static function Toggle (value : boolean, text : String, style : GUIStyle, params options : GUILayoutOption[]) : boolean static function Toggle (value : boolean, content : GUIContent, style : GUIStyle, params options : GUILayoutOption[]) : boolean Crea un botn que alterna on/off. Devuelve un booleano que indica el estado de dicho botn

Toolbar: static function Toolbar (selected : int, images : Texture[], params options : GUILayoutOption[]) : int static function Toolbar (selected : int, content : GUIContent[], params options : GUILayoutOption[]) : int static function Toolbar (selected : int, texts : string[], style : GUIStyle, params options : GUILayoutOption[]) : int static function Toolbar (selected : int, images : Texture[], style : GUIStyle, params options : GUILayoutOption[]) : int static function Toolbar (selected : int, contents : GUIContent[], style : GUIStyle, params options : GUILayoutOption[]) : int Crea un toolbar (barra de herramientas). Devuelve un int que contiene el ndice del botn seleccionado.

SelectionGrid: static function SelectionGrid (selected : int, texts : string[], xCount : int, params options : GUILayoutOption[]) : int static function SelectionGrid (selected : int, images : Texture[], xCount : int, params options : GUILayoutOption[]) : int static function SelectionGrid (selected : int, content : GUIContent[], xCount : int, params options : GUILayoutOption[]) : int static function SelectionGrid (selected : int, texts : string[], xCount : int, style : GUIStyle, params options : GUILayoutOption[]) : int static function SelectionGrid (selected : int, images : Texture[], xCount : int, style : GUIStyle, params options : GUILayoutOption[]) : int static function SelectionGrid (selected : int, contents : GUIContent[], xCount : int, style : GUIStyle, params options : GUILayoutOption[]) : int

Crea una cuadrcula de seleccin, devolviendo el int con el ndice del botn seleccionado.

HorizontalSlider: static function HorizontalSlider (value : float, leftValue : float, rightValue : float, params options : GUILayoutOption[]) : float static function HorizontalSlider (value : float, leftValue : float, rightValue : float, slider : GUIStyle, thumb : GUIStyle, params options : GUILayoutOption[]) : float Crea una barra de desplazamiento horizontal que el usuario puede arrastrar desde un mnimo hasta un mximo. Devuelve un float con el valor que ha sido escogido por el usuario.

VerticalSlider: static function VerticalSlider (value : float, leftValue : float, rightValue : float, params options : GUILayoutOption[]) : float static function VerticalSlider (value : float, leftValue : float, rightValue : float, slider : GUIStyle, thumb : GUIStyle, params options : GUILayoutOption[]) : float Crea una barra de desplazamiento vertical que el usuario puede arrastrar desde un mnimo hasta un mximo.

HorizontalScrollbar: static function HorizontalScrollbar (value : float, size : float, leftValue : float, rightValue : float, params options : GUILayoutOption[]) : float static function HorizontalScrollbar (value : float, size : float, leftValue : float, rightValue : float, style : GUIStyle, params options : GUILayoutOption[]) : float Crea un scrollbar horizontal. Devuelve el valor modificado en float, que puede ser cambiado por el usuario arrastrando el scrollbar o haciendo click en las flechas al final.

VerticalScrollbar: static function VerticalScrollbar (value : float, size : float, topValue : float, bottomValue : float, params options : GUILayoutOption[]) : float static function VerticalScrollbar (value : float, size : float, topValue : float, bottomValue : float, style : GUIStyle, params options : GUILayoutOption[]) : float Crea un scrollbar vertical.

Space: static function Space (pixels : float) : void Inserta un espacio en el actual grupo de distribucin. La direccin de dicho espacio depender del la direccin del grupo de distribucin en el que estemos trabajando. Si por ejemplo se trata de un grupo vertical, el espacio ser vertical. Observemos la diferencia con dos ejemplos:

function OnGUI () { GUILayout.Button ("Primer botn"); GUILayout.Space (20); GUILayout.Button ("Segundo botn"); } Si ejecutamos este primer script, observaremos dos botones situados uno encima del otro, con un espacio (vertical) entre ambos de 20 pxeles. En cambio, si estuviramos trabajando con un grupo de distribucin horizontal... function OnGUI () { GUILayout.BeginHorizontal(); GUILayout.Button ("Primer botn"); GUILayout.Space (20); GUILayout.Button ("Segundo botn"); GUILayout.EndHorizontal(); } ... nos encontraramos con un botn al lado del otro separados por un espacio (horizontal) de 20 pxeles. (En breve estudiaremos las funciones BeginHorizontal y EndHorizontal, aunque supongo que se intuye su cometido)

FlexibleSpace: static function FlexibleSpace () : void Inserta un elemento de espacio flexible. Esta funcin utiliza cualquier espacio que sobra en un diseo.

BeginHorizontal: static function BeginHorizontal (params options : GUILayoutOption[]) : void static function BeginHorizontal (style : GUIStyle, params options : GUILayoutOption[]) : void static function BeginHorizontal (text : String, style : GUIStyle, params options : GUILayoutOption[]) : void static function BeginHorizontal (image : Texture, style : GUIStyle, params options : GUILayoutOption[]) : void static function BeginHorizontal (content : GUIContent, style : GUIStyle, params options : GUILayoutOption[]) : void Empieza un grupo de controles horizontal. Todos los controles dentro de este elemento sern colocados horizontalmente uno junto a otro. El grupo debe cerrarse con una llamada a EndHorizontal.

EndHorizontal: static function EndHorizontal () : void Cierra el grupo abierto por BeginHorizontal.

BeginVertical: static function BeginVertical (params options : GUILayoutOption[]) : void static function BeginVertical (style : GUIStyle, params options : GUILayoutOption[]) : void static function BeginVertical (text : String, style : GUIStyle, params options : GUILayoutOption[]) : void static function BeginVertical (image : Texture, style : GUIStyle, params options : GUILayoutOption[]) : void static function BeginVertical (content : GUIContent, style : GUIStyle, params options : GUILayoutOption[]) : void Empieza un grupo de controles vertical. Todos los controles dentro de este elemento sern situados verticalmente uno

debajo del otro. El grupo debe cerrarse con EndVertical

EndVertical: static function EndVertical () : void Cierra un grupo iniciado por BeginVertical.

BeginArea: static function BeginArea (screenRect : Rect) : void static function BeginArea (screenRect : Rect, text : String) : void static function BeginArea (screenRect : Rect, image : Texture) : void static function BeginArea (screenRect : Rect, content : GUIContent) : void static function BeginArea (screenRect : Rect, style : GUIStyle) : void static function BeginArea (screenRect : Rect, text : String, style : GUIStyle) : void static function BeginArea (screenRect : Rect, image : Texture, style : GUIStyle) : void static function BeginArea (screenRect : Rect, content : GUIContent, style : GUIStyle) : void Comienza un bloque GUILayout de controles GUI en un determinado rea de la pantalla. Por defecto, cualquier control GUI hecho usando GUILayout es situado en la parte superior izquierda de la pantalla. Si queremos colocar una serie de controles en una zona arbitraria, hemos de usar esta funcin para definir un nuevo area. por ejemplo: function OnGUI () { GUILayout.BeginArea (Rect (10,10,100,100)); GUILayout.Button ("Un botn"); GUILayout.Button ("Otro botn"); GUILayout.EndArea (); } Aqu iniciamos un rea de controles ubicada en las coordenadas 10,10 y con unas dimensiones de 100 X 100.

EndArea: static function EndArea () : void Cierra un rea de controles abierto con BeginArea.

BeginScrollView: static function BeginScrollView (scrollPosition : Vector2, params options : GUILayoutOption[]) : Vector2 static function BeginScrollView (scrollPosition : Vector2, alwaysShowHorizontal : boolean, alwaysShowVertical : boolean, params options : GUILayoutOption[]) : Vector2 static function BeginScrollView (scrollPosition : Vector2, horizontalScrollbar : GUIStyle, verticalScrollbar : GUIStyle, params options : GUILayoutOption[]) : Vector2 static function BeginScrollView (scrollPosition : Vector2, style : GUIStyle) : Vector2 static function BeginScrollView (scrollPosition : Vector2, alwaysShowHorizontal : boolean, alwaysShowVertical : boolean, horizontalScrollbar : GUIStyle, verticalScrollbar : GUIStyle, params options : GUILayoutOption[]) : Vector2

static function BeginScrollView (scrollPosition : Vector2, alwaysShowHorizontal : boolean, alwaysShowVertical : boolean, horizontalScrollbar : GUIStyle, verticalScrollbar : GUIStyle, background : GUIStyle, params options : GUILayoutOption[]) : Vector2 Comienza un scrollview (o vista de desplazamiento) automticamente distribudo. Este puede tomar cualquier contenido que le metas dentro y lo muestra normalmente (sin que se vea el scroll). Si no cabe el contenido, aparece la barra. Una llamada a esta funcin debe siempre acabar con una llamada a EndScrollView. Esta funcin devuelve un Vector2 con la posicin del scroll modificada. Cuenta con los siguientes parmetros: scrollPosition: La posicin de uso de la pantalla. alwayShowHorizontal: Parmetro opcional para ensear siempre el scrollbar horizontal. Si est en falso o no se aporta, slo se mostrar el scrollbar cuando el contenido dentro del scrollview sea ms ancho que ste. alwayShowVertical: Lo mismo que el anterior para el scrollbar vertical. horizontalScrollbar: GUIStyle opcional a usar para el scrollbar horizontal. Si no se indica, se usar el estilo de horizontalScrollbar del GUISkin que se est usando. verticalScrollbar Lo mismo pra el scrollbar vertical.

EndScrollView: static function EndScrollView () : void Finaliza un scroll view empezado con una llamada a BeginScrollView.

Window: static function Window (id : int, screenRect : Rect, func : GUI.WindowFunction, text : String, : ) : Rect static function Window (id : int, screenRect : Rect, func : GUI.WindowFunction, image : Texture, : ) : Rect static function Window (id : int, screenRect : Rect, func : GUI.WindowFunction, content : GUIContent, : ) : Rect static function Window (id : int, screenRect : Rect, func : GUI.WindowFunction, text : String, style : GUIStyle, : ) : Rect static function Window (id : int, screenRect : Rect, func : GUI.WindowFunction, image : Texture, style : GUIStyle, : ) : Rect static function Window (id : int, screenRect : Rect, func : GUI.WindowFunction, content : GUIContent, style : GUIStyle, : ) : Rect Crea una ventana emergente que distribuye su contenido automticamente. Las ventanas flotan sobre los controles GUI normales y pueden opcionalmente ser arrastradas por el usuario final. A diferencia de otros controles, necesitas pasarles una funcin separada a los controles GUI para ponerlos dentro de la ventana. Devuelve un rect, que es el rectngulo en el que est la ventana y que puede tener una posicin y tamao diferentes que aqulla.

Width: static function Width (width : float) : GUILayoutOption Opcin pasada a un control para darle una anchura absoluta.

function OnGUI() { GUILayout.Button("Botn con una anchura fija", GUILayout.Width(300)); }

MinWidth: static function MinWidth (minWidth : float) : GUILayoutOption Opcin pasada a un control para especificar una anchura mnima.

MaxWidth: static function MaxWidth (maxWidth : float) : GUILayoutOption Opcin pasada a un control para especificar una anchura mxima.

Height: static function Height (height : float) : GUILayoutOption Opcin pasada a un control para darle una altura absoluta.

MinHeight: static function MinHeight (minHeight : float) : GUILayoutOption Opcin pasada a un control para especificar una altura mnima.

MaxHeight: static function MaxHeight (maxHeight : float) : GUILayoutOption Opcin pasada a un control para especificar una altura mxima.

ExpandWidth: static function ExpandWidth (expand : boolean) : GUILayoutOption Opcin pasada a un control para habilitar o deshabilitar la expansin horizontal.

ExpandHeight: tatic function ExpandHeight (expand : boolean) : GUILayoutOption Opcin pasada a un control para habilitar o deshabilitar la expansin vertical.

32. CLASE TEXTURE

Clase base para el manejo de textures. Contiene funcionalidades que son comuntes tanto en la clase Texture2D como en la clase RenderTexture. VARIABLES: width: Variable de slo lectura que indica la anchura de la textura en pxeles.

height: var height : int Variable de slo lectura que indica la alturade la textura en pxeles.

filterMode: var filterMode : FilterMode Modo de filtrado de la textura. La variable FilterMode es una enumeracin que permite estos valores: Point: bloques Bilinear: Trilinear: Filtrado de puntos, los pxeles de la textura se convierten en de cerca. Filtrado bilinear, las muestras de la textura se promedian. Filtrado trilinear, los pxeles de la textura se promedian y tambin son mezclados entre los niveles del mipmap.

anisoLevel: var anisoLevel : int Nivel de filtro anisotrpico de la textura (anisotropa recordemos que implica que algunas caractersticas del objeto, como la luz, dependen del lugar desde donde ste es observado.) El filtrado anisotrpico hace que las texturas luzcan mejor cuando son vistas en un ngulo bajo, pero a cambio de un importante coste de rendimiento en la tarjeta grfica. Usualmente se usa esto en texturas de suelo, tierra o carreteras para que se vean mejor. El rango de valor de esta variable va de 1 a 9, donde 1 equivale no filtro aplicado y 9 implica filtro totalmente aplicado. A medida que el valor es ms grande, la textura es ms clara en los ngulos bajos.

wrapMode: var wrapMode : TextureWrapMode Modo de envoltura de la textura. Esta puede establecerse en clamp (que podemos traducir por fija o pinzada) o en repear, que "azuleja" la textura en un nmero de repeticiones. renderer.material.mainTexture.wrapMode = TextureWrapMode.Clamp; TextureWrapMode como decimos es una enum con estos valores: Repeat: Clamp: Azuleja la textura, creando un patrn de repeticin. Sujeta la textura al ltimo pixel en el borde de sta.

33. CLASE TEXTURE2D

Es esta una clase para manejo de texturas. Se suele usar para crear texturas "al vuelo" (en tiempo de ejecucin) o para modificar los assets de texturas existentes.

VARIABLES: mipmapCount: var mipmapCount : int Variable de slo lectura que indica cuntos niveles de mipmap hay en la textura. El valor retornado incluye el nivel base tambin, razn por la cual esta variable siempre vale 1 o ms. El conteo de mipmaps se usa en caso de que utilicemos las funciones GetPixels o SetPixels para obtener o modificar respectibamente los diferentes niveles de mipmal. Por ejemplo, podemos querer cambiar una textura de tal manera que cada nivel de mipmap se tinte de un color diferente, y as en el juego veramos cuantos niveles de mipmap son en realidad visibles.

textureFormat: var format : TextureFormat El formato de los datos de los pxeles en la textura (slo lectura).

FUNCIONES: Texture2D: static function Texture2D (width : int, height : int) : Texture2D Crea una nueva textura vaca. Esta tendr un tamao dado por anchura y altura, con un formato de textura ARGV32 y con mipmaps. Normalmente querremos poner los colores de la textura despus de crearla, usando las funciones SetPixel, SetPixels y Apply. function Start () { var nuevaTextura = new Texture2D (128, 128); renderer.material.mainTexture = nuevaTextura; } Este sera el ejemplo bsico. Creamos una nueva textura de dimensiones 128 X 128 y se la asignamos como principal textura al gameobject al que le vinculemos el script. En este caso eliminamos MiPrimerScript del gameobject PortaScripts y se lo vinculamos a la Esfera. Observaremos, si la tenemos seleccionada al darle al play, que sta importa a vuelo la nueva textura, que por defecto es de color negro. static function Texture2D (width : int, height : int, format : TextureFormat, mipmap : boolean) : Texture2D Este segundo prototipo se diferencia del primero en que se le pasa a la funcin como parmetro un determinado formato para la textura y a la vez se indica si se crea con o sin mipmaps.

SetPixel: function SetPixel (x : int, y : int, color : Color) : void Funcin que nos permite indicar el color de los pxeles en las coordenadas que le pasamos. No obstante, para actualizar en realidad el color de dichos pxeles en la tarjeta grfica del usuario, deberemos acto seguido llamar a la funcin Apply. Dado que esta manera de actualizar las texturas consume bastantes recursos, as que sera deseable que cambiramos tantos pxeles como fuera posible entre cada llamada a la funcin Apply. Si tenemos pensado regenerar constantemente texturas en tiempo de ejecucin, puede ser ms rpido generar un array de colores de pxeles y asignarlos todos a la vez con la funcin SetPixels. Esta funcin, por ltimo, trabaja slo con los formatos ARGB32, RGB24 y Alpha8. Para el resto de formatos SetPixel es ignorada. Vamos a verlo con un ejemplo. Previamente sera interesante colocar la cmara en las siguientes coordenadas: position(0,1.5,-6), rotation(10,0,0). As tendremos una mejor visin de lo que le acontecer a la esfera en el prximo script. Editamos MiPrimerScript ahora: function Start () { var nuevaTextura = new Texture2D(128, 128); renderer.material.mainTexture = nuevaTextura; var mitadH : int = nuevaTextura.width/2; var mitadV : int = nuevaTextura.height/2; var unColor : Color = Color.green;

for (var x : int = 0; x < mitadH; x++){ for (var y : int = 0; y < mitadV; y++){ nuevaTextura.SetPixel(x, y, unColor); } } nuevaTextura.Apply(); } Vamos por partes. Creamos primero una nueva textura y se la pasamos al gameobject al que tenemos vinculado el script. Almacenamos acto seguido en sendos integers la mitad de la altura y la anchura de la nueva textura. De esta manera, en un bucle for podemos asignar un determinado color a esa mitad. Recordemos en todo caso dejar la funcin Apply fuera del bucle, a los efectos de no sobrecargar el pc.

GetPixel: function GetPixel (x : int, y : int) : Color Devuelve el color del pxel que se halla en las coordenadas dadas. Si stas estn fuera de los bordes (ms grandes de la anchura/altura o ms pequeas que cero) sern fijadas o repetidas en base al wrapmode de la textura Si quieres leer un bloque amplio de pxeles de una textura, ser ms rpido usar GetPixels, la cual devuelve un bloque entero de colores de pxeles. La textura debe tener activa la variable Is Readable en import settings, ya que de lo contrario fallar la funcin.

GetPixelBilinear: function GetPixelBilinear (u : float, v : float) : Color Devuelve el color de los pxeles filtrado en coordenadas normalizadas (u, v). dichas coordenadas normalizadas u y v van de 0.0 a 1.0, al igual que las coordenadas UV en mallas.

SetPixels: function SetPixels (colors : Color[], miplevel : int = 0) : void Establece un bloque de colores de pxeles. Esta funcin toma un array de colores y cambia los colores de los pxeles del nivel mip entero de la textura. Precisa una posterior llamada a Aply para que los cambios se actualicen en la tarjeta grfica. El array de colores es un array 2d plano, donde los pxeles se distribuyen de izquierda a derecha y de abajo arriba. El tamao del array debe ser al menos la anchura por la altura o el level de mapeo mip usado. Usar SetPixels puede ser ms rpido que llamar a SetPixel repetidamente, especialmente para texturas grandes. Adems, SetPixels puede acceder a niveles de mipmap individuales. function SetPixels (x : int, y : int, blockWidth : int, blockHeight : int, colors : Color[], miplevel : int = 0) : void Esta versin de la funcin no modifica el nivel mip entero, sino slo la parte comprendida entre los parmetros blockWidth y blockHeight empezando desde x,y. El array de colores debe tener un tamao de blockWidth*blockHeight, y el bloque modificado debe caber dentro del nivel mip usado.

SetPixels32: function SetPixels32 (colors : Color32[], miplevel : int = 0) : void Establece un bloque de colores de pxeles. Esta funcin toma un array de tipo Color32 y cambia los colores de los pxeles del nivel de mip entero de la textura. No nos olvidemos de llamar despus a Apply.

LoadImage: function LoadImage (data : byte[]) : boolean Carga una imagen de tipo JPG o PNG desde un array de bytes.

GetPixels: function GetPixels (miplevel : int = 0) : Color[] Esta funcin devuelve un array de colores de pxeles del nivel de mip entero de la textura. function GetPixels (x : int, y : int, blockWidth : int, blockHeight : int, miplevel : int = 0) : Color[] Este segundo prototipo retorna slo el mip de la regin blockWidth por blockHeight empezando por x,y.

GetPixels32: function GetPixels32 (miplevel : int = 0) : Color32[] Obtiene un bloque de colores de pxeles en formato Color32.

Apply: function Apply (updateMipmaps : boolean = true, makeNoLongerReadable : boolean = false) : void Aplica en la prctica todos los cambios previamente efectuados con las funciones SetPixel y SetPixels. Si el parmetro updateMipmaps es true, los niveles de mipmap son recalculados tambin, usando el nivel base como fuente. Normalmente tendremos este parmetro en true salvo cuando queramos modificar los niveles mip nosotros mismos usando SetPixels. Si el parmetro makeNoLongerReadable es true, la textura se marcar como no legible y la memoria ser liberada en la siguiente actualizacin. Por defecto makeNoLongerReadable se pone en false. Esta funcin, como ya dijimos previamente, consume muchos recurso, as que es deseable hacer el mayor nmero de cambios precisos entre cada llamada a la misma.

Resize: function Resize (width : int, height : int, format : TextureFormat, hasMipMap : boolean) : boolean

Redimensiona la textura, y en concreto modifica la anchura, altura, formato y en ocasiones crea mipmaps. Esta funcin es muy similar al constructor, salvo que esta trabaja con una textura que ya existe. precisa llamar a Apply para que los cambios tengan efecto en la tarjeta grfica. function Resize (width : int, height : int) : boolean Esta variante cambia meramente la altura y o la anchura de la textura.

ReadPixels: function ReadPixels (source : Rect, destX : int, destY : int, recalculateMipMaps : boolean = true) : void Lee pxeles de pantalla dentro de los datos de la textura guardada. Copia un rea de pxeles rectangular de la RenderTexture en uso o bien la vista (especificada por el parmetro source) dentro de la posicin definida por destX y destY. Ambas coordenadas usan el espacio de pxeles, donde (0,0) is abajo a la izquierda. Si recalculateMipMaps est establecido en true, los mip maps de la textura sern tambien actualizados. En caso contrario deberemos llamar a Apply para recalcularlos. Esta funcin trabaja slo con los formatos de textura ARGB32 y RGB24.

EncodeToPNG: function EncodeToPNG () : byte[] Codifica esta textura en formato PNG. El array de bytes que devuelve es el archivo PNG. Puedes escribirlo entonces en disco o enviarlo a travs de la rec, por ejemplo. Esta funcin solo trabaja con los formatos de textura ARGB32 y RGB24. La textura tambin debe tener el flag Is Readable marcado en import settings.

34. CLASE INPUT

Es la interfaz que controla todo el sistema de entradas (inputs) de Unity. Esta clase se usa, por ejemplo, para leer la configuracin de ejes en el input Manager. Para leer un eje usaramos Input.GetAxis con uno de los ejes por defecto: Horizontal y Vertical estn configurados para joystick, as como A,W,S,D, y las teclas de flecha. MouseX y Mouse Y estn configurados para el movimiento del ratn. Por su parte Fire1", "Fire2" y "Fire3" estn configurados para Ctrl, Alt y tres botones de ratn o joystick . Pueden aadirse nuevos ejes de entrada en el Input Manager. Si hemos se usar inputs para cualquier tipo de comportamiento que entrae movimiento, es aconsejable usar Input.GetAxis. Esto nos dar una entrada ms suave y configurable que puede servir para teclado, joystick o mouse. En cambio es mejor usar Input.GetButton para acciones como eventos, mejor que para movimientos. Las llamadas a inputs se deben hacer dentro de la funcin update.

VARIABLES DE CLASE: mousePosition: static var mousePosition : Vector3 Variable de slo lectura que indica la posicin actual del ratn en coordenadas de pxeles, donde la esquina inferior izquierda de la pantalla o ventana est en (0, 0) y la superior derecha en (Screen.width, Screen.height). Podemos probarlo con un ejemplo sencillo, para el cual eliminamos el script vinculado a la esfera, y reeditamos MiPrimerScript como sigue: function Update(){ var apunten : Vector3 = Input.mousePosition; Debug.Log(apunten); } Salvamos y arrastramos hasta PortaScripts. Meramente se nos imprimir en pantalla la posicin exacta en pxeles de nuestro cursor. Podemos observar que la esquina inferior izquierda se mueve en parmetros del 0,0.

anyKey: static var anyKey : boolean Booleano de slo lectura que comprueba si hay alguna tecla o botn del ratn apretada en ese momento. Podemos modificar nuestro script anterior para ilustrar esta variable: function Update(){ if(Input.anyKey){ Debug.Log("Se ha pulsado una tecla o botn"); } }

No tenemos ms que apretar cualquier tecla o botn del ratn para ver el mensaje impreso.

anyKeyDown: static var anyKeyDown : boolean Variable de slo lectura que devuelve true el primer frame en que el usuario golpea cualquier tecla o botn del ratn. Debemos colocar esta variable dentro de la funcin update, ya que el estado de la misma se resetea cada frame. No devolver true de nuevo hasta que el usuario libere todas las teclas/botones y presione alguna tecla/botn otra vez. Para entender grficamente la diferencia entre la variable anterior y la siguiente vamos a hacer una cosa: volvemos a darle al play (sigue en vigor el ejemplo anterior) y hacemos un click con un botn del ratn. Automticamente nos aparece el mensaje impreso bajo la ventana del juego. Hacemos un click ahora sobre dicho mensaje, para que nos aparezca el popup de la consola, tal como muestra la captura:

Vale. Ahora, sin retirar dicho popup, presionamos sin soltar el botn del mouse sobre la ventana Game. Vemos que se imprime de manera continuada el mensaje (una por cada frame que mantenemos pulsado el botn del ratn). Y ahora sustituimos en el script la variable "anyKey" por "anyKeyDown", y repetimos los pasos anteriorer. Comprobaremos que aunque mantengamos el botn del ratn presionado, el mensaje slo se imprime el primer frame que lo pulsamos, y no se vuelve a imprimir hasta que lo soltamos y lo volvemos a apretar.

inputString: static var inputString : String Variable de slo lectura que devuelve la entrada de teclado introducida este frame. La misma slo puede contener caracteres ASCII o un par de caracteres especiales que deben ser manejados: el carcter \b significa retroceso y \n representa return o enter.

acceleration: static var acceleration : Vector3 Ultima medicion de aceleracin lineal de un dispositimo en espacio tridimensional. Slo lectura.

accelerationEvents: static var accelerationEvents : AccelerationEvent[] Variable de slo lectura que devuelve una lista de mediciones de aceleracin ocurridas durante el ltimo frame. Dichas medidas son alojadas en variables temporales. Dichas variables temporales son un array del tipo AccelerationEvent, que es una estructura con dos valores: acceleration: De tipo Vector3, es el valor de aceleracin. deltaTime: De tipo float, el tiempo transcurrido desde la ltima medicin de aceleracin.

accelerationEventCount: static var accelerationEventCount : int Nmero de mediciones de aceleracin ocurrida durante el ltimo frame.

eatKeyPressOnTextFieldFocus: static var eatKeyPressOnTextFieldFocus : boolean Propiedad que indica si las teclas impresas son comidas por la entrada de texto si esta tiene el foco (por defecto true).

FUNCIONES DE CLASE: GetAxis: static function GetAxis (axisName : String) : float Devuelve el valor del eje virtual identificado por axisName. El valor estar en el rango -1...1 para entradas de teclado (tradicionalmente la flechas de desplazamiento) y joystick. Si el axis es indicado por el movimiento del ratn, ste ser multiplicado por el eje de sensibilidad y su rango ser distinto a 11. Es una de las funciones con las que ms tropezaremos cuando programemos con Unity, as que merece la pena que nos detengamos para ilustrarla con algn ejemplo. El primer ejemplo lo hemos sacado del manual de referencia. Para que funciones bien (recordemos que tenemos en la actualidad MiPrimerScript vinculado a la esfera) es necesario que eliminemos el componente Rigidbody de la esfera. Y acto seguido editamos nuestro script como sigue: var velocidad : float = 2.0; var velocidadRotacion : float = 45.0;

function Update () { var translacion : float = Input.GetAxis ("Vertical") * velocidad; var rotacion : float = Input.GetAxis ("Horizontal") * velocidadRotacion; translacion *= Time.deltaTime; rotacion *= Time.deltaTime; transform.Translate (0, 0, translacion); transform.Rotate (0, rotacion, 0); } Tratemos de explicar lo que hemos hecho. A travs de Input.GetAxis recogemos las entradas de teclado provinentes de las flechas de desplazamiento verticales y horizontales. As, la flecha de desplazamiento hacia arriba vale 1 y la de desplazamiento hacia abajo vale -1, y lo mismo hacia la derecha (1) y la izquierda (-1). Dichos valores son multiplicados por la velocidad contenida en la variable "velocidad" en el caso del eje arriba/abajo, y por la contenida en la variable "velocidadRotacion" para el eje derecha/izquierda. Ambos valores son almacenados en variables de tipo Vector3 que luego -tras ser reconvertidos en velocidad por frame a velocidad por segundo- se utilizan para participar en el movimiento del game object tanto en el eje delante/detrs de translacin como en el eje Y de rotacin. En suma, nos queda un script -muy bsico y torpe, eso s- para manejar el desplazamiento y giro de nuestra esfera en base a las flechas de desplazamiento. Probmoslo un rato. Hemos dicho que Input.GetAxis tambin acepta como entrada el provocado por el movimiento vertical y horizontal del ratn, as que ilustrmoslo: var velocidadHorizontal : float = 20.0; var velocidadVertical : float = 20.0; function Update () { var h : float = velocidadHorizontal * Input.GetAxis ("Mouse X"); var v : float = velocidadVertical * Input.GetAxis ("Mouse Y"); transform.Rotate (v, h, 0); } Es un ejemplo sencillo. Se almacena en sendas variables el fruto de multiplicar el valor de los ejes de desplazamiento horizontal y vertical del ratn (que recordemos que no es -1,1) por el valor de velocidad que le hayamos dado a las variables expuestas del inicio de script. En base a ello, nuestra esfera girar sobre su eje X e Y en respuesta a los movimientos vertical y horizontal de nuestro ratn.

GetAxisRaw: static function GetAxisRaw (axisName : String) : float Devuelve el valor del eje virtual identificado por el parmetro axisName sin ningn filtro de suavizado aplicado. El valor estar en el rango de -11 para entrada de teclado y joystick. Como a la entrada -al contrario de la funcin anterior- no se le aplica smooth (suavizado),la entrada de teclado ser siempre o -1 o cero o 1. Esta funcin puede sernos til para el caso de que queramos hacer todo el proceso de suavizado de entrada nosotros mismos manualmente.

GetButton: static function GetButton (buttonName : String) : boolean Devuelve true mientras el botn virtual que le pasemos como parmetro en formato string est presionado. Podemos

pensar por ejemplo en un disparador automtico, que devolvera true mientras el botn estuviera presionado. Eso s, as como esta funcin es ptima para acciones como disparar un arma, para cualquier tipo de movimiento es mejor usar GetAxis, que a ste le introduce valores de suavizado que en GetButton no hallaremos (ni podremos implementar manualmente, al contrario que en GetAxisRaw. Un ejemplo: var proyectil : GameObject; var frecuenciaDisparo : float = 0.5; private var proximoDisparo : float = 0.0; function Update () { if (Input.GetButton ("Fire1") && Time.time > proximoDisparo) { proximoDisparo = Time.time + frecuenciaDisparo; var clon : GameObject = Instantiate(proyectil, transform.position+Vector3.forward, transform.rotation) as GameObject; } } Salvamos y arrastramos el cubo a la variable expuesta proyectil. Pulsamos play y observaremos que estamos clonando/disparando cubos cada vez que -dentro del lapso de tiempo permitido- pulsamos el botn izquierdo del ratn o la tecla Ctrl situada a la izquierda del teclado (que son por defecto los dos elementos que tenemos vinculados al evento Fire1. Por otro lado, si mantenemos pulsado de manera ininterrumpida bien el botn o bien la tecla indicados, observaremos que disparamos un cubo cada medio segundo. En s el script comprueba si hemos pulsado la tecla o botn que tengamos asignada a Fire1. En caso afirmativo pasa a comprobar si ha transcurrido un lapso de tiempo superior al que le hemos fijado en frecuenciaDisparo (que para el primer disparo valdr cero). Si tambin es true esta segunda condicin se le aade medio segundo de espera al resto de disparos ms el tiempo transcurrido en hacerlo, el script nos permite clonar/disparar otro proyectil ms.

GetButtonDown: static function GetButtonDown (buttonName : String) : boolean Devuelve true durante el frame en que el jugador aprieta el botn virtual identificado como buttonName. Debemos llamar siempre a esta funcin desde la funcin Update, dado que el estado se resetea cada frame. No devolver true hasta que el usuario libere la tecla y la presione de nuevo, al igual que suceda con anyKeyDown.

GetButtonUp: static function GetButtonUp (buttonName : String) : boolean Devuelve true el primer frame en que el jugador libera el botn virtual identificado como buttonName. Recordemos llamar esta funcin desde Update ya que se resetea su estado cada frame. No devolver true hasta que se libere la tecla y se vuelva a presionar.

GetKey: static function GetKey (name : String) : boolean Devuelve true mientras el jugador aprieta la tecla identificada como name (pensemos de nuevo en un disparador automtico) Para ver la lista de indentificadores de tecla podemos consultar Input Manager en el men=>Edit=>Project Settings=>Input. Un ejemplo sencillo: function Update () { if (Input.GetKey ("up")) print ("Has presionado la flecha de desplazamiento superior"); if (Input.GetKey ("down")) print ("Has presionado la flecha de desplazamiento inferior"); } static function GetKey (key : KeyCode) : boolean En este segundo prototipo la funcin devuelve true mientras el jugador presiona la tecla identificada por el parmetro de tipo KeyCode. As, el ejemplo anterior en esta segunda modalidad se quedara as: function Update () { if (Input.GetKey (KeyCode.UpArrow)) print ("Has presionado la flecha de desplazamiento superior"); if (Input.GetKey (KeyCode.DownArrow)) print ("Has presionado la flecha de desplazamiento inferior"); } Paso a relacionar todo el enum KeyCode: None Backspace Delete Tab Clear Return Pause Escape Space Keypad0 Keypad1 Keypad2 Keypad3 Keypad4 Keypad5 Keypad6 Keypad7 Keypad8 Keypad9 KeypadPeriod KeypadDivide KeypadMultiply Not assigned (never is pressed) The backspace key The forward delete key The tab key The Clear key Return key Pause on PC machines Escape key Space key Numeric keypad 0 Numeric keypad 1 Numeric keypad 2 Numeric keypad 3 Numeric keypad 4 Numeric keypad 5 Numeric keypad 6 Numeric keypad 7 Numeric keypad 8 Numeric keypad 9 Numeric keypad '.' Numeric keypad '/' Numeric keypad '*'

KeypadMinus KeypadPlus KeypadEnter KeypadEquals UpArrow DownArrow RightArrow LeftArrow Insert Home End PageUp PageDown F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 Alpha0 Alpha1 Alpha2 Alpha3 Alpha4 Alpha5 Alpha6 Alpha7 Alpha8 Alpha9 Exclaim DoubleQuote Hash Dollar Ampersand Quote LeftParen RightParen Asterisk Plus Comma Minus Period Slash Colon Semicolon Less Equals Greater Question At LeftBracket Backslash RightBracket Caret

Numeric keypad '-' Numeric keypad '+' Numeric keypad enter Numeric keypad '=' Up arrow key Down arrow key Right arrow key Left arrow key Insert key key Home key End key Page up Page down F1 function key F2 function key F3 function key F4 function key F5 function key F6 function key F7 function key F8 function key F9 function key F10 function key F11 function key F12 function key F13 function key F14 function key F15 function key The '0' key on the top The '1' key on the top The '2' key on the top The '3' key on the top The '4' key on the top The '5' key on the top The '6' key on the top The '7' key on the top The '8' key on the top The '9' key on the top Exclaim key Double quote key Hash key Dollar sign key Ampersand key Quote key Left Parent key Right Parent key Asterisk key Plus key Comma ',' key Minus '-' key Period '.' key Slash '/' key Colon ',' key Semicolon ';' key Less '<' key Equals '=' key Greater '>' key Question mark '?' key At key Left bracket key Backslash key Backslash key Caret key

of of of of of of of of of of

the the the the the the the the the the

alphanumeric alphanumeric alphanumeric alphanumeric alphanumeric alphanumeric alphanumeric alphanumeric alphanumeric alphanumeric

keyboard. keyboard. keyboard. keyboard. keyboard. keyboard. keyboard. keyboard. keyboard. keyboard.

Underscore BackQuote A B C D E F G H I J K L M N O P Q R S T U V W X Y Z Numlock CapsLock ScrollLock RightShift LeftShift RightControl LeftControl RightAlt LeftAlt LeftApple LeftWindows RightApple RightWindows AltGr Help Print SysReq Break Menu Mouse0 Mouse1 Mouse2 Mouse3 Mouse4 Mouse5 Mouse6 JoystickButton0 JoystickButton1 JoystickButton2 JoystickButton3 JoystickButton4 JoystickButton5 JoystickButton6 JoystickButton7 JoystickButton8

Underscore '_' key Back quote key 'a' key 'b' key 'c' key 'd' key 'e' key 'f' key 'g' key 'h' key 'i' key 'j' key 'k' key 'l' key 'm' key 'n' key 'o' key 'p' key 'q' key 'r' key 's' key 't' key 'u' key 'v' key 'w' key 'x' key 'y' key 'z' key Numlock key Capslock key Scroll lock key Right shift key Left shift key Right Control key Left Control key Right Alt key Left Alt key Left Apple key Left Windows key Right Apple key Right Windows key Alt Gr key Help key Print key Sys Req key Break key Menu key First (primary) mouse button Second (secondary) mouse button Third mouse button Fourth mouse button Fifth mouse button Sixth mouse button Seventh mouse button Button 0 on any joystick Button 1 on any joystick Button 2 on any joystick Button 3 on any joystick Button 4 on any joystick Button 5 on any joystick Button 6 on any joystick Button 7 on any joystick Button 8 on any joystick

JoystickButton9 JoystickButton10 JoystickButton11 JoystickButton12 JoystickButton13 JoystickButton14 JoystickButton15 JoystickButton16 JoystickButton17 JoystickButton18 JoystickButton19 Joystick1Button0 Joystick1Button1 Joystick1Button2 Joystick1Button3 Joystick1Button4 Joystick1Button5 Joystick1Button6 Joystick1Button7 Joystick1Button8 Joystick1Button9 Joystick1Button10 Joystick1Button11 Joystick1Button12 Joystick1Button13 Joystick1Button14 Joystick1Button15 Joystick1Button16 Joystick1Button17 Joystick1Button18 Joystick1Button19 Joystick2Button0 Joystick2Button1 Joystick2Button2 Joystick2Button3 Joystick2Button4 Joystick2Button5 Joystick2Button6 Joystick2Button7 Joystick2Button8 Joystick2Button9 Joystick2Button10 Joystick2Button11 Joystick2Button12 Joystick2Button13 Joystick2Button14 Joystick2Button15 Joystick2Button16 Joystick2Button17 Joystick2Button18 Joystick2Button19 Joystick3Button0 Joystick3Button1 Joystick3Button2 Joystick3Button3 Joystick3Button4 Joystick3Button5 Joystick3Button6 Joystick3Button7 Joystick3Button8 Joystick3Button9 Joystick3Button10 Joystick3Button11

Button Button Button Button Button Button Button Button Button Button Button Button Button Button Button Button Button Button Button Button Button Button Button Button Button Button Button Button Button Button Button Button Button Button Button Button Button Button Button Button Button Button Button Button Button Button Button Button Button Button Button Button Button Button Button Button Button Button Button Button Button Button Button

9 on any joystick 10 on any joystick 11 on any joystick 12 on any joystick 13 on any joystick 14 on any joystick 15 on any joystick 16 on any joystick 17 on any joystick 18 on any joystick 19 on any joystick 0 on first joystick 1 on first joystick 2 on first joystick 3 on first joystick 4 on first joystick 5 on first joystick 6 on first joystick 7 on first joystick 8 on first joystick 9 on first joystick 10 on first joystick 11 on first joystick 12 on first joystick 13 on first joystick 14 on first joystick 15 on first joystick 16 on first joystick 17 on first joystick 18 on first joystick 19 on first joystick 0 on second joystick 1 on second joystick 2 on second joystick 3 on second joystick 4 on second joystick 5 on second joystick 6 on second joystick 7 on second joystick 8 on second joystick 9 on second joystick 10 on second joystick 11 on second joystick 12 on second joystick 13 on second joystick 14 on second joystick 15 on second joystick 16 on second joystick 17 on second joystick 18 on second joystick 19 on second joystick 0 on third joystick 1 on third joystick 2 on third joystick 3 on third joystick 4 on third joystick 5 on third joystick 6 on third joystick 7 on third joystick 8 on third joystick 9 on third joystick 10 on third joystick 11 on third joystick

Joystick3Button12 Joystick3Button13 Joystick3Button14 Joystick3Button15 Joystick3Button16 Joystick3Button17 Joystick3Button18 Joystick3Button19

Button Button Button Button Button Button Button Button

12 13 14 15 16 17 18 19

on on on on on on on on

third third third third third third third third

joystick joystick joystick joystick joystick joystick joystick joystick

GetKeyDown: static function GetKeyDown (name : String) : boolean Devuelve true durante el frame en que el usuario empieza a presionar la tecla identificada como name. Recordemos llamarla dentro de la funcin Updata, ya que resetea su estado cada frame. No devuelve true hasta que el usuario suelta y luego aprieta la tecla de nuevo (tal como hace por ejemplo GetButtonDown con respecto a GetButton). static function GetKeyDown (key : KeyCode) : boolean Devuelve true durante el frame en que el jugador empieza a presionar la tecla identificada por la key de tipo enumeracin KeyCode, que vimos en el captulo anterior.

GetKeyUp: static function GetKeyUp (name : String) : boolean static function GetKeyUp (key : KeyCode) : boolean Devuelve true durante el frame en que el jugador libera la tecla identificada por name.

GetJoystickNames: static function GetJoystickNames () : string[] Devuelve un array de strings describiendo los joysticks conectados. Esto puede ser til en una configurancin de entradas de pantalla de usuario. As, en lugar de ensear etiquetas como joystick 1, puedes mostrasr ttulos ms personalizados.

GetMouseButton: static function GetMouseButton (button : int) : boolean Devuelve true si el botn indicado del ratn es apretado. La variable button es un int que representa 0 para el botn izquierdo, 1 para el derecho y 2 para el central. Por poner un ejemplo muy simple: function Update() { if(Input.GetMouseButton(0)) Debug.Log("presionado botn izquierdo."); if(Input.GetMouseButton(1)) Debug.Log("presionado botn derecho."); if(Input.GetMouseButton(2))

Debug.Log("presionado botn central."); }

GetMouseButtonDown: static function GetMouseButtonDown (button : int) : boolean Devuelve true durante el frame en que el usuario aprieta el botn del ratn indicado. Debes llamar esta funcin dentro de update, ya que el estado se resetea cada frame. No devolver true hasta que el botn sea liberado y vuelto a pulsar (recordemos de nuevo la diferencia de GetButtonDown con respecto a GetButton, para aplicarla tambin aqu).

GetMouseButtonUp: static function GetMouseButtonUp (button : int) : boolean Devuelve true durante el frame en que el usuario libera el botn del ratn indicado.

ResetInputAxes: static function ResetInputAxes () : void Resetea todos los inputs, con lo que todos los axes y botones retornan a 0. Esto puede ser util cuando se regenera al jugador y no te interesa conservar ningn imput que proceda de alguna tecla que pudiera continuar presionando.

GetAccelerationEvent: static function GetAccelerationEvent (index : int) : AccelerationEvent Devuelve mediciones de aceleracin que ocurrieron durante el ltimo frame.

35. ESTRUCTURA BOUNDS

Como es fcil apreciar, Bounds no es una clase, sino una estructura. La diferencia, aunque a efectos prcticos una clase es lo mismo que una estructura, es ms de tipo semntico. Esto es, cuando nos topamos con una estructura, se nos quiere informar de que la misma tiene un componente de complemento a una o varias clases que no suelen tener las clases en s. La estructura bounds representa una caja de bordes con los ejes alineados. Tambin denominada AABB (para abreviar axis-aligned bounding box), es una caja alineada con los ejes de coordenadas globales que envuelve algn objeto. Como la caja nunca rota respecto de los ejes, puede ser definida por su centro y extensiones, o alternativamente por mnimo y mximo. (center, extents, min y max, en ingls) La estructura Bounds se usa en Collider.bounds, Mesh.bounds y Renderer.bounds.

VARIABLES: center: var center : Vector3 El centro de la caja.

size: var size : Vector3 El tamao total de la caja. Es siempre dos veces ms grande que las extensiones (extents)

extents: var extents : Vector3 Las extensiones de la caja. Es siempre la mitad del tamao (size)

min: var min : Vector3 El punto mnimo de la caja. Es siempre igual a center extents.

max: var max : Vector3 El punto mximo de la caja. Siempre es igual a center+extents.

FUNCIONES: static function Bounds (center : Vector3, size : Vector3) : Bounds Crea una nueva caja de bordes con un centro dado y un tamao total. Las extensiones deben ser la mitad del tamao dado.

SetMinMax: function SetMinMax (min : Vector3, max : Vector3) : void Establece los bordes en los valores mnimos y mximos de la caja. Usar esta funcin es ms rpido que asignar min y max de manera separada.

Encapsulate: function Encapsulate (point : Vector3) : void function Encapsulate (bounds : Bounds) : void Incrementa la caja para incluir el punto que se pasa como parmetro (1er prototipo) o para incluir la nueva caja (2 prototipo)

Expand: function Expand (amount : float) : void function Expand (amount : Vector3) : void Expande la caja para incrementar su tamao en una cantidad a lo largo de cada cara.

Intersects: function Intersects (bounds : Bounds) : boolean Hay alguna otra caja intersectando nuestra caja?

Contains: function Contains (point : Vector3) : boolean Est el punto point contenido en la caja?

sqrDistance: function SqrDistance (point : Vector3) : float El cuadrado de la distancia entre el punto point y la caja.

intersectRay: function IntersectRay (ray : Ray) : boolean El rayo ray intersecta esta caja? Pongamos un ejemplo. Previamente ubicamos la esfera (que es el gameobject al que tenemos vinculado nuestro script) en la posicion (2,0,2), y le aadimos de nuevo un componente Rigidbody. Ahora reeditamos MiPrimerScript as: var rayo : Ray = new Ray (Vector3.zero, Vector3.forward);; function Update () { Debug.DrawRay (Vector3.zero, Vector3.forward * 999, Color.green); var bordes : Bounds = transform.collider.bounds; if (bordes.IntersectRay (rayo)) Debug.Log("La caja toc el rayo"); } function FixedUpdate() { rigidbody.AddForce(-Vector3.right*6*Time.deltaTime); } Creamos primero un rayo que surge en el centro global de la escena y se prolonga a lo largo del eje z positivo (vulgarmente, hacia delante). Ya dentro de la funcin update dibujamos ese mismo rayo que ya tenemos descrito, para que visualmente podamos seguir lo que est pasando. Acto seguido creamos una instancia de la estructura Bounds que en un alarde de originalidad llamaremos bordes, y la inicializaremos con la caja de bordes del collider de nuestro gameobject (la caja que envuelve el collider, ojo, no confundir con el collider mismo. En este caso el collider tiene forma de escena y el Bounds de la esfera sigue teniendo forma de caja). Dejamos establecido que si la caja toca el rayo se mostrar un mensaje en pantalla, as que slo nos queda darle movimiento a la esfera para que cuando intersecte el rayo (que aqu hemos dibujado a travs de DrawRay, pero que podramos haber dejado invisible) se muestre dicho mensaje.

36. CLASE COLLISION

Clase que obtiene diferente informacin de una colisin. La informacin de la collision es pasada a los eventos Collider.OnCollisionEnter, Collider.OnCollisionStay y Collider.OnCollisionExit.

VARIABLES: relativeVelocity: var relativeVelocity : Vector3 Variable de slo lectura que devuelve la velocidad lineal relativa de los dos objetos que colisionan. Para realizar un ejemplo, recoloquemos antes la esfera en (2,0,0). Luego escribamos nuestro script: function OnCollisionEnter(colision : Collision) { var velCol: Vector3 = colision.relativeVelocity; Debug.Log(velCol.magnitude); } function FixedUpdate(){ rigidbody.AddForce(Vector3(-4,0,0)); } Expliquemos el script de abajo arriba. En la funcin FixedUpdate lo nico que hacemos es aplicar una fuerza de cuatro unidades hacia la izquierda a la esfera, forzndola a colisionar con el cubo. En el momento en que la esfera topa con el cubo, los datos de la colisin son almacenados en el parmetro colision. Uno de dichos datos es, como estamos estudiando, la velocidad relativa a la que aqulla se produce, velocidad que almacenamos en la variable velCol, de tipo Vector3. Ya slo nos queda imprimir la fuerza o longitud de dicho vector, que como recordaremos se hace a travs de la variable magnitude. Pulsamos play y observamos que la magnitud de la colisin es de algo menos de 4 (fruto de descontar el rozamiento y la resistencia respecto de la fuerza aplicada)

rigidbody: var rigidbody : Rigidbody Variable de slo lectura que hace referencia al rigidbody que golpeamos. Es nulo si el objeto que golpeamos es un collider sin rigidbody vinculado. Es fcil de ilustrar con un ejemplo: function OnCollisionEnter(colision : Collision) { if(colision.rigidbody){ Debug.Log("He topado con el rigidbody del objeto " + colision.rigidbody.name); } }

function FixedUpdate(){ rigidbody.AddForce(Vector3(-4,0,0)); } No hay mucho que explicar. Si el collider con el que topa nuestra esfera tiene un rigidbody, se nos imprime un texto que adems incluye el nombre del objeto al que dicho rigidbody pertenece.

collider: var collider : Collider El collider que golpeamos (slo lectura). Para determinar la parte concreta que golpeamos de cada collider deberemos iterar a travs de los puntos de contacto con la propiedad contacts.

transform: var transform : Transform El transform del objeto que golpeamos (read only). Si chocamos contra un collider con un rigidbody, el transform ser el vinculado al rigidbody. Si colisionamos contra un collider sin rigidbody, el transform ser el vinculado al collider.

gameObject: var gameObject : GameObject Variable de slo lectura que devuelve el objeto con el que chocamos.

contacts: var contacts : ContactPoint[] El punto de contacto generado por el engine de fsicas. Cada contacto implica un punto de contacto, un normal y dos colliders que colisionan (ver ContactPoint). A travs de OnCollisionStay o OnCollisionEnter puedes siempre estar seguro de que el contacto tiene al menos un elemento. ContactPoint es una estructura que tiene estas variables: 1) point: el punto de contacto. Por ejemplo: function OnCollisionEnter(colision : Collision) { if(colision.relativeVelocity.magnitude > 2){ print("Puntos de colision: " + colision.contacts.Length); print("Primer punto de colision: " + colision.contacts[0].point); } } function FixedUpdate(){

rigidbody.AddForce(Vector3(-8,0,0)); } Una breve explicacin del script: Como en el anterior aplicamos una fuerza a la esfera que la obliga a colisionar con el cubo. Si dicha colisin tiene una fuerza superior a 2 unidades se imprimen dos mensajes: uno que indica el nmero de colisiones que se ha producido y otro el punto exacto de la primera colisin. Si no hubiramos establecido una fuerza mnima del contacto para que aparecieran los mensajes, el propio contacto de la esfera con el suelo habra disparado dichos mensajes. Pulsamos play y veremos uno de los mensajes, y si hacemos click sobre dicho mensaje para que nos aparezca el popup de la consola, encontraremos el segundo, tal como muestro en esta captura:

2) normal: El normal del punto de contacto. 3) thisCollider: El primer collider en contacto, o sea, el vinculado al script. function OnCollisionEnter(colision : Collision) { if (colision.relativeVelocity.magnitude > 2){ print("This collider is named: " + colision.contacts[0].thisCollider.name); } } function FixedUpdate(){ rigidbody.AddForce(Vector3(-8,0,0)); } En este sencillo script observamos que thisCollider se corresponde a la esfera. 4) otherCollider: El otro collider en contacto. Para comprobar que hace referencia al cubo, meramente sustituir en el script anterior thisCollider por otherCollider.

37. CLASE CONTROLLERCOLLIDERHIT

ControllerColliderHit es usado por CharacterController.OnControllerColliderHit para dar informacin detallada sobre la colisin y como trabajar con ella.

VARIABLES: controller: var controller : CharacterController El controller que golpea el collider. un simple ejemplo, para el cual con la esfera seleccionada vamos a men=>Component=>Physics=>Character Controller, y reemplazamos la Sphere Collider. Luego escribimos el siguiente script: function OnControllerColliderHit(colision : ControllerColliderHit) { Debug.Log(colision.controller.name); } function FixedUpdate(){ collider.Move(Vector3(-8,0,0)); } Poco que explicar. Movemos la esfera hacia el cubo (notad que sustituimos la funcin AddForce por Move, ya que ahora nuestra esfera tiene un character controller. Una vez impacta con el cubo, se imprime el nombre del controller (la esfera)

collider: var collider : Collider El collider que fue golpeado por el controller. Para verlo en un ejemplo sustituyamos "colision.controller.name" por "colision.collider.name".

rigidbody: var rigidbody : Rigidbody El rigidbody que fue golpeado por el controller. Es null si no se toca un rigidbody sino un collider esttico.

gameObject: var gameObject : GameObject El game object que fue golpeado por el controller.

transform: var transform : Transform El transform que fue golpeado por el controller.

point: var point : Vector3 El punto de impacto en coordenadas globales.

normal: var normal : Vector3 El normal de la superficie con la que colisionamos en coordenadas globales.

moveDirection: var moveDirection : Vector3 Aproximadamente la direccin desde el centro de la cpsula al punto que tocamos. Esto puede ser til para encontrar una direccin razonable para aplicar fuerzas a rigidbodies golpeados. Por poner un ejemplo muy bsico: function OnControllerColliderHit(colision : ControllerColliderHit) { colision.rigidbody.AddForce(colision.moveDirection * 15); Debug.Log(colision.moveDirection); } function FixedUpdate(){ collider.Move(Vector3(-2,0,0)); } Cuando el cubo recibe el impacto de la esfera, a su vez al rigidbody vinculado al cubo le aplicamos una fuerza en la misma direccin del impacto, multiplicada por quince. Paralelamente imprimimos la direccin desde el centro de la cpsula de nuestro controller al punto de contacto.

moveLenght: var moveLength : float Indica lo lejos que el character controller ha viajado hasta golpear al collider. Note que esto puede ser diferente de lo que pasas a CharacterController.Move, porque todos los movimientos estn constreidos por colisiones.

38. CLASE DEBUG

Clase que contiene mtodos para desbugear con facilidad mientras se desarrolla un juego:

VARIABLES DE CLASE: isDebugBuild: static var isDebugBuild : boolean En el dilogo Build Settings, que podemos encontrar en el men=>File, hay un check box llamado Development Build. Si dicho check box est marcado, entonces isDebugBuild ser true.

FUNCIONES DE CLASE: DrawLine: static function DrawLine (start : Vector3, end : Vector3, color : Color = Color.white, duration : float = 0.0f) : void Dibuja una lidea desde el punto que le pasemos como parmetro start hasta el establecido como end con el color que le establezcamos como tercer parmetro y durante un tiempo fijado en duration. Si la duracin es 0 entonces la linea es dibujada un frame. La linea ser dibujada en la vista de escena del editor. Si en la ventana Game est habilitada la opcion Gizmos, tambin se mostrar ah la lnea. Un pequeo ejemplo: function Update () { Debug.DrawLine (Vector3.zero, transform.position, Color.red); } Estamos dibujando una lnea que empezara en el centro de la escena y que ira hasta el centro del objeto que tiene vinculado el script, esto es, la esfera. La lnea sera de color rojo y se dibuja cada frame, coincidiendo con las veces que es llamada la funcin Update. Si queremos ver tambin la lnea en la vista Game, recordemos activar el botn Gizmos.

DrawRay: static function DrawRay (start : Vector3, dir : Vector3, color : Color = Color.white, duration : float = 0.0f) : void Dibuja una lnea desde start a start+dir con el color que especifiquemos por una duracin de tiempo tambin establecida. Si duracin es 0 entonces la lnea es dibujada un frame. Para ver las diferencias con la funcin anterior, lo mejor ser realizar el mismo ejemplo con la nueva funcin. As: function Update () { Debug.DrawRay (Vector3.zero, transform.position*10, Color.red); }

Vemos que aqu el segundo parmetro no es el destino final del rayo, sino la direccin y distancia de ste. En este caso veremos una lnea/rayo de 10 metros saliendo desde el centro de la escena.

Break: static function Break () : void Pausa el editor. Esto es til cuando queremos comprobar ciertos valores en el inspector y no somos capaces de pausarlo manualmente.

Log: static function Log (message : object) : void Anota mensajes en la consola de Unity: Debug.Log("Hola, mundo"); static function Log (message : object, context : Object) : void Cuando seleccionas en mensaje en la consola se dibuja una conexin con el objeto contextual. Esto es muy til si queremos saber qu errores ocurren en un objeto. Me explico. Escribimos esto en MiPrimerScript (que recordemos que tenemos vinculado a la esfera): Debug.Log ("Hola, mundo", gameObject); Al darle al play, tal como podemos suponer, aparece el mensaje impreso en la consola. Pero en este caso, si hacemos click sobre ese mensaje, observaremos que en la jerarquia automticamente se nos selecciona la esfera durante unos segundos.

LogError: static function LogError (message : object) : void Una variable de Debug.Log que anota un mensaje de error en la consola (en color rojo) Debug.LogError("Esto es un error"); static function LogError (message : object, context : Object) : void Variante similar a la que tratbamos antes para Log.

LogWarning: static function LogWarning (message : object) : void Una variante de Debug.Log que muestra un mensaje de aviso en la pantalla (en color amarillo) static function LogWarning (message : object, context : Object) : void Mensaje vinculado a un determinado objeto, como en los dos casos anteriores.

39. CLASE EVENT

Tipos de teclas modificadores que pueden estar activos durante un proceso de pulsacin de tecla. Los eventos pueden corresponder a entradas de usuario (teclas presionadas, accin de ratn) o bien ser distribuciones (layers) de unityGUI o eventos de renderizado. Asi como OnGUI es potencialmente llamado multiples veces por frame. Event.current corresponde al actual evento dentro de la llamada a OnGUI.

VARIABLES: type: var type : EventType Variable que indica el tipo de evento. Es de tipo EventType, que es una enumeracin que permite los siguientes valores: MouseDown: MouseUp: MouseMove: MouseDrag: KeyDown: KeyUp: ScrollWheel: Repaint: Layout: DragUpdated: DragPerform: DragExited: Ignore: Used: ValidateCommand: ExecuteCommand: ContextClick: Pongamos un breve ejemplo: function OnGUI () { Debug.Log("Current event detected: " + Event.current.type); } Este script meramente imprime el evento que est teniendo lugar cada frame. Prueba, tras pulsar play, a hacer click con diferentes botones del ratn, pulsa distintas teclas, mueve el ratn, etc. Luego detn el reproductor y haz click sobre el ltimo mensaje de la consola para que te aparezca el pop up. Vers una lista enorme de eventos que han tenido lugar, la mayora de repintado y distribucin, pero entre ellos estarn los que hayas provocado durante ese tiempo. Un botn del ratn ha sido presionado. Un botn del ratn ha sido liberado. El ratn se ha movido (slo en vista de edicin). El ratn fue arrastrado. Una tecla del teclado fue presionada. Una tecla del teclado fue liberada. La rueda del ratn se movi. Un evento de repintado. Se enva uno cada frame. Un evento de distribucin. Solo en editor: operacin de drag & drop actualizada. Slo en editor: operacin de drag & drop realizada. Slo en editor: operacion de drag & drop finalizada. el evento debe ser ignorado. Evento ya procesado. Valida un comando especial (p.ej. copy & paste) Ejecuta un comando especial (p.ej. copy & paste) El usuario ha hecho click con el botn derecho.

mousePosition: var mousePosition : Vector2 La posicin del ratn. Variable usada en los eventos EventType.MouseMove y EventType.MouseDrag.

delta: var delta : Vector2 El movimiento relativo del ratn comparado con el ltimo evento.

button: var button : int Qu botn del ratn ha sido presionado. Apliquemos un ejemplo: function OnGUI() { var miEvento : Event = Event.current; if(miEvento.button == 0 && miEvento.isMouse){ Debug.Log("Botn izquierdo"); } else if(miEvento.button == 1) { Debug.Log("Botn derecho"); } else if (miEvento.button == 2) { Debug.Log("Botn del centro"); } } Creamos primero una instancia de la clase Event, que contendr el evento actual. Si dicho evento es un evento de ratn (isMouse, que estudiaremos de aqu a un momento) y button vale cero (esto es, button vale cero pese a haber un evento de ratn, ya que si no hay evento de ratn button tambin vale cero, no s si me estoy explicando) se imprime un mensaje, y as sucesivamente (con valores de button en uno y dos no hace falta descartar la posibilidad de que no se est produciendo un evento de ratn por lo anteriormente explicado.

modifiers: var modifiers : EventModifiers Qu tecla modificadora est siendo pulsada( ahift, ctrl, alt...) function OnGUI() { var miEvento : Event = Event.current; Debug.Log(miEvento.modifiers); } Probad a pulsar las teclas modificadoras y las veris impresas, a diferencia de las que no tienen esa condicin.

clickCount: var clickCount : int Cuntos clicks de ratn consecutivos hemos recibido. Es usado en el evento EventType.MouseDown. Usadlo para diferenciar entre un click nico y un doble click. Un ejemplo:

private var numeroClicks : int = 0; function OnGUI() { var miEvento : Event = Event.current; if (miEvento.isMouse) { numeroClicks +=miEvento.clickCount; Debug.Log("Mouse clicks: " + numeroClicks); } } Si lo probamos, vemos que tenemos un contador de clicks que contabiliza cada actividad (down y up) del botn del ratn desde el inicio del juego. Es una adaptacin del script que est en el manual de referencia. Si os fijis, declaramos la variable numeroClicks fuera de la funcin onGUI, para que no nos contabilice (como hace en el manual de referencia) los clicks de cada frame, sino los totales. Por lo dems, el script no tiene mucho misterio: inicializamos una variable de tipo Event con el evento actual, nos aseguramos de que el evento tenga que ver con el ratn y pasamos a contar clicks.

character: var character : char El tipo de caracter. function OnGUI() { var miEvento : Event = Event.current; if (miEvento.isKey) { Debug.Log("Pulsado caracter: " + miEvento.character); } }

commandName var commandName : String El nombre de un evento de tipo ExecuteCommand o Validate Command ("Copy", "Cut", "Paste", "Delete", "FrameSelected", "Duplicate", "SelectAll", etc)

keyCode: var keyCode : KeyCode El key code para eventos de teclado. Usado en los eventos EventType.KeyDown y EventType.KeyUp; devuelve el valor del KeyCode, por lo que se usa para manejar, por ejemplo, teclas de cursor, de funciones, etc. Teclead este cdigo y tras salvar y darle al play pulsad por ejemplo una de las flechas de desplazamiento del teclado: function OnGUI() { var miEvento : Event = Event.current; if (miEvento.isKey) { Debug.Log("El key code es: " + miEvento.keyCode); } }

shift: var shift : boolean Est shift pulsado? (slo lectura)

control: var control : boolean Est control pulsado? (slo lectura)

alt: var alt : boolean Est alt pulsado? (Slo lectura)

capsLock: var capsLock : boolean Est el bloqueo de maysculas pulsado? (slo lectura)

numeric: var numeric : boolean Se est presionando alguna tecla del teclado numrico) (slo lectura)

functionKey: var functionKey : boolean Es la tecla presionada una tecla de funcin (alt, ctrl, shift, etc)? (Slo lectura)

isKey: var isKey : boolean Es este evento un evento de teclado? (slo lectura)

isMouse: var isMouse : boolean Es este evento un evento de ratn? (slo lectura)

FUNCIONES: GetTypeFromControl: function GetTypeForControl (controlID : int) : EventType Esta funcin devuelve un tipo de evento que es filtrado para un determinado control cuya id pasamos como parmetro. Esta funcin es usada para implementar bloqueos de ratn y de focos de teclado. El id del control para el que requerimos el tipo de evento se obtiene de GUIUtilty.GetControlID (), y en EventType podemos ver una lista de sus posibles valores.

Use: function Use () : void Evento ya utilizado. deberamos llamar a este mtodo cuando ya hemos usado un evento. El tipo de evento ser colocado en EventType.Used, causando que otros elementos GUI lo ignoren.

VARIABLES DE CLASE: current: static var current : Event El evento actual/corriente que est siendo procesado en este mismo momento. Un ejemplo: function OnGUI() { var miEvento : Event = Event.current; if(miEvento.type != EventType.repaint && miEvento.type != EventType.layout){ Debug.Log("Current detected event: " + Event.current); } } Salvamos y tras pulsar al play disparamos los eventos que deseemos. Detenemos el reproductor y accedemos a la consola donde se muestran los mensajes haciendo click sobre el ltimo y ah tendremos toda la informacin sobre teclas pulsadas, movimientos y clics del ratn, etc. Observaris que descart la impresin de eventos de tipo repaint y layout, que son los que se producen de manera automtica y en un nmero mayor.

40. CLASE GIZMOS

Los Gizmos son usados para permitir un debug visual o bien para colocar ayudas en la vista de escena. Todos los gizmos deben ser dibujados o con la funcin OnDrawGizmos o con la funcin. OnDrawGizmosSelected. La diferencia de ambas es que: OnDrawGizmos es llamada cada frame. OnDrawGizmosSelected es llamada slo si el objeto al cual est vinculado el script es seleccionado.

VARIABLES DE CLASE: color: static var color : Color Establece el color para los gizmos que sern dibujados a continuacin. Vamos a hacer un pequeo ejemplo. Aseguros de que MiPrimerScript sigue estando vinculado a la esfera, y acto seguido deseleccionar cualquier gameobject haciendo click en un espacio vaco de la Jerarqua. Comprobamos que en la vista game tengamos marcada la pestaa Gizmos. Escribimos: function OnDrawGizmosSelected () { Gizmos.color = Color.blue; var direction : Vector3 = transform.TransformDirection (Vector3.forward) * 5; Gizmos.DrawRay (transform.position, direction); } Le damos al play y no parece ocurrir nada. Esto es porque estamos llamando a la funcin OnDrawGizmosSelected, que slo muestra el dibujo cuando seleccionamos el objeto al cual va vinculado el script, as que en la jerarqua seleccionamos la esfera y automticamente nos debera aparecer una lnea de color azul que va desde la posicin del transform de la esfera cinco metros en adelante.

FUNCIONES DE CLASE: DrawRay: static function DrawRay (r : Ray) : void static function DrawRay (from : Vector3, direction : Vector3) : void Dibuja un rayo que empieza desde from hasta from + direction. Lo hemos visto en funcionamiento en el ejemplo anterior.

DrawWireSphere: static function DrawWireSphere (center : Vector3, radius : float) : void Dibuja una esfera de alambre con centro y radio.

var radio = 2.0; function OnDrawGizmos() { Gizmos.color = Color.cyan; Gizmos.DrawWireSphere (transform.position, radio); } Meramente como apunte, aqu la esfera de alambre se ve tengamos o no seleccionado el game object esfera, porque la hemos dibujado con la funcin OnDrawGizmos.

DrawSphere: static function DrawSphere (center : Vector3, radius : float) : void Dibuja una esfera slida con centro y radio.

DrawWireCube: static function DrawWireCube (center : Vector3, size : Vector3) : void Dibuja una caja de alambre con centro y tamao.

DrawCube: static function DrawCube (center : Vector3, size : Vector3) : void Dibuja una caja slida con centro y tamao.

DrawIcon: static function DrawIcon (center : Vector3, name : String) : void Dibuja un icono en posicin global en la vista de escena. El icono deber tener el mismo nombre que le asignamos al parmetro name y estar ubicado en las coordenadas que le pasemos al parmetro center. El path del icono puede encontrarse en la carpeta Assets/Gizmos. Vamos por partes: Antes que nada necesitamos una imagen tipo icono. Yo para el ejemplo he usado sta. Renombramos a la imagen como "nave". Por otro lado, en el archivo donde estamos guardando estos ejemplos, dentro de la carpeta assets, hemos de crear una carpeta llamada Gizmos, que es el path que Unity buscar para dar con los iconos de este tipo. Luego arrastramos nuestra nave a la recin creada carpeta. Y ahora editamos el script: function OnDrawGizmos () { Gizmos.DrawIcon (transform.position + Vector3(0,2,0), "nave.png"); } Pulsamos el play, y dos metros por encima de nuestra esfera debera aparecernos la nave, tal que as:

DrawGUITexture: static function DrawGUITexture (screenRect : Rect, texture : Texture, mat : Material = null) : void static function DrawGUITexture (screenRect : Rect, texture : Texture, leftBorder : int, rightBorder : int, topBorder : int, bottomBorder : int, mat : Material = null) : void Dibuja una textura en coordenadas de pantalla. Es til para backgrounds de GUI.

41. CLASE LIGHTMAPSETTINGS

Almacena los mapas de luces (lightmaps) de la escena. Una escena puede tener varios lightmaps almacenados en ella, y suss componentes Renderer pueden usar esos lightmaps. Esto hace posible usar el mismo material en mltiples objetos, mientras cada objeto puede referirse a diferentes lightmaps o diferentes porciones del mismo lightmap.

VARIABLES DE CLASE: lightmaps: static var lightmaps : LightmapData[] Es un array de tipo LightmapData que puede almacenar diferentes lightmaps. LightmapData es una clase con dos variables: lightmapFar: lightmapNear: Lightmap que almacena la totalidad de la luz entrante. Lightmap que almacena slo la luz indirecta entrante.

lightsmapMode: static var lightmapsMode : LightmapsMode Modo de renderizado de lightmaps. LightmapsMode es una enumeracin con los siguientes dos valores: Single: Dual: Modo de renderizado de lightmap tradicional. Modo de renderizado de lightmap dual.

42. ESTRUCTURA MATHF

Estructura que contiene una coleccin de funciones matemticas que podemos usar para nuestros scripts.

VARIABLES DE CLASE: PI: static var PI : float El famoso 3.141592. (slo lectura) Como pequea anotacin, observad que las variables de clase de Mathf comienzan por mayscula, al contrario de las variables de clase del resto de clases y funciones en Unity. Tenedlo presente, ya que es una fuente importante de errores.

Infinity: static var Infinity : float Representacin del infinito positivo (slo lectura)

NegativeInfinity: static var NegativeInfinity : float Una representacin del infinito negativo (slo lectura)

Deg2Rad: static var Deg2Rad : float Conversin constante de grados a radianes (slo lectura)

Rad2Deg: static var Rad2Deg : float Conversin constante de radianes a grados (slo lectura)

Epsilon: static var Epsilon : float El valor ms pequeo que un float puede tener diferente de cero (slo lectura)

FUNCIONES DE CLASE: Sin: static function Sin (f : float) : float

Devuelve el seno del ngulo f en radianes.

Cos: static function Cos (f : float) : float Devuelve el coseno del ngulo f en radianes.

Tan: static function Tan(f : float) : float Devuelve la tangente del ngulo f en radianes.

Asin: static function Asin (f : float) : float Devuelve el arco seno de f menos el ngulo en radianes cuyo seno es f.

Acos: static function Acos (f : float) : float Devuelve el arco coseno de f menos el ngulo en radianes cuyo coseno es f.

Atan: static function Atan (f : float) : float Devuelve el arco tangente de f menos el ngulo en radianes cuya tangente es f.

Atan2: static function Atan2 (y : float, x : float) : float Devuelve el ngulo en radianes cuya tangente es y/x. El valor retornado es el ngulo entre el eje X y un vector 2D que empieza en cero y acaba en (x,y)

Sqrt: static function Sqrt (f : float) : float Devuelve la raz cuadrada de f.

Abs: static function Abs (value : float) : float static function Abs (value : int) : int Devuelve el valor absoluto de value.

Min: static function Min (a : float, b : float) : float static function Min (params values : float[]) : float static function Min (a : int, b : int) : int static function Min (params values : int[]) : int Devuelve el valor mnimo de dos o ms valores dados.

Max: static function Max (a : float, b : float) : float static function Max (params values : float[]) : float static function Max (a : int, b : int) : int static function Max (params values : int[]) : int Devuelve el valor mximo de dos o ms valores.

Pow: static function Pow (f : float, p : float) : float Devuelve f elevado a la potencia p.

Exp: static function Exp (power : float) : float Devuelve la potencia natural de un determinado nmero.

Log: static function Log (f : float, p : float) : float static function Log (f : float) : float Devuelve el logaritmo de un determinado nmero en una base especificada.

Log10: static function Log10 (f : float) : float Devuelve el logaritmo en base diez de un determinado nmero.

Ceil: static function Ceil (f : float) : float Devuelve el integer ms pequeo igual o mayor que f.

Floor: static function Floor (f : float) : float Devuelve el mayor integer igual o ms pequeo que f.

Round: static function Round (f : float) : float Devuelve f redondeado al integer ms cercano. Si el nmero acaba en .5 y queda entre dos integers, uno de los cuales es par y el otro impar, se devolver el numero par.

CeilToInt: static function CeilToInt (f : float) : int Devuelve el integer ms pequeo igual o mayor que f.

FloorToInt: static function FloorToInt (f : float) : int Devuelve el mayor integer menor o igual que f.

RoundToInt: static function RoundToInt (f : float) : int Devuelve f rendondeada al integer ms cercano. Si e nmero acaba en .5 y por lo tanto est a medio camino entre dos integers, uno impar y el otro par, se devuelve el nmero par.

Sign: static function Sign (f : float) : float Devuelve el signo de f. Devuelve 1 si es positivo o cero, y -1 si f es negativo.

Clamp: static function Clamp (value : float, min : float, max : float) : float static function Clamp (value : int, min : int, max : int) : int Restringe un valor entre un mnimo y un mximo, sean floats o ints. Vamos a verlo con un ejemplo: for(var x : int = 0; x <= 10; x++) { var numeroFijado : int = Mathf.Clamp(x, 1, 5); Debug.Log(numeroFijado); } Mediante un bucle for le pasamos como primer parmetro a la funcin Clamp nmeros del 10 al diez. Si desplegamos la consola tras probar este ejemplo veremos que cuando x vale 0, clamp devuelve el valor mnimo fijado (en este caso 1). Lo mismo pasa cuando x vale ms de 5.

Clamp01: static function Clamp01 (value : float) : float Fija un valor entre 0 y 1 y lo devuelve.

Lerp: static function Lerp (from : float, to : float, t : float) : float Interpola a hacia b pasando por t. t queda fijada entre 0 y 1. Cuando t = 0 devuelve from. Cuando t = 1 devuelve to. Cuando t = 0.5 devuelve la media de a y b.

LerpAngle: static function LerpAngle (a : float, b : float, t : float) : float Lo mismo que lerp, pero asegurndonos de interpolar valores correctamente cuando d un giro de 360 grados. Las variables a y b representan grados. Para ilustrar esta funcin y la anterior vamos a apaar un pequeo ejemplo. Sera interesante que eliminrais el script vinculado a la esfera. Editamos: var var var var origen = -2.0; destino = 1.0; anguloInicial= 0.0; anguloFinal= 90.0;

function Update () { transform.position = Vector3(Mathf.Lerp(origen, destino, Time.time * 0.1), 0, 0); var angle : float = Mathf.LerpAngle(anguloInicial, anguloFinal, Time.time * 0.1); transform.eulerAngles = Vector3(0, angle, 0); } Salvamos y vinculamos el script al cubo. A la funcin Lerp le pasamos el parmetro de situacin inicial -2, que coincide con su posicin actual en el eje x, y le indicamos un destino en 1. Tradicionalmente como tercer parmetro se coloca Time.time, que pasa de 0 a 1 en un segundo, pero como queremos que el trayecto sea ms lento, multiplicamos Time.time por 0.1, de tal manera que el trayecto total dure 10 segundos. Otro tanto hacemos con el angulo inicial y final. Como resultado, el cubo se mover tres metros en el eje X y girar 90 grados sobre el eje Y en diez segundos.

MoveTowards: static function MoveTowards (current : float, target : float, maxDelta : float) : float Mueve el valor que indicamos en el parmetro current hacia el que indicamos en target. Hasta aqu la funcin sera parecida a Mathf.Lerp, pero aqu nos aseguramos de la que velocidad no exceda de maxDelta. Valores negativos para maxDelta empuja el valor lejos del objetivo.

MoveTowardsAngle: static function MoveTowardsAngle (current : float, target : float, maxDelta : float) : float Lo mismo que MoveTowards pero estando seguros de que los valores se interpolarn correctamente cuando gire 360 grados. La diferencia de MoveTowards y MoveTowardsAngle con respecto de Lerp y LerpAngle la veremos ms fcilmente rehaciendo el script anterior: var var var var origen = -2.0; destino = 1.0; minAngle = 0.0; maxAngle = 90.0;

function Update () { transform.position = Vector3(Mathf.MoveTowards(origen, destino, Time.time * 1), 0,0); var angle : float = Mathf.MoveTowardsAngle(minAngle, maxAngle, Time.time * 30); transform.eulerAngles = Vector3(0, angle, 0); } La diferencia la tenemos que hallar en el tercer parmetro. En el caso de MoveTowards lo que le estamos pidiendo aqu al cubo es que se mueva en el eje x de la posicin -2 a la 1 (3 metros, o sea) a razn de un metro por segundo. Y Para MoveTowardsAngle estamos indicndole al cubo que gire 90 grados a razn de 30 grados por segundo. De esta manera, en 3 segundos el cubo debera haber completado ambos movimientos. Probadlo.

SmoothStep: static function SmoothStep (from : float, to : float, t : float) : float Interpola entre mnimo y mximo y facilita entrada y salida de los lmites. Sera como Lerp, pero con un impulso inicial. Si meramente sustitus em el ltimo script MoveTowards por SmoothStep veris a qu me refiero.

Approximately: static function Approximately (a : float, b : float) : boolean Compara si dos valores en punto flotante son similares. Debido a que los numeros en punto flotante son imprecisos no es recomendable compararlos usando el operador == (podra no devolver true), y es mejor utilizar esta funcin.

SmoothDamp: static function SmoothDamp (current : float, target : float, ref currentVelocity : float, smoothTime : float, maxSpeed : float = Mathf.Infinity, deltaTime : float = Time.deltaTime) : float Gradualmente cambia un valor hacia un objetivo en un determinado tiempo. La funcin se puede usar para suavizar la transicin de valores, colores, posiciones, escalares. Cuenta con los siguientes parmetros:

current target currentVelocity smoothTime maxSpeed deltaTime

La posicin actual. La posicin que estamos tratando de alcanzar. La velocidad actual. Este valor es modificado por la funcin cada vez que la llamamos. Aproximadamente el tiempo que tardaremos en alcanzar el objetivo. Un valor pequeo har que allcancemos el objetivo ms rpido. Opcionalmente nos permite fijar la velocidad mxima. El tiempo desde la ltima llamada a esta funcin. Por defecto Time.deltaTime.

Un ejemplo: var objetivo : Transform; var tiempoEmpleado = 3; private var yVelocity =4.0; function Update () { var newPosition : float = Mathf.SmoothDamp(transform.position.x, objetivo.position.x, yVelocity, tiempoEmpleado); transform.position = Vector3(newPosition, transform.position.y, transform.position.z); } Salvamos y arrastramos el cubo a la variable expuesta "objetivo". Lo que aqu estamos haciendo es usar la funcin SmoothDamp para ir marcando la nueva posicin de nuestro cubo. El punto de origen ser la posicin actual del cubo (en el eje x), el destino la posicin actual en dicho eje del transform que marcamos como objetivo, le establecemos un tiempo para que el origen alcance al objetivo de 3 segundos y le limitamos la velocidad mxima que pueda alcanzar nuestro cubo a cuatro metros por segundo.

SmoothDampAngle: static function SmoothDampAngle (current : float, target : float, ref currentVelocity : float, smoothTime : float, maxSpeed : float = Mathf.Infinity, deltaTime : float = Time.deltaTime) : float Cambia gradualmente un ngulo dado en grados hacia el ngulo que constituye el objetivo en un tiempo determinado. El uso ms comn de esta funcin es para suavizar una cmara que est siguiendo algn personaje o escena.

Repeat: static function Repeat (t : float, length : float) : float Introduce en un bucle el valor t, de tal manera que nunca sea ms grande que length y nunca ms pequeo que 0.

PingPong: static function PingPong (t : float, length : float) : float Hace rebotar el valor t, de tal manera que nunca sea mayor que length y nunca mayor que 0. El valor retornado se mover atrs y adelante entre 0 y length.

InverseLerp: static function InverseLerp (from : float, to : float, value : float) : float Calcula el parmetro Lerp entre dos valores.

ClosestPowerOfTwo: static function ClosestPowerOfTwo (value : int) : int Retorna la potencia de dos ms cercana.

IsPowerOfTwo: static function IsPowerOfTwo (value : int) : boolean Devuelve true si el valor es potencia de dos

NextPowerOfTwo: static function NextPowerOfTwo (value : int) : int Devuelve el valor de la siguiente potencia de dos.

DeltaAngle: static function DeltaAngle (current : float, target : float) : float Calcula la diferencia ms corta entre dos ngulos dados.

43. CLASE PHYSICS

Componen esta clase, al igual que la estructura Mathf anterior, propiedades globales y mtodos de ayuda relacionados con las fsicas.

VARIABLES DE CLASE: gravity: static var gravity : Vector3 La gravedad aplicada a todos los rigidbodies en la escena. Puede ser desconectada para un rigidbody individual usando su propiedad useGravity.

FUNCIONES DE CLASE: Raycast: static function Raycast (origin : Vector3, direction : Vector3, distance : float = Mathf.Infinity, layerMask : int = kDefaultRaycastLayers) : boolean Lanza un rayo contra todos los colliders en la escena. Devuelve true cuando el rayo intersecta algn collider. Tiene los siguientes parmetros: origin: direction: distance: layerMask: El punto inicial del rayo en coordenadas globales. La direccin del rayo. La longitud o fuerza del rayo. Una mscara de distribucin (Layer mask) que se usa para ignorar selectivamente colliders cuando se proyecta un rayo.

Por ejemplo: function Update () { var derecha : Vector3 = transform.TransformDirection (Vector3.right); if (Physics.Raycast (transform.position, derecha, 10)) { print ("Hay algo a mi derecha"); } } Lo que hacemos aqu es primero tomar la direccin local de nuestro cubo y convertirla en direccin global, a travs de la funcin TransformDirection. Dicha direccin global la almacenamos en la variable "derecha". Acto seguido, imprimimos un mensaje si desde la posicin de nuestro cubo en una distancia no superior a diez metros hay a la derecha global del mismo otro objeto. static function Raycast (origin : Vector3, direction : Vector3, out hitInfo : RaycastHit, distance : float = Mathf.Infinity, layerMask : int = kDefaultRaycastLayers) : boolean Proyecta un rayo contra todos los colliders en la escena y devuelve informacin detallada sobre qu golpe.

Los parmetros de este segundo prototipo de funcin son: origin direction distance hitInfo layerMask El punto de inicio del rayo en coordenadas globales. La direccin del rayo. La fuerza o longitud del rayo. Si se devuelve true, esta variable contendr ms informacin sobre donde colision el collider. Un layer mask usado para ignorar colliders selectivamente cuando se proyecte un rayo.

static function Raycast (ray : Ray, distance : float = Mathf.Infinity, layerMask : int = kDefaultRaycastLayers) : boolean static function Raycast (ray : Ray, out hitInfo : RaycastHit, distance : float = Mathf.Infinity, layerMask : int = kDefaultRaycastLayers) : boolean Son similares a las funciones anteriores, slo que usando ray.origin y ray.direction en vez de origen y direccin como sendos Vector3.

RaycastAll: static function RaycastAll (ray : Ray, distance : float = Mathf.Infinity, layerMask : int = kDefaultRaycastLayers) : RaycastHit[] static function RaycastAll (origin : Vector3, direction : Vector3, distance : float = Mathf.Infinity, layermask : int = kDefaultRaycastLayers) : RaycastHit[] Lanza un rayo a travs de la escena y devuelve todos los choques. Vamos a adaptar un ejemplo del manual de referencia: function Update () { var choques : RaycastHit[]; choques = Physics.RaycastAll (transform.position, transform.right, 100.0); for (var i = 0;i < choques.Length; i++) { var miChoque : RaycastHit = choques[i]; var renderer = miChoque.collider.renderer; if (renderer) { renderer.material.shader = Shader.Find("Transparent/Diffuse"); renderer.material.color.a = 0.3; } } } Vamos paso a paso en la explicacin. Primero declaramos una variable que contendr un array de tipo RaycastHit, que es precisamente lo que hemos visto que devuelve la funcin RaycastAll. La inicializamos con todas aquellas colisiones que sufra nuestro rayo, el cual proyectamos desde el cubo 100 metros a la derecha. Dado que puede haber ms de una colisin, iteramos a travs del array y el collider con el que se ha producido cada colisin le es asignado temporalmente a la variable miChoque, a travs de la cual lo volvemos semitransparente. Si pulsamos play vemos que nuestra esfera se torna semiinvisible.

LineCast: static function Linecast (start : Vector3, end : Vector3, layerMask : int = kDefaultRaycastLayers) : boolean Devuelve true si hay algn collider intersectando la lnea entre start y end. static function Linecast (start : Vector3, end : Vector3, out hitInfo : RaycastHit, layerMask : int = kDefaultRaycastLayers) : boolean En este segundo prototipo, si se devuelve true, hitinfo contendr ms informacin sobre dnde colision el collider.

OverlapSphere: static function OverlapSphere (position : Vector3, radius : float, layerMask : int = kAllLayers) : Collider[] Devuelve un array con todos los colliders que toquen o estn dentro de la esfera cuya posicin y radio pasamos como parmetros.

CapsuleCast: static function CapsuleCast (point1 : Vector3, point2 : Vector3, radius : float, direction : Vector3, distance : float = Mathf.Infinity, layerMask : int = kDefaultRaycastLayers) : boolean static function CapsuleCast (point1 : Vector3, point2 : Vector3, radius : float, direction : Vector3, out hitInfo : RaycastHit, distance : float = Mathf.Infinity, layerMask : int = kDefaultRaycastLayers) : boolean Lanza una cpsula contra todos los colliders de la escena y devuelve informacin de contra qu ha chocado. Devuelve true cuando el sweep (barrido) de la cpsula choca con algn collider. Los parmetros de esta funcin son: point1 point2 radius direction hitInfo distance layerMask El inicio de la cpsula. El fin de la cpsula. El radio de la cpsula. La direccin en la cual hace el barrido la cpsula. Si devuelve true, hitInfo contendr ms informacin sobre dnde golpe el collider. La longitud del barrido. Un Layer mask que se usa para ignorar selectivamente colliders cuando se proyecte la cpsula.

La cpsula viene conformada por las dos esferas con radios alrededor del point1 y point2, que forman los dos finales de la cpsula. Esto es til cuando un Raycast no tiene suficiente precisin para lo que queremos hacer, como por ejemplo asegurarnos de que un personaje podr moverse a cualquier sitio sin colisionar con nada en el camino.

SphereCast: static function SphereCast (origin : Vector3, radius : float, direction : Vector3, out hitInfo : RaycastHit, distance : float = Mathf.Infinity, layerMask : int = kDefaultRaycastLayers) : boolean Proyecta una esfera contra todos los colliders de la escena y proporciona informacin sobre los que colisionan. Devuelve true si topa con alguno en su barrido. Cuenta con estos parmetros:

origin radius direction hitInfo distance layerMask

El centro de la esfera al principio del barrido. El radio de la esfera. La direccin en la cual hace el barrido la esfera. Si la funcin devuelve true, esta variable contendr ms informacin acerca de dnde el collider colision (Para ms informacin ver: RaycastHit). La longitud del barrido. Un Layer mask que se usa para ignorar selectivamente colliders cuando se proyecta la cpsula.

Esta funcin es til cuando un Raycast no nos da suficiente precisin, como por ejemplo en el caso en que queramos averiguar si un objeto de un determinado tamao, como un character, ser capaz de de moverse a algn lado sin colisionar con algo por el camino. En casos como estos es preferible usar la funcin SphereCast. Hemos de tener presente, eso s, que la SphereCast no funcionar contra aquellos colliders configurados como triggers. Probemos un ejemplo. Previamente hay que aadirle un character controller al cubo. Acto seguido tecleamos este script: function Update () { var hit : RaycastHit; var charCtrl : CharacterController = GetComponent(CharacterController); var p1 : Vector3 = transform.position + charCtrl.center; if (Physics.SphereCast (p1, charCtrl.height /2, transform.right, hit, 10)) { Debug.Log("Hay un obstculo a " + hit.distance + " metros"); } } Lo que hemos hecho aqu es, a grandes rasgos, que nuestro cubo efecte un barrido hacia la derecha en busca de obstculos para un character con un radio equivalente a la mitad de la altura de nuestro character. Al topar con uno, se muestra un mensaje en pantalla junto con informacin suplementaria, como en este caso la distancia a que se halla dicho obstculo. El ejemplo es un poco rupestre, pero nos permite intuir la utilidad de esta funcin para aplicrsela a un personaje. static function SphereCast (ray : Ray, radius : float, distance : float Mathf.Infinity, layerMask : int = kDefaultRaycastLayers) : boolean static function SphereCast (ray : Ray, radius : float, out hitInfo : RaycastHit, distance : float = Mathf.Infinity, layerMask : int = kDefaultRaycastLayers) : boolean

CapsuleCastAll: static function CapsuleCastAll (point1 : Vector3, point2 : Vector3, radius : float, direction : Vector3, distance : float = Mathf.Infinity, layermask : int = kDefaultRaycastLayers) : RaycastHit[] Es como Physics.CapsuleCast, pero devolviendo todos los colliders que la cpsula intercepta en su barrido e informacin sobre los mismos. Devuelve un array con todos esos colliders. Parmetros: point1 point2 radius direction distance layerMask El principio de la cpsula. El final de la cpsula. El radio de la cpsula. La direccin en la cual efecta el barrido la cpsula. La longitud del barrido. Un Layer mask que se usa para ignorar selectivamente algunos colliders cuando se proyecta la cpsula

La cpsula es definida por las dos esferas con su radio alrededor de point1 y point2, que forman los dos extremos de la cpsula. Son devueltos datos de todos los colliders contra los que nuestra cpsula proyectada choque en esa direccin.

Recordemos que esta funcin no funciona contra colliders configurados como triggers.

SphereCastAll: static function SphereCastAll (origin : Vector3, radius : float, direction : Vector3, distance : float = Mathf.Infinity, layerMask : int = kDefaultRaycastLayers) : RaycastHit[] static function SphereCastAll (ray : Ray, radius : float, distance : float = Mathf.Infinity, layerMask : int = kDefaultRaycastLayers) : RaycastHit[] Como physics.SphereCast, pero devolviendo todos los colliders que colisionen.

CheckSphere: static function CheckSphere (position : Vector3, radius : float, layerMask : int = kDefaultRaycastLayers) : boolean Devuelve true si hay algn collider tocando la esfera definida por position y radius en coordenadas globales.

CheckCapsule: static function CheckCapsule (start : Vector3, end : Vector3, radius : float, layermask : int = kDefaultRaycastLayers) : boolean Devuelve true si hay algn collider tocando la cpsula definida por el eje que va de start a end y que tiene el radio radius, en coordenadas globales.

IgnoreCollision: static function IgnoreCollision (collider1 : Collider, collider2 : Collider, ignore : boolean = true) : void Hace que el sistema de deteccin de colisiones ignore todas las colisiones entre collider1 y collider2. Esto es muy til por ejemplo para que los proyectiles no colisionen con el objeto que los dispara.

Esta funcin tiene algunas limitaciones: 1.- No es persistente. Esto significa que el estado de ignorar colisin no ser almacenado en el editor cuando se salve la escena. 2.- Slo puedes aplicar esta funcin a colliders en gameobjects activos. Cuando se desactiva el collider o el rigidbody vinculado se pierde el estado de IgnoreCollision y tendrs que llamar a esta funcin otra vez.

IgnoreLayerCollision: static function IgnoreLayerCollision (layer1 : int, layer2 : int, ignore : boolean = true) : void Hace que el sistema de deteccin de colisiones ignore todas las colisiones entre cualquier collider en layer1 y otros en layer2.

GetIgnoreLayerCollision: static function GetIgnoreLayerCollision (layer1 : int, layer2 : int) : boolean Booleano que indica si las colisiones entre layer1 y layer2 estn siendo ignoradas.

44. ESTRUCTURA QUATERNION

Nuestros amigos los quaterniones son usados para representar rotaciones. Unity internamente usa Quaterniones para representar todas las rotaciones. Sin embargo, los quaterniones estn basados en nmeros complejos y no son fciles de entender intuitivamente, as que casi nunca accederemos o modificaremos los componentes individuales de un Quaternin (x,y,z,w). Lo que ser ms habitual es que queramos meramente tomar rotaciones ya existentes (por ej desde un Transform) y usarlas para construir nuevas rotaciones (por ej interpolando suavemente entre dos rotaciones). Las funciones sobre Quaterniones que usaremos el 99% del tiempo (las otras funciones son para usos exticos) son Quaternion.LookRotation, Quaternion.Angle, Quaternion.Euler, Quaternion.Slerp, Quaternion.FromToRotation y Quaternion.identity.

VARIABLES: eulerAngles: var eulerAngles : Vector3 Devuelve la representacion en ngulos euler de la rotacion.

FUNCIONES: ToAngleAxis: function ToAngleAxis (out angle : float, out axis : Vector3): void Convierte una rotacin en una representacin de angle-axis (ngulo de eje)

SetFromToRotation: function SetFromToRotation (fromDirection : Vector3, toDirection : Vector3) : void Crea una rotacin que rota desde fromDirection hasta toDirection.

ToString: function ToString () : String function ToString (format : String) : String Devuelve un string formateado del Quaternion.

VARIABLES DE CLASE: identity: static var identity : Quaternion Sera el equivalente a no rotation. El transform quedar perfectamente alineado con el mundo o con los ejes del padre.

FUNCIONES DE CLASE: AngleAxis: static function AngleAxis (angle : float, axis : Vector3) : Quaternion Crea una rotacin que rota los ngulos que le pasemos como primer parmetro con respecto al eje que le pasamos como segundo. O sea, para girar nuestro cubo (previamente eliminadle el character controller que le aadimos el captulo anterior), tecleamos: transform.rotation = Quaternion.AngleAxis(30, Vector3.up); De esta forma tan simple giramos el cubo 30 grados sobre el eje Y.

FromToRotation: static function FromToRotation (fromDirection : Vector3, toDirection : Vector3) : Quaternion Crea una rotacin que rota desde el primer parmetro al segundo. Normalmente usaremos esta funcin para rotar un transform uno de cuyos ejes sigue un objetivo en una direccin en coordenadas globales.

Slerp: static function Slerp (from : Quaternion, to : Quaternion, t : float) : Quaternion Interpola esfriamente del primer al segundo parmetro durante el tercero.

RotateTowards: static function RotateTowards (from : Quaternion, to : Quaternion, maxDegreesDelta : float) : Quaternion Efecta una rotacin entre el primer parmetro y el segundo. Esto es esencialmente lo mismo que Quaternion.Slerp, pero aqu la funcin se aregura de que la velocidad angular nunca exceda de la marcada en maxDegreesDelta. Si maxDegreesDelta tiene un valor negativo la rotacin es empujada lejos del segundo parmetro (to).

Angle: static function Angle (a : Quaternion, b : Quaternion) : float Devuelve el ngulo en grados entre dos rotaciones dadas. Veamos eso: var objetivo : Transform; function Update () { var angulo : float = Quaternion.Angle(transform.rotation, objetivo.rotation); Debug.Log(angulo); } Arrastramos la esfera a la variable expuesta objetivo. Si pulsamos play, observaremos que nos aparece un cero en pantalla, ya que (si teneis ambas figuras colocadas como yo) ambas tienen sus respectivas rotaciones a 0,0,0. Probad ahora a cambiar la rotacin de una -o las dos- figuras.

Euler: static function Euler (x : float, y : float, z : float) : Quaternion static function Euler (euler : Vector3) : Quaternion Devuelve en quaterniones una rotacin pasada como parmetro en grados Euler.

45. CLASE RANDOM

Clase para generar nmeros aleatorios.

VARIABLES DE CLASE: seed: static var seed : int Coloca la semilla para el generador de nmeros aleatorios.

value: static var value : float Devuelve un nmero aleatorio entre 0.0 (inclusive) y 1.0 (inclusive). for(var x: int =0; x<10; x++){ print(Random.value); } Podris comprobar que los diez nmeros que nos aparecern en pantalla estn entre ambos valores.

insideUnitSphere: static var insideUnitSphere : Vector3 Devuelve un punto aleatorio dentro de una esfera con radio 1. transform.position = Random.insideUnitSphere * 2; Este ejemplo situara nuestro cubo en un punto aleatorio dentro de una esfera (3 dimensiones) con un radio de 2 unidades.

insideUnitCircle: static var insideUnitCircle : Vector2 Devuelve un punto aleatorio dentro de un crculo con radio 1. var newPosition : Vector2 = Random.insideUnitCircle * 5; transform.position.x = newPosition.x; transform.position.y = newPosition.y; en este caso nuestro cubo se movera dentro de un crculo (2D) con radio de 5 unidades.

onUnitSphere: static var onUnitSphere : Vector3 Devuelve un punto aleatorio sobre la superficie de una esfera con radio 1. function FixedUpdate(){ rigidbody.velocity = Random.onUnitSphere * 10; } Esta funcin mueve al rigidbody de nuestro cubo a una velocidad de 10 en una direccin aleatoria, por lo que no esperis ver otra cosa al darle al play que un cubo volvindose loco.

rotation: static var rotation : Quaternion Devuelve una rotacin aleatoria (read only) var prefab : GameObject; Instantiate(prefab, Vector3.zero, Random.rotation); Este ejemplo instanciara un nuevo gameobject en el centro de la escena y con una rotacin aleatoria.

FUNCIONES DE CLASE: Range: static function Range (min : float, max : float) : float Devuelve un float aleatorio entre un min (inclusive) y max (inclusive). var prefab : GameObject; function Start () { var position: Vector3 = Vector3(Random.Range(-5.0, 5.0), 0, Random.Range(-5.0, 5.0)); Instantiate(prefab, position, Quaternion.identity); } Si arrastramos la esfera a la variable expuesta prefab, al darle al play observaremos que se clona una instancia de la misma y aparece en un lugar aleatorio en un margen de 5 metros en los ejes X y Z. static function Range (min : int, max : int) : int La misma funcin, pero admite y devuelve integers.

46. ESTRUCTURA RAY

Estructura que nos permite representar y modificar rayos. Un rayo es una linea infinita que empieza en un punto dado y va en alguna direccin.

VARIABLES: origin: var origin : Vector3 El punto de origen del rayo.

direction: var direction : Vector3 La direccin del rayo. La direccin es siempre un vector normalizado(1,0,0 o 0,1,0 o 0,0,1. Si asignamos un vector de longitud distinta de la unidad, ser normalizado.

FUNCIONES:

Ray: static function Ray (origin : Vector3, direction : Vector3) : Ray Crea un rayo que empieza en origin a lo largo de direction. var ray = new Ray (transform.position, transform.forward); En este ejemplo crearamos un rayo que parte de la posicin del transform al que est vinculado el script y que parte hasta el infinito a travs del eje Z.

GetPoint: function GetPoint (distance : float) : Vector3 Devuelve un punto tantas unidades como le pasemos en el parmetro a lo largo del rayo. var r : Ray; print( r.GetPoint (10) ); Este ejemplo imprime un punto situado 10 unidades a lo largo del rayo.

ToString: function ToString () : String function ToString (format : String) : String Devuelve un string formateado para este rayo.

47. ESTRUCTURA RAYCASTHIT

Estructura usada para obtener informacin de vuelta de un raycast (rayo proyectado).

VARIABLES: point: var point : Vector3 El punto de impacto en coordenadas globales donde el rayo golpea el collider

normal: var normal : Vector3 El normal de la superficie que golpea el rayo.

baryentricCoordinate: var barycentricCoordinate : Vector3 La coordenada baricntrica del tringulo que golpeamos (baricentro = es un punto de una figura geomtrica la recta que pasa por el cual divide la figura en dos partes iguales. ) Esto nos permite interpolar cualquiera de los datos de los vrtices a lo largo de los tres ejes.

distance: var distance : float La distancia desde el origen del rayo hasta el punto de impacto.

triangleIndex: var triangleIndex : int el ndice del tringulo que ha sido golpeado. El ndice del tringulo es slo vlido si el colider que lo golpea es un MeshCollider.

textureCoord: var textureCoord : Vector2 La coordenada de la textura UV en el punto de impacto. Esto puede ser usado para pinturas de textura 3d o impactos de bala dibujados. Si el collider no es una mesh collider, retorna un Vector2 a cero.

textureCoord2: var textureCoord2 : Vector2 Las coordenadas de la textura uv secundaria.

lightmapCoord: var lightmapCoord : Vector2 La coordinada del lightmap de uv en el punto de impacto.

colider: var collider : Collider El collider que fue golpeado. Esta propiedad es nula si no se golpea nada y no-nula si golpeas algo.

rigidbody: var rigidbody : Rigidbody El rigidbody del collider que ha sido golpeado. Si el collider no est vinculado a un rigidbody es null.

transform: var transform : Transform El Transform del rigidbody o collider que ha sido golpeado.

48. ESTRUCTURA RECT

Variables y funciones para la creacin y manejo de un rectngulo 2D definido por la posicin x,y y anchura, altura. La estructura Rect es principalmente usada para operaciones 2D; el sistema UnityGUI la usa extensamente, adems del posicionado de cmaras en la pantalla.

VARIABLES: x: var x : float Coordenada izquierda del rectngulo (a lo largo del eje X).

y: var y : float Coordenada superior del rectngulo.

width: var width : float Anchura del rectngulo.

height: var height : float Altura del rectngulo.

xMin: var xMin : float Coordenada izquierda del rectngulo. Cambiando este valor conservamos el lado derecho del rectngulo (as width cambia tambin)

yMin: var yMin : float Coordenada superior del rectngulo. Cambiando este valor conservamos el lado inferior del rectngulo (as height cambiar tambin)

xMax: var xMax : float Coordenada derecha del rectnculo. Cambiando este valor seguimos conservando el lado izquierdo del rectngulo, por lo que la anchura cambiar tambin.

yMax: var yMax : float Coordenada inferior del rectngulo. Cambiando este valor seguimos conservando el lado superior del rectngulo, as que la altura cambiar tambin.

FUNCIONES: Rect: static function Rect (left : float, top : float, width : float, height : float) : Rect Crea un nuevo rectngulo.

Contains: function Contains (point : Vector2) : boolean function Contains (point : Vector3) : boolean Devuelve true si los componentes x e y del parmetro point conforman un punto dentro del rectngulo Un breve ejemplo explicativo: function Update () { var rect = Rect (0, 0, 150, 150); if (rect.Contains(Input.mousePosition)) print("Dentro del rectngulo"); else print ("Fuera del rectngulo"); } Hemos creado primero un plano a partir de las coordenadas 0(izquierda), 0(abajo), con 150 metros/unidades de ancho (a contar desde la izquierda) y otras tantas de alto(contadas desde abajo). Por lo tanto si el ratn lo ubicamos hacia la zona superior derecha se nos mostrar el mensaje de que estamos fuera del rectngulo y si hacemos lo propio hacia la zona inferior izquierda estaremos dentro del rectngulo.

FUNCIONES DE CLASE: MinMaxRect: static function MinMaxRect (left : float, top : float, right : float, bottom : float) : Rect Crea un rectngulo entre min/max valores de coordenadas.

49. CLASE RENDERSETTINGS

Esta clase se corresponde con las variables que podemos encontrar en el inspector si nos vamos al men=>edit=>Render Settings. Contiene valores para un rango de elementos visuales en tu escena, como niebla y luz de ambiente.

VARIABLES DE CLASE: fog: static var fog : boolean Est habilitada la niebla?

fogMode: static var fogMode : FogMode Modo de niebla a usar. FogMode es una enumeracin que admite los siguientes valores: Linear: Exponential: ExponentialSquared: Niebla lineal. Niebla exponencial. Niebla exponencial al cuadrado (por defecto).

fogColor: static var fogColor : Color El color de la niebla.

fogDensity: static var fogDensity : float La densidad de la niebla exponencial. Resumamos lo visto con un ejemplo: RenderSettings.fog = true; RenderSettings.fogColor = Color.blue; RenderSettings.fogDensity = 0.1; Pulsamos play y habremos activado la niebla, que ser de color azul y con una densidad de 0.1.

fogStartDistance: static var fogStartDistance : float La distancia inicial de la niebla lineal. Las distancias de inicio y final de la niebla son usadas por el modo de niebla Linear.

fogEndDistance: static var fogEndDistance : float La distancia final de la niebla lineal (slo para modo Linear).

ambientLight: static var ambientLight : Color Color de la luz de ambiente de la escena.

haloStrength: static var haloStrength : float Tamao del halo de luz. Para cualquier luz, el tamao del halo es este valr multiplicado por Light.range.

flareStrength: static var flareStrength : float La intensidad de las llamas/destellos en la escena. Vamos a hacer un ejemplo progresivo de la utilidad de estas ltimas variables. En primer lugar, eliminamos el script que tenemos vinculado al cubo. Acto seguido editamos MiPrimerScript como sigue: RenderSettings.ambientLight = Color.green; Salvamos y arrastramos a PortaScipts. Al darle al play deberamos tener una luz de ambiente as:

Dmonos cuenta que no ha sido preciso vincularle el script a la luz principal para que tenga efecto. Ahora nos vamos al men=>Gameobject=>Create other=>SpotLight. Ubicamos nuestra nueva luz en las coordenadas 0,3,0, con una rotacin de 90,0,0, para que se note claramente su efecto y los posteriores cambios. En el inspector, asimismo, marcar la casilla que pone "draw hallo". Ya que al inicio de este repaso por las clases no cargamos ningn asset, nos faltar uno para completar nuestro ejemplo, as que vamos a men=>assets=>import Package=>Light Flares. Importamos. Ahora, de nuevo en el inspector de nuestra spotlight hacemos click en la pequea fleha que encontramos junto a Flare y seleccionamos Small Flare. Podemos ya reescribir nuestro script: RenderSettings.ambientLight = Color.green; yield WaitForSeconds(5); RenderSettings.haloStrength = 0.2; RenderSettings.flareStrength = 0.2; Dadle al play y observar los cambios transcurridos 5 segundos. HaloStrength afectar al dimetro del haz de luz que pega contra el suelo (la galleta o cookie, que dicen los anglosajones). FlareStrength en cambio se refiere a ese tipo de brillo que emite la fuente de la luz en su origen.

skybox: static var skybox : Material El skybox global en uso.

50. CLASE SCREEN


Acceso a la pantalla de informacin. Esta clase puede ser usada para obtener la lista de las resoluciones soportadas, cambiar la resolucin actual, esconder o mostrar el puntero de ratn del sistema, etc.

VARIABLES DE CLASE: resolutions: static var resolutions : Resolution[] Devuelve todas las resoluciones de pantalla completa soportadas por el monitor (read only). Las resoluciones retornadas se ordenan por anchura, empezando por las resoluciones ms bajas. El tipo Resolucion es una estructura con las siguientes variables: Width: height: refreshRate: Anchura de la resolucin en pxeles. Altura de la resolucin en pxeles. Tipo de refresco de resolucin vertical en Hz.

currentResolution: static var currentResolution : Resolution Variable de slo lectura que devuelve la resolucin de pantalla actual. Si el jugador est corriendo en modo windows, esto devuelve la resolucin actual del escritorio.

showCursor: static var showCursor : boolean Debe el cursor ser visible? Es enteramente posible implementar un cursor personalizado en lugar del que tiene el sistema. Para hacer esto debemos esconder el del sistema, seguir la posicin o movimiento de ratn y mostrar nuestra propia imagen en el lugar preciso. Vamos a hacer desaparecer nuestro cursor. Para ello previamente eliminamos la luz que creamos en la leccin anterior, y luego editamos nuestro Script (que recordaremos que tenemos vinculado a PortaScripts) Screen.showCursor = false; Observaremos que cuando pasamos el cursor por encima de la ventana Game, ste se torna invisible.

lockCursor: static var lockCursor : boolean Debe el cursor ser bloqueado?

El cursor ser ocultado automticamete, centrado en la vista y haciendo que no se pueda abandonar sta. Si estamos realizando un juego de navegador web, el cursor podr slo ser bloqueado despus de que el usuario haya hecho click en el contenido y siempre que ste no abandone la vista presionando escape o cambiando a otra aplicacin, ya que en estos casos el cursor ser automticamente desbloqueado. El bloqueo del cursor tambin se perder cuando se salga del modo de pantalla completa. Se puede consultar si el cursor est actualmente bloqueado consultando el estado de lockCursor. Para proveer una buena experiencia de usuario es recomendable slo bloquear el cursor como resultado de apretar un botn. Tambin debemos consultar si el cursor se desbloquea en orden a pej pausar el juego o hacer surgir un men del juego. En el Web Player y Editor el cursor automticamente se desbloquear cuando aprietes escape. En el Standalone Player tienes control pleno sobre el bloqueo del ratn de manera que no perders automticamente el bloqueo del mismo a menos que cambies de aplicacin.

width: static var width : int La anchura actual de la ventana en la pantalla en pxeles (slo lectura). Esta es la actual anchura de la ventana del jugador (en pantalla completa es tambin la resolucin actual)

height: static var height : int La altura actual de la ventana en la pantalla en pxeles (slo lectura) Esta es la actual altura de la ventana del jugador (en pantalla completa es tambn la resolucin corriente)

fullScreen: static var fullScreen : boolean Est el juego corriendo en pantalla completa? Es posible intercambiar al modo de pantalla completa cambiando esta propiedad. sleepTimeout: static var sleepTimeout : float Un ajuste de ahorro de energa, permitiendo la atenuacin de la pantalla algn tiempo despus de la interaccin del ltimo usuario activo. Es muy til para dispositivos tctiles, permitiendo el ahorro de la batera. SleepTimeout es medido en segundos, donde 0 significa que nunca duerme. El valor por defecto vara de plataforma en plataforma, siendo generalmente distinto a cero el dispositivos mviles. En dispositivos mviles sera til colocar esta variable a cero para juegos que usen acelermetros como principal fuente de entrada. Sin embargo, estos juegos deberan permitir la atenuacin de la pantalla mientras estn en la pantalla del men o pausados.

FUNCIONES DE CLASE: SetResolution: static function SetResolution (width : int, height : int, fullscreen : boolean, preferredRefreshRate : int = 0) : void Cambia la resolucin de pantalla. Se usar una resolucin de anchura por altura dada. Si la resolucin indicada no existe o no es soportada por nuestro dispositivo, se usar la mas cercana a la indicada. Si el parmetro preferredRefreshRate es 0 (default) Unity cambiar a la mayor velocidad de actualizacin soportada por el monitor. Si preferredRefreshRate no es cero, Unity la usar si el monitor la soporta, y en otro caso encontrar la ms alta soportada. En la web player slo podemos cambiar de resolucin depus de que el usuario ha hecho click en el contenido. La manera recomendada de hacer esto es cambiar la resolucin slo cuando el usuario haga clic en un botn designado a tal efecto. El cambio de resolucin no sucede inmediatamente, sino cuando el frame actual acaba.

51. CLASE TIME

Como su nombre indica (y tal como ya hemos visto en algunos ejemplos previamente) esta clase nos permite utilizar caractersticas de gran utilidad relacionadas con el tiempo.

VARIABLES DE CLASE: time: static var time : float Es el tiempo en segundos desde el inicio del juego (slo lectura). Cuando esta propiedad es llamada desde dentro de la funcin fixedUpdate devuelve la propiedad fixedTime. function Update(){ print(Time.time); } No hace falta mucha explicacin: nos aparece en pantalla el tiempo transcurrido desde el inicio del juego.

timeSinceLevelLoad: static var timeSinceLevelLoad : float Tiempo en segundos desde que el ltimo level ha sido cargado (slo lectura)

deltaTime: static var deltaTime : float El tiempo en segundos que se tard en completar el ltimo frame (slo lectura). Debemos usar esta propiedad para hacer que las cosas funcionen de manera independiente a la frecuencia de frames de casa ordenador. As, cuando multiplicamos dentro de la funcin Update el movimiento de un objeto con Time.deltaTime estaremos queriendo decir: quiero mover este objeto 10 metros por segundo en lugar de 10 metros por frame. Recordemos que si llamamos a esta propiedad desde dentro de FixedUpdate, devuelve el delta time de framerate fijo, para adaptarse a ste. No debemos confiar en Time.deltaTime desde dentro de un onGUI, ya que OnGUI puede ser llamado mltiples veces por frame y delta time debe sostener el mismo valor cada llamada, hasta el siguiente frame en que ser actualizado de nuevo.

fixedTime: static var fixedTime : float El tiempo desde que el ltimo FixedUpdate comenz (slo lectura). Este es el tiempo en segundos desde el inicio del

juego. Fixed time es actualizado en intervalos regulares (igual que fixedDeltaTime) hasta que la propiedad time es alcanzada.

maximumDeltaTime: static var maximumDeltaTime : float El mximo tiempo que un frame puede tomar. Physics y otras actualizaciones de frecuencia fija de frames (como FixedUpdate) trabajarn solo durante esta duracin de tiempo por frame.

smoothDeltaTime: static var smoothDeltaTime : float Un Time.deltaTime suavizado.

timeScale: static var timeScale : float La escala en la cual el tiempo pasa. Puede ser usada para efectos de cmara lenta. Cuando est establecida en 1.0, el tiempo transcurre igual que en la vida real. Cuando est en 0.5 est el doble de lento que en la vida real. Si lo colocamos en cero el juego se pausa si todas las funciones son independientes del frame rate. Si bajamos el timeScale es recomendable que tambin bajemos Time.fixedDeltaTime en la misma cantidad. Las funcione dentro de FixedUpdate no sern llamadas cuando timeScale est colocada a cero.

frameCount: static var frameCount : int El nmero total de frames que han pasado (slo lectura)

realtimeSinceStartup: static var realtimeSinceStartup : float El tiempo real en segundos desde que el juego empez (solo lectura). En casi todos los casos, no obstante, debemos usar Time.time en lugar de esto.

captureFramerate: static var captureFramerate : int Si est establecida en un valor superior a 0, el tiempo avanzar en (1.0 / captureFramerate) por frame sin tener en cuenta el tiempo real. Esto es til si quieres capturar una pelcula donde necesitas una frecuencia de frames constante.

52. CLASE YIELDINSTRUCTION

Es una clase base para otras clases que vamos a introducir dentro de este apartado, para no disgregarlas mucho dado su pequeo tamao.

CLASE WAITFORSECONDS: Suspende la ejecucin de una corrutina por una cantidad dada de segundos. Slo puede usarse con una declaracin yield en corrutinas. Por ejemplo: print (Time.time); yield WaitForSeconds (5); print (Time.time); Esta clase slo la compone su constructor: static function WaitForSeconds (seconds : float) : WaitForSeconds //Esto imprimir 0. //Espera cinco segundos. //Ahora imprime 5.0.

CLASE WAITFORFIXEDUPDATE: Espera hasta la siguiente funcin de actualizacin de frames fijados yield new WaitForFixedUpdate ();

CLASE COROUTINE: MonoBehaviour.StartCoroutine devuelve una Coroutine. Las instancias de esta clase son usadas slamente como referencia de esas coroutines y no tienen propiedades ni funciones. Una coroutine es una function que puede suspender su ejecucin (yield) hasta que la instruccin dada YieldInstruction acaba.

FISICAS: CONCEPTOS BASICOS

Examinadas las clases principales de Unity, quisiera ahora realizar una serie de incursiones ms o menos extensivas en algunos aspectos del engine que creo que merecen una atencin especial, bien por su importancia, bien por la dificultad para entenderlos. As que, avisando de nuevo en que este que os est escribiendo no es en absoluto un experto en la materia, intentar ayudar en lo que buenamente pueda. Quisiera empezar con un acercamiento a todo el componente de fsicas del engine, que considero que es el centro neurlgico del noventa y pico por ciento de los videojuegos que se han creado. Existe entre los recin llegados a Unity bastante confusin entre los trminos y conceptos que envuelven su apartado de fsicas, y en consecuencia a veces no se aplican correctamente los elementos necesarios para por ejemplo- detectar adecuadamente una colisin o permitir que un determinado gameobject sea inmune a la gravedad. Para que nuestro juego funcione adecuadamente y no consuma ms recursos de los necesarios debemos tener muy claro cul es la mejor solucin para cada necesidad. Vamos a intentar desgranar para qu sirve cada cosa. Empezaremos por examinar las diferentes posibilidades de deteccin de colisiones que nos brinda Unity, y para ello necesitaremos introducir el primer concepto: COLLIDER: Un collider, en trminos muy bsicos, es un envoltorio que hace que un determinado objeto se torne slido y en consecuencia pueda chocar con otros objetos (siempre que a su vez esos otros objetos tengan otro collider). Un collider se compone, por un lado, de una determinada forma (que no tiene por qu coincidir con la forma del objeto, aunque es preferible que casen de alguna manera, para originar colisiones crebles) y, por otro, de un determinado material fsico (aqu no estamos hablando de colores o modos de reflejar la luz de una superficie, sino de capacidad de rebote y/o friccin de dicho objeto, as que no confundamos el trmino material que usamos para renderizar un objeto con el material fsico). Atendiendo a su forma, podemos diferenciar los colliders en dos subgrupos: colliders de malla (mesh colliders) y colliders de primitivas (primitive colliders): El mesh collider lo creamos cuando importamos una malla desde alguna aplicacin 3d tipo Blender o 3dMax. Al seleccionar dicha malla desde la vista de Proyecto y previo a importarlo, debemos (caso de querer este tipo de malla) marcar la casilla generate colliders (ver captura de pantalla) para que nuestra malla tenga un collider de este tipo.

Cuando marcamos esta casilla e importamos la malla, Unity genera un collider que tendr la misma forma que dicha malla (de ah el nombre). Podramos pensar: pues ya est, es tan sencillo como pedir a Unity que genere colliders para todas las mallas que vayamos importando y ya tenemos nuestro sistema de deteccin de colisiones montado, sin necesidad de complicarnos la vida asignando colliders de primitivas que adems no cuadran tan perfectamente con nuestras mallas como los colliders de malla.

Pero no es tan sencillo. Para empezar, dos colliders de malla no colisionarn entre s si al menos uno de ellos no tiene marcado en el inspector el checkbox convex, que hace que el collider envuelva adecuadamente la malla. No hay problema podemos pensar- marco la casilla convex y asunto solucionado. Sigue sin ser tan sencillo. Si dos colliders de malla colisionan entre s a una velocidad importante es posible que no se detecte la colisin. y para el caso de objetos que s positivamente que no se movern a mucha velocidad puedo usar mesh colliders? La respuesta es: poder, se puede, pero si se puede evitar, mejor. Pensemos que la cantidad de recursos que consume un PC para calcular colisiones derivadas de mallas complejas es muy superior a la precisa para hacer lo propio con primitives colliders. En resumen, que deberamos usar los colliders de malla en objetos que sepamos positivamente que en nuestro juego se movern poco o nada, que no estarn sometidos a colisiones continuas con otros objetos y que tengan una forma difcil de casar con un collider primitivo.

Por su parte, el primitive collider implica asignar a una malla un collider prefabricado por Unity, pudiendo meramente escoger entre las siguientes formas primitivas: esfera, caja, cpsula o rueda. Se tratara meramente de teniendo nuestra malla seleccionada- irnos al men Components=>Physics y seleccionar uno de los indicados colliders, para despus moverlo de tal forma que encaje lo mejor posible con nuestra malla. En ocasiones precisaremos usar varios colliders primitivos para cubrir toda la fisonoma de una malla. Esto se puede conseguir creando un gameobject vaco y emparentar dichos colliders como hijos de esta, para crear as una unidad manipulable, por decirlo de alguna forma. Aunque este segundo sistema primitive collider- es ms trabajoso y antiesttico que el anterior- mesh collider- es recomendable que en la medida de lo posible lo usemos para nuestras mallas. ____________________________ Como veamos, un collider vendra a ser meramente un caparazn que le aadimos a una malla para que pueda colisionar con otras mallas, pudiendo ese caparazn tener la misma forma que la malla (mesh collider) o una forma que nosotros le diseemos para l a partir de una o varias formas primitivas (primitive collider)que Unity nos ofrece. Supongamos entonces que tenemos dos mallas en nuestra escena, a cada una de las cuales le asignamos un collider (del tipo que sea, eso no importa para este ejemplo). A travs de un script vinculado a una de las mallas movemos su transform para que colisione contra la otra malla. Probadlo si queris con dos cubos (que ya traen "de serie" un collider primitivo (obviamente, un box collider)). Comprobaris que pese a tener cada malla un collider, a efectos prcticos es como si no lo tuvieran, ya que se atraviesan. Esto sucede porque para que dos mallas puedan colisionar, adems de estar ambas dotadas de su pertinente collider, es preciso que al menos una de las dos mallas tenga vinculado adems un Rigidbody no kinemtico. Olvidmonos de momento del palabro "kinemtico" y centrmonos en el Rigidbody. Un rigidbody es el conjunto de datos que permiten a Unity calcular, entre otras cosas, las consecuencias que tendr una colisin para el gameobject al cual se asigna dicho rigidbody. Al igual que nos pasara a nosotros si estuviramos en clase de fsica, para que Unity calcule las consecuencias de una hipottica colisin necesita tener en cuenta factores como la masa del gameobject al que se vincula, la velocidad relativa a que se produce la colisin, si existe o no rozamiento y en qu medida, si hay o no gravedad, etc. Por resumir, asignando

un rigidbody a un gameobject automticamente estamos dotando a dicho gameobject de una serie de propiedades fsicas, tales como gravedad, rozamiento y peso, ya que sin saber la masa de un objeto - por ejemplo- es imposible calcular el resultado de una colisin (probad si no a patear de manera indiscriminada objetos con diferentes masas, paredes de carga y yorkshires inclusive, para que comprobis las diferentes posibilidades de desplazamiento). Lo ms impactante para los recin llegados a Unity cuando le asignamos un rigidbody a una malla -como muchos ya habris comprobado- es que automticamente, salvo que el suelo a su vez tenga otro collider, nuestra malla se pierde en las profundidades de la escena. Por eso se tiende por algunos (manuales de pago incluidos) a simplificar en ocasiones cuando se explica lo que es un rigidbody, limitndolo a "lo que hace que un objeto se vea afectado por la gravedad". Y por ah suelen empezar tambin las confusiones entre colliders y rigidbodies, debido a que los dos tienden a solaparse y es difcil explicar uno sin mencionar al otro. Es verdad que ambos son necesarios para que se produzca una colisin, pero intervienen en apartados distintos: el collider sera el dnde (se produce la colisin) y el rigidbody el cmo. Supongo que se entiende que no tendra sentido asignar un rigidbody a una malla que no tenga un collider, ya que de nada sirve calcular una colisin que nunca tendr lugar (ya que no hay collider para esa malla con el que colisionar o ser colisionado) S cabe pensar en un collider que no tenga rigidbody. De hecho, es lo que en Unity se conoce como "static colliders". Un collider esttico, como su nombre indica, est pensado para objetos que no se van a mover en la escena. Este tipo de colliders sin rigidbody pueden interactuar/colisionar con otros colliders siempre que stos colliders s tengan vinculado un rigidbody (ya hemos visto que si ninguno de los dos objetos tiene un rigidbody la colisin no se produce, bsicamente porque Unity no tiene ninguna forma de calcular las consecuencias de dicha colisin entre dos objetos "no fsicos" y directamente obvia la colisin). Lo que sucede es que cuando un collider dinmico (con rigidbody) se mueve y fruto de ese movimiento colisiona con un collider esttico (sin rigidbody), como Unity ignora las propiedades fsicas del collider esttico, meramente ste -haciendo honor a su nombre- no se mover. Y de hecho, si se moviera, y precisamente por lo expuesto (Unity no sabe calcular cmo y cunto se ha de mover) el costo computacional sera brutal. Por todo lo anterior, los static colliders son ptimos para las partes fijas de nuestro juego, tal como paredes, libreras, rboles y objetos similares que no han de moverse pero que tampoco han de atravesarse por los personajes y dems partes mviles del juego. Espero que estos conceptos que estoy intentando explicar a cuentagotas queden claros. S que al principio parece todo un poco confuso, pero es esencial entenderlos correctamente. Un abrazo y hasta pronto.