# Scripting con Unity

Uno de los tipos de *assets* más importantes de Unity son los *scripts*. Éstos nos permiten, mediante código, programar el comportamiento que tendrán nuestros objetos en el juego. Estos *scripts* pueden describirse en diferentes lenguajes, como C#, Javascript, y Boo, pero nos centraremos en C# por ser el más potente y versátil.

Para la edición de estos *scripts* contamos con la herramienta MonoDevelop, aunque a partir de la versión 5.2 de Unity en Windows se integra también con Visual Studio. La herramienta de desarrollo a utilizar puede ser configurada en *Preferences ... > External tools*.

## Creación de scripts

Crearemos un *script* como cualquier otro *asset*, con la opción del menú *Assets > Create > C# Script*. Una vez creado, podremos añadirlo como componente a cualquier *Game Object*, pudiendo de esta forma personalizar su comportamiento. Los \_scripts \_se comportarán como un tipo de componente más.

Veremos el *script* creado entre los *assets* del proyecto. Haciendo doble *click* sobre él se abrirá en el editor de código que tengamos configurado, pudiendo así editarlo.

## Estructura de un script

Cuando abramos con el editor un *script* recién creado, veremos un esqueleto como se muestra a continuación:

```
public class EsferaScript : MonoBehaviour {
    void Start () {

    }

    void Update () {

    }
}
```

Esta es la estructura básica de un *script*. Encontramos los siguientes métodos:

* `Start`: Se ejecutará cuando se cree el *Game Object* sobre el que esté aplicado el *script* (como componente del mismo).
* `Update`: Se ejecutará en cada iteración del juego, para actualizar el estado del *Game Object* sobre el que esté aplicado. Por ejemplo, si nuestro juego se ejecuta a una frecuencia de 60 FPS (fotogramas por segundo), cada segundo se llamará 60 veces a los métodos `Update` de todos los componentes de los objetos para actualizarlos.

Estos son los métodos principales que encontraremos en la plantilla, aunque también podríamos definir otros métodos como:

* `Awake`: Se ejecuta antes de todos los `Start`, y será útil si tenemos que inicializar elementos de los que dependa la inicialización de otros objetos. Podemos inicializar lo básico en `Awake`, y dejar en `Start` toda aquella inicialización que dependa de que se haya realizado la inicialización básica de todos los objetos.
* `LateUpdate`: Se ejecuta después de haber ejecutado los `Update` de todos los objetos. Al igual que el caso anterior, también será útil para el caso de tener dependencias. Podemos dejar para `LateUpdate` todas las actualizaciones que dependan de haber actualizado todo lo que realiza `Update`.

## Ciclo del juego

El elemento principal del motor de un videojuego es el ciclo del juego. Se trata de un bucle infinito que se ejecuta a una determinada frecuencia (es habitual que se ejecute a 60 FPS, 60 veces por segundo), y en cada iteración lo que hace es:

* Leer la entrada del usuario (mandos, teclado, ratón, pantalla táctil, etc).
* Actualizar los elementos de la escena (*Game Objects*).
* Dibujar los gráficos de la escena actual.

Hay que remarcar que sólo se actualizará y se dibujará la escena actualmente activa. Es decir, funciona como una máquina de estados, en la que cada escena representa un estado. Por ejemplo, podemos tener una escena con nuestra pantalla de título, otra con el menú de selección de nivel y otra para cada nivel del juego. Para pasar de una pantalla a otra podremos cambiar de escena, y en ese momento Unity cargará todos sus *Game Objects*, llamará a sus métodos `Awake` y `Start` para inicializarlos, y tras esto los actualizará en cada iteración del juego llamando a sus métodos `Update` y `LateUpdate` mientras la escena siga activa.

Podemos cambiar a otra escena usando el método `SceneManager.LoadScene`, proporcionando el nombre de la escena a la que queremos cambiar:

```
using UnityEngine;
using UnityEngine.SceneManagement;

public class JugadorScript : MonoBehaviour {
    void Update () {
        ...
        if(muerto) {
            SceneManager.LoadScene ("GameOver");        
        }
    }
}
```

