Episodix: Iteración 2

A continuación se describirá la Iteración 2 del proyecto Episodix.

El estructura de la Iteración 2 será la siguiente:

  • Learning Phase: El usuario camina (al estilo FPS) por una calle vacía. En el lado derecho aparecen tres sólidos tridimensionales aleatorios sencillos de entre los sólidos disponibles de una lista de seis. Estos sólidos se situarán en unas posiciones llamadas Anchor Points (tres en total).
  • Recall Phase:  Cuando llega al final de la calle, el juego le presenta preguntas sí/no para comprobar si recuerda qué sólidos tridimensionales ha visto mientras caminaba por la calle. Se le preguntará por los sólidos en el orden en que aparecen en la calle y por tres sólidos aleatorios más (pudiendo ser repetidos los tres anteriores).
  • Scores: Finalmente el juego presenta la puntuación obtenida. No se almacenan los resultados.
Scene

La escena iteration_2 es la única existente y se compondrá de los siguientes objetos:

  • Scores: objeto vacío que recogerá y almacenará las respuestas del usuario mediante un script asociado.
  • Directional light: alumbrará nuestra Scene.
  • Street: será la calle vacía con los seis sólidos tridimensionales en su lado derecho desactivados y los tres Anchor Points. Al inicio del juego se asignarán de manera aleatoria tres de los sólidos a las posiciones de los Anchor Points y se activarán. Además tendrá cuatro paredes invisibles para evitar que el jugador caiga al vacío.

street

  • FPSController: personaje con vista en primera persona que manejará el usuario para moverse por la calle y observar el entorno. Está sacado de los Standard Assets de Unity. Se desplazará con las teclas WASD y empleará el ratón para mover la vista.
  • CheckEnd: pared invisible con el collider puesto en modo Trigger que se usará para detectar el momento en el que el jugador llega al final de la calle. Tendrá una marca amarilla para indicar con claridad dónde se sitúa.

checkend

  • Recall Phase Camera: será la cámara usada en todas las fases del juego que no requieran del uso del FPSController.
  • Recall Phase: es una UI (User Interface) en la que se mostrarán las preguntas al usuario, que tendrá que responder haciendo clic el el botón Sí/No. Al responder a todas las preguntas se mostrará la puntuación (incluída también en Recall Phase) y podrá elegir si quiere reiniciar la prueba o salir del juego. Esta interfaz aparecerá cuando el usuario llegue al final de la calle. Cada pregunta constará de un texto con la pregunta y dos botones (Sí/No) para responderla, además de una imagen del sólido por el cual se pregunta.

RecallPhase_1 RecallPhase_2

  • Menu: es una UI en la que se muestra el menú del juego, que incluirá tres botones: 1) Continuar, para volver al punto en el que estamos en el juego. 2) Reiniciar, para cargar el nivel de nuevo y empezar de nuevo el juego. 3) Salir, para cerrar el juego.

menu

  • All Solids: es una UI que mostrará la imagen de todos los sólidos posibles, con sus respectivos nombres, al jugador.

allsolids

  • EventSystem: se creará automáticamente al crear un Canvas ( un elemento usado para el renderizado de pantalla de la UI , el objeto Recall Phase en nuestro caso) para controlar los eventos del mismo.
Scripts

En la Iteración 2 se hará uso de un total de seis C# scripts:

  • EndMenu.cs : constará de dos funciones. Una para reiniciar el nivel y otra para cerrar el juego. Este script estará asociado a FPSController.

using UnityEngine;
using System.Collections;

public class EndMenu : MonoBehaviour
{
// Esta funcion reinicia el nivel.
public void ResetLevel ()
{
Application.LoadLevel ("iteration_1");
}

// Esta funcion cierra el juego.
public void ExitGame ()
{
Application.Quit ();
}
}

diagram_endmenu

  • Menu.cs : será el encargado de gestionar la activación/desactivación del menú (objeto Menu) mediante la tecla escape y de All Solids manteniendo la tecla tab. Este script estará asociado a Street.

using UnityEngine;
using System.Collections;

