• No results found

4.3 Producing the STS Score

4.3.4 Machine Learning

Woods es el nivel principal del juego, donde se realizará la acción de plataformas y se podrá controlar libremente al personaje principal. En esta escena el ratón no tiene ninguna interacción.

El objeto EventSystem se mantiene igual que en las otras escenas, y el objeto Audio Source solo modificará la pista que se reproduce.

El objeto Main Camera es distinto al de las demás escenas dado que ahora debemos cambiar su posición a medida que el jugador se mueva por el nivel. Para ello se le ha añadido un componente C# script a la cámara que calcula en cada fotograma la posición de jugador y, si se acerca a uno de los márgenes de

35

la pantalla, mueve la cámara en esa dirección para que el personaje no salga nunca de la pantalla.

Para añadir el fondo, se ha creado un GameObject Canvas que incluye las dos imágenes que se van a utilizar para el fondo. Como la cámara está en movimiento, hay que marcar el modo de renderizado a Screen Space – Camera y seleccionar la cámara de la escena como cámara de renderizado. Esto provoca que las imágenes se mantengan fijas en la cámara, así que no importa cuánto se mueva el jugador que siempre estará el fondo en pantalla. Las imágenes están ordenadas para que esté una sobre la otra.

El objeto Miscellaneous es un objeto padre cuyos hijos son pequeños objetos decorativos. Estos objetos están en una capa distinta para que no interfiera con el movimiento del jugador, es decir, para que solo sean elementos estéticos. La mayoría de estos objetos solo tienen un Sprite Renderer con la imagen del objeto, pero algunos como Torch o Bonfire tienen una animación que se ejecuta constantemente.

Player es el GameObject más complejo de la escena Woods. Empezando por los componentes físicos del GameObject, se ha establecido una etiqueta “Player” para el objeto, la cual permitirá comprobar si otros objetos están en contacto con Player. Además, se la ha añadido un componente Rigidbody 2D, el cual implementa las físicas del motor al GameObject añadiendo, entre otros elementos, una fuerza gravitatoria y que hace que el objeto caiga. Esto resultará útil para poder saltar y caer sobre el suelo. Por último, se ha añadido un

36

componente Box Collider 2D, cuyo cometido es hacer que el objeto pueda colisionar con otros objetos. La utilidad de este componente es, por ejemplo, que el personaje pueda entrar en contacto con el suelo dado que, sin este componente, Player no tocaría el suelo y, en vez de posarse sobre él, caería al vacío.

En la parte visual, lleva un componente Sprite Renderer con el diseño de Allard (el caballero) y otro componente Animator con un Animator Controller asociado para gestionar las distintas animaciones de Allard. Los cambios de transición se realizan a través de dos variables booleanas IsRunning e IsJumping que se irán cambiando en los scripts. El diagrama de transiciones entre animaciones se puede ver en la ilustración x. El personaje tendrá tres animaciones:

¾ Idle: Es la animación del personaje cuando está en reposo. El personaje empezará con esta animación al entrar a la escena y se repetirá en bucle hasta que haya una transición a otra animación.

¾ Run: Esta animación representa la acción de correr y se activa con un movimiento horizontal, es decir, cuando la variable IsRunning sea igual a true se mantendrá en bucle hasta que deje de serlo o IsJumping sea true.

¾ Jump: La animación de salto que se activa cuando la variable IsJumping es igual a true A esta animación se puede acceder desde cualquier otra, pero desde la animación solo se puede transitar al estado Idle.

37

Para finalizar con Player, se han añadido el script Player_Controller y el script Player_Movement.

void Update() {

if (Input.GetAxisRaw("Horizontal") != 0) {

anim.SetBool("IsRunning", true);

if (Input.GetAxisRaw("Horizontal") > 0) { movement = speed; if (!facingRight) { player.GetComponent<Transform>().Rotate(0f, 180f, 0f); facingRight = true; } } else { movement = -speed; if (facingRight) { player.GetComponent<Transform>().Rotate(0f, 180f, 0f); facingRight = false; } } } else {

38

anim.SetBool("IsRunning", false); movement = 0;

}

if (Input.GetButtonDown("Jump")) {

anim.SetBool("IsJumping", true); jump = true;

} }

private void FixedUpdate() {

playerMovement.Movement(movement, jump); jump = false;

}

En este fragmento de código se encuentran las funciones Update y FixedUpdate del script Player_Controller. La función FixedUpdate hace una llamada al método Movement del script Player_Movement con los parámetros movement, al cual le asignaremos el parámetro speed que es la velocidad a la que queremos que se mueva en positivo si avanza a la derecha y en negativo si avanza a la izquierda, y jump, que será una variable booleana que será true cuando el jugador quiera saltar. Como podemos ver, en el método Update se comprueba con la función Input.GetAxisRaw("Horizontal") si el jugador ha pulsado la tecla “A”