En este caso, por defecto se destruirán todos los objetos de la escena actual y se cargarán los de la nueva que se inicializarán y empezarán a actualizarse. También existe la opción de cargar una escena de forma aditiva, que nos permitirá cargar los objetos de la nueva escena sin destruir los actuales:

```
SceneManager.LoadScene ("Laboratorio", LoadSceneMode.Additive);
```

En cualquiera de los casos anteriores, los objetos que se carguen serán inicializados y comenzarán a actualizarse hasta que se destruyan. Aunque en muchos videojuegos la frecuencia de actualización del ciclo del juego habitualmente es de 60 FPS, en Unity puede variar según la plataforma. En plataformas de sobremesa suele intentar alcanzar los máximos FPS posibles, mientras que en móviles suele limitar a 30 FPS para ahorrar batería. Si no queremos este comportamiento por defecto, podemos especificar los FPS que queremos intentar conseguir con:

```
Application.targetFrameRate = 60;
```

Esto no nos garantiza que podamos conseguir una frecuencia de 60 FPS, ya que según la capacidad de la máquina podría no llegar a conseguir esta frecuencia, pero intentará llegar a ella. Además, tampoco podemos confiar en que la frecuencia se mantenga constante, dependiendo de la carga gráfica y de procesamiento del videojuego, en determinados momentos podría bajar. Por este motivo es importante poder conocer en todo momento cuánto tiempo ha transcurrido desde la anterior actualización hasta la actual. Esto es lo que se conoce como *delta time*, y el motor Unity nos lo proporciona en segundos en la propiedad `Time.deltaTime`:. Un uso habitual de esta propiedad es la actualización de la posición de los objetos en la escena. Si sabemos la velocidad de un objeto, la posición que ocupaba en el fotograma anterior, y tenemos el tiempo transcurrido desde dicho fotograma, podemos calcular la nueva posición con:

```
posicion = posicion + velocidad * Time.deltaTime;
```

## Acceso a los componentes y polimorfismo

Como hemos comentado anteriormente, Unity sigue una arquitectura orientada a componentes. El comportamiento de los objetos lo definen los componentes que incorporan, y hemos visto que los *scripts* son un tipo de componente más. Por lo tanto, para poder modificar las propiedades de los objetos desde el código de los *scripts* deberemos ser capaces de acceder a los diferentes componentes que incorpora el objeto. Algunos de los componentes a los que nos puede interesar acceder son:

| Componente  | Descripción                                                                                                                        |
| ----------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| Transform   | Nos permitirá cambiar la posición, orientación y escala de un objeto. Es un componente básico para mover los objetos en la escena. |
| Renderer    | Nos permite cambiar el material y la apariencia de un objeto.                                                                      |
| AudioSource | Nos permite reproducir *clips* de audio desde un determinado lugar de la escena.                                                   |
| Camera      | Nos permite configurar la cámara, como por ejemplo el campo visual de la misma.                                                    |
| Light       | Nos permite cambiar las propiedades de las luces, como por ejemplo cambiar la intensidad o color de las mismas.                    |

Uno de los componentes que más utilizaremos será `Transform`, que será el que nos permita cambiar la posición de los objetos en la escena. Podemos obtener el componente de la siguiente forma:

`Transform transform = GetComponent<Transform>();`

El método `GetComponent` nos devolverá el componente que indiquemos del *Game Object* sobre el que estemos, o `null` si este *Game Object* no tuviese ningún componente de este tipo. De esta forma podremos comprobar si nuestro objeto (el objeto sobre el que apliquemos nuestro *script*) tiene o no un determinado componente. Una vez obtenido el componente, podremos acceder y modificar sus propiedades. Por ejemplo, en el caso del componente `Transform` podríamos modificar su posición, para así mover el objeto:

`transform.position = new Vector3(0,0,5);`

Cuando vayamos a utilizar en repetidas ocasiones un determinado componente, es conveniente que lo guardemos en uno de los campos de nuestra clase, para de esta forma no tener que volver a obtenerlo cada vez. Este es habitualmente el caso de `Transform`, que podríamos guardarlo al inicializar nuestro objeto de la siguiente forma:

```
private Transform m_transform;

void Start () {
    m_transform = GetComponent<Transform>();
}
```

Será recomendable hacer esto para cualquier componente que vayamos a utilizar en repetidas ocasiones.