public class Menu : MonoBehaviour
{
// Se almacenarán los objetos que necesitaremos activar/desactivar
// a la hora de activar/desactivar el menú.
//
public GameObject men;
public GameObject character;
public GameObject cam;
public GameObject recallPhase;
public GameObject allSolids;


// menu indicará el estado del menú actualmente.
bool menu = false;
// rP indicará si la RecallPhase está activa.
// rP2 indicará si RecallPhase deberá activarse o desactivarse al cerrar el menú.
bool rP, rP2;


public void Update()
{
// Al pulsar la tecla "escape" se activará/desactivará el menú.
//
if (Input.GetKeyDown ("escape"))
{
rP = recallPhase.activeInHierarchy;
if(!menu)
{
menu = true;
men.SetActive(true);
if(rP)
{
recallPhase.SetActive(false);
rP2 = true;
}
else
{
character.SetActive(false);
cam.SetActive(true);
rP2 = false;
}
}
else
{
menu = false;
men.SetActive(false);
if(rP2)
{
recallPhase.SetActive(true);
}
else
{
cam.SetActive(false);
character.SetActive(true);
}
}
}


// Al mantener pulsada la tecla "tab" se mantendrá activo el objeto All Solids.
//
if (Input.GetKey ("tab"))
{
allSolids.SetActive (true);
}
else
{
allSolids.SetActive(false);
}
}


// En el caso de cerrar el menú con el botón Continuar, esta función será llamada y
// cambiará el valor de menu al valor de newMenu (que será false).
//
public void ChangeMenuValue(bool newMenu)
{
menu = newMenu;
}
}

diagram_menu

  • Scores.cs : constará de dos funciones. La primera recogerá la respuesta del usuario a una pregunta. La otra comprobará si es correcta y almacenará los resultados; si es la última pregunta calcula el porcentaje de acierto del usuario. El script estará asociado al objeto Scores.

using UnityEngine;
using System.Collections;

public class Scores : MonoBehaviour {

public float rightAnswers; // Mostrara el numero de respuestas correctas en inspector.
float rA; // Numero de respuestas correctas con las que trabajaran las funciones.
public float totalAnswers; // Mostrara el numero de respuestas totales en inspector.
float tA; // Numero de respuestas totales con las que trabajaran las funciones.
public float totalQuestions; // Numero de preguntas totales. Se establecera su valor en Inpector.
public float results; // Almacenara el porcentaje de acierto de las respuestas.

bool answer; // Almacenara la respuesta a una pregunta (Si o No)

// Recogera la respuesta del usuario a una pregunta.
//
public void CollectAnswer(bool ans)
{
answer = ans;
}

// Comprobara si el usuario ha acertado con su respuesta a la pregunta, añadira el resultado y lo almacenara con el resto.
// Si era la ultima pregunta del test, calculara el porcentaje de acierto del usuario a todas las respuestas.
//
public void AddScore (GameObject solid)
{
rightAnswers = rA;
totalAnswers = tA;

if (solid.activeInHierarchy==answer)
{
++rA;
rightAnswers = rA;
++tA;
totalAnswers = tA;
} else
{
++tA;
totalAnswers = tA;
}

if (totalQuestions == tA) {
results = (rA / tA) * 100;
rA = 0;
tA = 0;
}
}
}

diagram_scores

  • ShowScores.cs : almacenará en el componente Text del objeto al que está asociado el porcentaje de aciertos del usuario a las preguntas, basándose en el script Scores.cs que se le pase por Inspector del que tomará los resultados. El script estará asociado al objeto Scores_txt.

using UnityEngine;
using UnityEngine.UI;
using System.Collections;

// Almacena en el componente Text los resultados obtenidos de las respuestas del test.
//
public class ShowScores : MonoBehaviour
{

Text text; // Almacenara el texto que mostrara el porcentaje de acierto a las preguntas.

float scores; // Almacenara el porcentaje de acierto del usuario.

public Scores scr; // Almacenara el componente Scores(Script) que se le pase en Inspector.

void Awake ()
{
text = GetComponent<Text> ();
}

void Update ()
{
scores = scr.results;
scores *= 100;
scores = Mathf.Round(scores);
scores /= 100;
text.text = "Porcentaje de aciertos: " + scores +"%.";
}
}

diagram_showscores

  • Solids.cs : se encargará de asignar tres sólidos aleatorios del conjunto de seis a las posiciones de los Anchor Points. Una vez asignados a dichas posiciones se activarán en la escena. El script estará asociado al objeto Solids, hijo del objeto Street, al que están asociados los sólidos.

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class Solids : MonoBehaviour
{
// Almacenará los objetos correspondientes a los sólidos y el componente Transform de los Anchor Points.
//
public GameObject cube, sphere, cylinder, capsule, prism, circle;
public Transform anchor1, anchor2, anchor3;

int select, count, i;

// Se crea una lista con los sólidos de la escena y se selecciona de manera aleatoria tres
// de ellos para asignarlos a la posición de los Anchor Points y activarlos.
//
void Awake ()
{
List<GameObject> solids = new List<GameObject> ()
{
cube,
sphere,
cylinder,
capsule,
prism,
circle,
};


for (i=1; i<4; i++)
{
select = Random.Range(0, solids.Count);
switch(i)
{
case 1:
solids[select].GetComponent<Transform>().position = anchor1.position;
break;
case 2:
solids[select].GetComponent<Transform>().position = anchor2.position;
break;
case 3:
solids[select].GetComponent<Transform>().position = anchor3.position;
break;
}
solids[select].SetActive(true);
solids.RemoveAt (select);
}
}
}