o la “D”. Antes de comprobar si el jugador que tecla ha pulsado el jugador, si ha pulsado una tecla se activará la animación de correr asignando la variable booleana IsRunning a true. Si el jugador ha pulsado la tecla “A”, su intención es moverse a la izquierda y la función GetAxisRaw devolverá un número negativo, por lo que habrá que asignar un valor negativo a movement. Si ha pulsado la tecla ”D”, su intención es moverse a la derecha y la función GetAxisRaw devolverá un valor positivo, así que movement se asignará al valor positivo de speed. Si no ha pulsado ninguna de esas teclas, GetAxisRaw devolverá un 0, por lo cual se asignará a false el booleano IsRunning para que vuelva a la animación Idle y movement se asignará a 0.

Además, también hay que comprobar si el usuario estaba mirando a la izquierda o a la derecha, dado que habrá que cambiar la orientación de las animaciones para que, por ejemplo, el personaje no se mueva a la izquierda y en la animación esté corriendo hacia la derecha. Para ello está la variable facingRight, la cual será true si está mirando a la derecha y si, intenta moverse a la izquierda, se hará una rotación del personaje para que mire hacia la izquierda y se asignará la variable facingRight a false para que, si intenta moverse a la derecha, se vuelva a rotar.

La función Input.GetButtonDown("Jump")) comprobará si se ha pulsado la tecla

“Espacio”. Si se ha pulsado se activarán las variables booleanas IsJumping, para activar la animación de salto, y jump, para realizar la acción de saltar. Player_Movement realizará el movimiento dependiendo de los valores que reciba del FixedUpdate de Player_Controller. Tiene 6 posibles estados:

39

1. Movement = 0 y Jump = false: El personaje no se moverá en ninguna dirección. Pero igualmente se creará el vector de movimiento sin dirección.

2. Movement = positivo y Jump = false: El personaje se moverá a la derecha con la animación de correr. Para ello se creará un vector que moverá al personaje en dirección al eje X positivo con la velocidad speed. Para suavizar el movimiento, se ha utilizado la función SmoothDamp, la cual hace que la velocidad disminuya progresivamente al dejar de pulsar el botón.

3. Movement = negativo y Jump = false: Es el mismo caso que el anterior, pero moviéndose a la izquierda en vez de a la derecha, es decir, moviéndose en dirección al eje X negativo.

4. Movement = 0 y Jump = true: El personaje realizará un salto vertical sin moverse horizontalmente, es decir, en el eje Y positivo. Para que esto sea posible, la variable booleana IsGrounded tendrá que ser true, y esto solo se dará en el caso en el que el jugador esté en contacto con un objeto con el Tag Ground. Esto evita que se puedan realizar saltos en el aire. Si se cumple esta condición, al vector creado se le añadirá una fuerza vertical que se asignará como variable pública en el script Player_Movement. Esta acción se realizará con la animación de salto y, al caer al suelo, se asignará la variable IsJumping a false para volver a la animación Idle.

5. Movement = positivo y Jump = true: Funciona de la misma manera, solo que el salto se realizará en diagonal, dado que el vector se moverá en los ejes X e Y positivos. La animación que se utilizará será la de salto.

6. Movement = negativo y Jump = true: Igual que la anterior, pero el movimiento se realizará en el eje X negativo y en el eje Y positivo.

Volviendo con los demás elementos de la escena, se puede encontrar un objeto grid que contiene el objeto tilemap. Estos dos objetos componen el escenario del nivel.

40

Para construir un escenario con Tilemap se necesita crear el objeto Grid con el hijo Tilemap y posteriormente crear una paleta donde añadir los tiles como la que se puede ver en la ilustración x. Cada cuadrado es un Tile por lo que, para generar el escenario, se debe ir cogiendo los tiles y pintándolos con la brocha en el Tilemap.

Creado el Tilemap, ya estaría listo el escenario, a falta de añadir un Collider para que el Player pueda apoyarse en el suelo. Por eso se ha añadido un Tilemap Collider 2D. También se le ha añadido un Tag Ground para poder comprobar que el jugador está tocando el suelo.

Ilustración 56: Fragmento de

escenario Ilustración 16: Fragmento deescenario separado en Tiles

Ilustración 59: Paleta de Tiles de Suelo Ilustración 58: Tilemap

41

Para finalizar de comentar el contenido de esta escena, se hablará de los objetos generadores SkelletonGenerator, OwlGenerator y FungusGenerator. Cada uno de estos GameObjects tendrá su Sprite Renderer con su diseño y un Animator con la animación de Idle que le corresponda a cada uno. La importancia de estos objetos es el script GenerateEnemy que tienen asociado. Este script recibe un objeto enemyParty que, al igual que el objeto Party comentado en la escena MainMenu, contiene la información sobre los distintos enemigos. La diferencia es que enemyParty es un objeto prefabricado que no ha sido inicializado ni instanciado. Cada objeto generador tendrá asociado una “Party” que incluirá uno o dos enemigos distintos.

El script tendrá un método Start que hará que el objeto no se destruya entre escenas. También tendrá un método onTriggerEnter2D, el cual se lanzará cuando el enemigo entre en colisión con otro objeto. Si el objeto con el que entra en contacto tiene la etiqueta Player, carga la escena de batalla y activa un booleano para que el otro método pueda instanciar la enemyParty. El último método que tiene este script es OnSceneLoaded, que será invocado cuando se cargue una nueva escena y, si la escena es Battle, creará una instancia de enemyParty para la batalla y eliminará el objeto generador.

42