Si nuestro *script* requiere que el Game Object sobre el que se aplica tenga un determinado componente para poder funcionar correctamente, podemos añadir la siguiente directiva en la clase del *script*:

```
[RequireComponent(typeof(Renderer))]
public class JugadorScript : MonoBehaviour {
    ...
}
```

En el ejemplo anterior sólo podremos añadir nuestro script `JugadorScript` a *Game Objects* que tengan un componente `Renderer`. En caso de no tenerlo, el entorno no nos permitirá añadir nuestro *script* como componente. De esta forma estaremos garantizando que cuando solicitemos dicho componente mediante `GetComponent<Transform>()`, éste existirá, y no nos devolverá `null`.

## Parametrización del script

Para hacer nuestro *script* reutilizable en diferentes contextos, podemos parametrizarlo de forma que desde el propio entorno de Unity al añadirlo a un objeto podamos modificar desde el inspector las diferentes propiedades que hayamos definido.

Para parametrizar un *script* simplemente deberemos añadir una propiedad pública a la clase del *script*, como por ejemplo:

```
public Vector3 posicionInicial;

void Start () {
    GetComponent<Transform>().position = posicionInicial;
}
```

Al añadir dicha propiedad posicionInicial y grabar el *script*, cuando pasemos al entorno de Unity veremos que en el bloque destinado al componente de dicho *script* en el Inspector habrá aparecido un campo para editar el valor de la propiedad.

![](https://456511362-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LDGNO9wAWjKJPOnv9fB%2F-LDGNPx0ow-6xMRYhUWq%2F-LDGNd_8kJkSj1N5sWRc%2Fscript_param.png?generation=1527152567566630\&alt=media)

De esta forma podremos modificar de forma sencilla desde el entorno la posición inicial en la que se creará nuestro objeto, sin tener que entrar a editar el código, y si el *script* se introduce en diferentes objetos, cada uno de ellos podrá inicializarse en una posición distinta, configurando este parámetro para cada uno de ellos. De esta forma mejoramos la reusabilidad de nuestro *script*.

Podremos crear parámetros de diferentes tipos. En el ejemplo anterior hemos utilizado el tipo `Vector3`, que es el tipo utilizado en Unity para establecer coordenadas *(x,y,z)* en el espacio tridimensional, pero podríamos utilizar cualquier otro tipo de datos, como por ejemplo los diferentes tipos básicos de datos (`bool`, `int`, `float`, `String`, etc) o colecciones de elementos (`List`).

## Componentes y polimorfirmo

Un tipo de parámetro que merece atención especial es aquel que toma como tipo el tipo de algún componente. Por ejemplo, podríamos incorporar un parámetro de tipo `Transform`:

```
public Transform target;
```

En este caso, veremos el parámetro de la siguiente forma en el entorno:

![](https://456511362-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LDGNO9wAWjKJPOnv9fB%2F-LDGNPx0ow-6xMRYhUWq%2F-LDGNd_DW2gq3qgk6NqF%2Fscript_param_object.png?generation=1527152553848060\&alt=media)

A este parámetro le podremos asignar cualquier *Game Object* de la escena o *prefab* que incorpore un componente de tipo `Transform`. Es decir, los *Game Objects* se comportan de forma polimórfica respecto a sus componentes. Esto significa que podrán tomar la forma de cualquiera de los componentes que incorporen a la hora de asignarlos a parámetros

Esto nos da una gran versatilidad. Con un parámetro de tipo `Transform` estamos pidiendo que nos asignen cualquier objeto que incorpore este componente, sin importarnos el tipo de objeto concreto del que se trate. De esta forma reducimos el acoplamiento del código, haciéndolo más modular y favoreciendo la reutilización de los componentes.

Además, debemos recalcar que nuestro *scripts* se comportan también como componentes. Por lo tanto, podríamos poner un parámetro cuyo tipo sea el de uno de nuestros *scripts*:

```
public JugadorScript jugador;
```

En este caso podremos asignar a dicho parámetro cualquier *Game Object* que incorpore como componentes nuestro *script* `JugadorScript`. Tendremos además acceso a las propiedades y métodos públicos del *script*.

## Interfaz pública del script

## Búsqueda de objetos

## Creación y destrucción de objetos

## Corrutinas