diagram_solids

  • StartRecallPhase.cs : comprueba si el personaje atraviesa el objeto CheckEnd que marca el fin de la calle. De ser así finaliza la Learning Phase y lanza la Recall Phase. Dentro se encuentra también la función encargada de mostrar las preguntas en la RecallPhase (empezando por las que preguntan por los sólidos presentes en la calle) y sus resultados cuando ya no haya más preguntas que mostrar. El script estará asociado al objeto CheckEnd.

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class StartRecallPhase : MonoBehaviour
{
public GameObject q1,q2,q3,q4,q5,q6; // Almacenará los objetos de las posibles preguntas del test.
public GameObject cube, sphere, cylinder, capsule, prism, circle; // Almacenará todos los posibles sólidos.
public GameObject scores;
public GameObject fpsc; // Almacenará el objeto del personaje.
public GameObject cam; // Almacenará el objeto de la camara de la Recall Phase.
public GameObject recallPhase; // Almacenará el objeto Recall Phase;

public Transform anchor1, anchor2, anchor3;

int select;
int count = 3;

List<GameObject> allSolidsQuestions = new List<GameObject>(); // Lista con las preguntas de todos los sólidos.
List<GameObject> streetSolidsQuestions = new List<GameObject>(); // Lista con las preguntas de los sólidos de la calle.
List<GameObject> allSolids = new List<GameObject>(); // Lista con todos los sólidos posibles.

// Esta función añadirá a la lista streetSolidsQuestions la pregunta correspondiente al sólido
// que se encuentre en la posición del Anchor Point pasado como argumento.
//
void AddStreetSolidsQuestions(Transform anchorPoint)
{
for (int i = 0; i < allSolids.Count; i++)
{
if (allSolids[i].transform.position == anchorPoint.position)
{
switch (allSolids[i].name)
{
case "Cube":
streetSolidsQuestions.Add(q1);
break;
case "Sphere":
streetSolidsQuestions.Add(q2);
break;
case "Cylinder":
streetSolidsQuestions.Add(q3);
break;
case "Capsule":
streetSolidsQuestions.Add(q4);
break;
case "Prism":
streetSolidsQuestions.Add(q5);
break;
case "Circle":
streetSolidsQuestions.Add(q6);
break;
}
}
}
}


// Al inicio se añaden los objetos de las listas declaradas anteriormente.
//
void Start()
{
allSolids.Add(cube);
allSolids.Add(sphere);
allSolids.Add(cylinder);
allSolids.Add(capsule);
allSolids.Add(prism);
allSolids.Add(circle);

AddStreetSolidsQuestions(anchor1);
AddStreetSolidsQuestions(anchor2);
AddStreetSolidsQuestions(anchor3);

allSolidsQuestions.Add (q1);
allSolidsQuestions.Add (q2);
allSolidsQuestions.Add (q3);
allSolidsQuestions.Add (q4);
allSolidsQuestions.Add (q5);
allSolidsQuestions.Add (q6);
}


// Mostrará cual es la siguiente pregunta que de la Recall Phase. Empezará
// mostrando las correspondientes a los objetos situados en la calle.
// En caso de que ya no haya más preguntas mostrará los resultados.
//
public void nextQuestion()
{
if (streetSolidsQuestions.Count != 0)
{
streetSolidsQuestions[0].SetActive(true);
streetSolidsQuestions.RemoveAt(0);
}
else
{
if (allSolidsQuestions.Count != 0 && count != 0)
{
select = Random.Range(0, allSolidsQuestions.Count);
allSolidsQuestions[select].SetActive(true);
allSolidsQuestions.RemoveAt(select);
count--;
}
else
{
scores.SetActive(true);
}
}
}


// Comprueba si el personaje atraviesa al objeto que marca el fin de la calle y de
// ser asi comienza la Recall Phase.
//
void OnTriggerEnter(Collider other)
{
if (other.CompareTag ("Player"))
{
recallPhase.SetActive(true);
nextQuestion();
fpsc.SetActive (false);
cam.SetActive (true);
}
}
}

diagram_startrecallphase

El funcionamiento de los botones en las respuestas a las preguntas de la Recall Phase será el mismo que en la iteración 1.

Deja un comentario