Home | Clases | Unity: Plataformas en 3D | Receta 5: Monedas y premios

Receta 5: Monedas y premios


Introducción

En esta receta vamos a utilizar el escenario y la interfaz de usuario de la receta 4 para añadir una serie de elementos coleccionables (monedas) que incrementarán el contador del jugador.

Además, añadiremos ciertos premios que permitirán, por ejemplo, incrementar la potencia de salto o ganar una vida.

Puedes comprobar el objetivo final haciendo clic AQUÍ.

Las monedas coleccionables

Con todo lo anterior, lo único que necesita nuestro escenario es añadir una serie de elementos para recoger.

Empezaremos por crear una moneda como modelo o Prefab. Para ello, creamos un Empty Object llamado Monedas y dentro un 3D > Cylinder llamado Moneda al que daremos forma de moneda, así como un material amarillo de efecto dorado.

Recuerda resetear la posición de Monedas y luego coloca la Moneda encima de la plataforma fija (roja).

Además, vamos a añadir este pequeño script a la moneda para que esté constantemente girando sobre si misma:


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

public class Moneda : MonoBehaviour {

void Update () {

//Rota la moneda una cantidad diferente en cada dirección y en cada intervalo de tiempo
transform.Rotate(new Vector3(0,0,90) * Time.deltaTime);

}
}


Con esto ya tendríamos nuestra Moneda modelo, si bien como pondremos muchas y no queremos que el motor de Unity tenga que estar procesando y cacheando las rotaciones constantemente, es recomendable añadirle un Rigidbody con la propiedad Is Kinematic activada y la propiedad Use Gravity desactivada.

Además, vamos a marcar la propiedad Is Trigger de la componente Capsule Collider de la Moneda, y vamos a crear y aplicar una etiqueta o tag llamada Moneda a dicha Moneda.

El aspecto debería ser similar a este:



Para finalizar de crear nuestro modelo, crea una carpeta llamada Prefabs dentro de Assets y arrastra la Moneda a dicha carpeta. Desde ese momento, todas las monedas que creemos a partir de dicho Prefab (arrastrando a la Hierarchy window o a la Scene window) contendrán todas las propiedades y componentes de su Prefab, además de que si en algún momento modificamos dicho Prefab, las modificaciones afectarán a todos los elementos creados anteriormente a partir de él.

Una vez hecho esto, es el momento de crear en tu escenario tantas monedas como quieras (a partir del Prefab). La cantidad no importa, pero debes saber el número exacto de monedas que creas para luego poder contabilizarlas. En mi caso, tengo 20 monedas y he modificado la posición de la cámara para que puedas verlas todas:



Contabilizar las monedas y comprobar si he terminado

Para recoger las monedas debemos generar la lógica necesaria que las contabilice y las muestre en pantalla. Además, debemos comprobar si ha recogido todas las monedas para indicar mediante un mensaje que ha completado el juego.

Existen dos maneras de llevar el contador de monedas:

  • de forma incremental: el contador inicial está a 0 y va sumando monedas.
  • de forma decremental: el contador inicial muestra la cantidad de monedas a recoger y va decreciendo a medida que las recogemos hasta llegar a 0.

A mi particularmente me parece más intuitiva la manera decremental y es la que voy a implementar aquí, pero si quieres hacerlo de la otra forma sería cuestión de cambiar un par de líneas de código.

Puesto que las monedas las recoge el jugador y en desarrollo de videojuegos tendemos a aplicar la lógica de la programación a los elementos que provocan dicha lógica, el código necesario para contabilizar las monedas y comprobar si he terminado lo añadiremos al script JugadorController:


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

public class JugadorController : MonoBehaviour {

//Declarlo la variable de tipo RigidBody que luego asociaremos a nuestro Jugador
private Rigidbody rb;

//Declaro la variable pública velocidad para poder modificarla desde la Inspector window
[Range(1,10)]
public float velocidad = 5;

//Declaro la variable pública salto para poder modificarla desde la Inspector window
[Range(1,10)]
public float salto = 7;

//Límites en X y Z del Suelo
int limiteSuperior = 15;
int limiteInferior = -15;

//Variable para el número de vidas
int vidas = 3;

//Variable para asociar el objeto Texto Vidas
public Text textoVidas;

//variable para la posición inicial del jugador
Vector3 posicionInicial;

//Variable para asociar el objeto Mensajes
public Text textoMensajes;

//Variable para comprobar si debo seguir incrementando el tiempo transcurrido
public bool isTiempo = true;

//Variable para contabilizar las monedas
int monedas = 20;

//Variable para asociar el objeto Texto Coleccionables (que mostrará las monedas restantes)
public Text textoColeccionables;

//Variables para poder obtener el tiempo transcurrido del script Tiempo
public GameObject canvas;
Tiempo scriptTiempo;

void Start () {

//Capturo el rigidbody del jugador al iniciar el juego
rb = GetComponent<Rigidbody>();

//Inicializo el texto del contador de vidas
textoVidas.text = "Vidas: " + vidas;

//Inicio el texto de mensajes a vacío
textoMensajes.text = "";

//Capturo la posición inicial del jugador para cuando pierda una vida
posicionInicial = transform.position;

//Inicializo el texto del contador de monedas
textoColeccionables.text = "Monedas: " + monedas;

//Capturo el componente Tiempo del canvas
scriptTiempo = canvas.GetComponent<Tiempo>();

}

void FixedUpdate () {

if (vidas > 0 && monedas > 0){
//Muevo el jugador (si tiene vidas y monedas pendientes)
moverJugador();
//Compruebo si se ha salido del suelo en X o Z
if (transform.position.x > limiteSuperior ||
transform.position.x < limiteInferior || 
transform.position.z > limiteSuperior ||
transform.position.z < limiteInferior){

//Quito una vida
quitarVida();
}
}
else if (vidas == 0){
//Muestro mensaje (si no tiene vidas)
textoMensajes.text = "Juego Terminado";
if (isTiempo)
{
StartCoroutine(FadeInOutText(textoMensajes, 0.5f, 5.0f, false));
}
//Pongo isTiempo a false para que deje de contar el script Tiempo
isTiempo = false;
}
else if (monedas == 0){
//Muestro mensaje (si ha completado el juego)
textoMensajes.text = "¡Has completado el juego en " + scriptTiempo.formatearTiempo();
textoMensajes.color = new Color(0, 255, 0); //Color verde
if (isTiempo)
{
StartCoroutine(FadeInOutText(textoMensajes, 0.5f, 5.0f, false));
}
//Pongo isTiempo a false para que deje de contar el script Tiempo
isTiempo = false;
}

}

//Compruebo si el jugador está en el suelo antes de saltar (para que no vuele)
private bool isSuelo(){

//Genero el array de colisiones de la esfera/jugador pasando su centro y su radio
Collider[] colisiones = Physics.OverlapSphere(transform.position, 0.5f);
//Recorro ese array y si está colisionando con el suelo devuelvo true
foreach (Collider colision in colisiones){
if (colision.tag == "Suelo"){
return true;
}
}
return false;

}

//Quito una vida y muevo al jugador a la posición inicial
void quitarVida(){

//Resto una vida
vidas--;
//Actualizo el contador de vidas
textoVidas.text = "Vidas: " + vidas;
//Devuelvo el Jugador a su posición inicial y le quito la fuerza
transform.position = posicionInicial;
rb.velocity = Vector3.zero;

}

//Lógica necesaria para mover al jugador
void moverJugador(){

//Capturo el movimiento en horizontal y vertical de nuestro teclado
float movimientoH = Input.GetAxis("Horizontal");
float movimientoV = Input.GetAxis("Vertical");

//Genero el vector de movimiento asociado, teniendo en cuenta la velocidad
Vector3 movimiento = new Vector3(movimientoH * velocidad, 0.0f, movimientoV * velocidad);

//Aplico ese movimiento al RigidBody del jugador
rb.AddForce(movimiento);

//Si pulsa el botón de saltar y está en el suelo
if (Input.GetButtonDown("Jump") && isSuelo()){
//Aplico el movimiento vertical con la potencia de salto
rb.velocity += Vector3.up * salto;
}

}

//Mostrar (y ocultar) texto con fade in/out
private IEnumerator FadeInOutText(Text texto, float duracionIn, float duracionOut, bool ocultar){

//Fade in
texto.color = new Color(texto.color.r, texto.color.g, texto.color.b, 0); //opacidad a 0
while (texto.color.a < 1.0f){
//Voy incrementando la opacidad hasta llegar a 1
texto.color = new Color(texto.color.r, texto.color.g, texto.color.b, texto.color.a + duracionIn * Time.deltaTime);
yield return null;
}

//Fade out
if (ocultar){
texto.color = new Color(texto.color.r, texto.color.g, texto.color.b, 1); //opacidad a 1
while (texto.color.a > 0.0f){
//Voy decrementando la opacidad hasta llegar a 0
texto.color = new Color(texto.color.r, texto.color.g, texto.color.b, texto.color.a - duracionOut * Time.deltaTime);
yield return null;
}
}

}

//Se ejecuta al entrar a un objeto con la opción isTrigger seleccionada
void OnTriggerEnter(Collider other) {

if (other.gameObject.CompareTag ("Moneda")){

//Desactivo el objeto
other.gameObject.SetActive (false);
//Decremento el contador de monedas en uno (también se puede hacer como monedas = monedas -1)
monedas--;
//Actualizo el texto del contador de monedas
textoColeccionables.text = "Monedas: " + monedas;

}

}

}


Recuerda asociar los objetos Canvas y Texto Coleccionables con sus variables correspondientes en Jugador Controller.


Incrementar la potencia de salto durante un tiempo determinado

Una vez entendida la lógica de recolección de monedas, vamos a plantearnos crear 3 coleccionables en las 3 esquinas desocupadas de nuestro juego que nos permitan incrementar la potencia de salto durante 10 segundos. Además, durante ese tiempo el jugador tendrá un efecto alrededor para indicarlo.

  • Crear un Empty Object llamado Capsulas y dentro de él una cápsula mediante 3D Object > Capsule llamada Capsula
  • Crea un nuevo material de color naranja y aplícaselo a Capsula
  • Crea una etiqueta o tag llamada Capsula y asígnala a la Capsula.
  • Marca la propiedad Is Trigger de su Capsule Collider


Para terminar, vamos a aplicar un efecto de cambio de color progresivo de naranja a fucsia creando y asociándole un nuevo script ColorMaterial con el siguiente código:


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

public class ColorMaterial : MonoBehaviour {

//variables para el material, el color del material y la dirección
Material material;
Color color;
int direccion = 1;

void Start () {

//Capturo del objeto el material y el color del material
material = GetComponent<Renderer>().material;
color = material.color;

}

void Update () {

//Compruebo en qué dirección debo ir
if (color.b >= 1.0f){ //azul a 1 (fucsia)
direccion = -1;
}
else if (color.b <= 0.0f){ //azul a 0 (naranja)
direccion = 1;
}

//Incremento o decremento cantidad de azul
color.b += direccion * Time.deltaTime;
//Asigno el color al material
material.color = color;

}

}


Una vez hecho esto, arrastra Capsula a la carpeta Prefabs y crea otras dos cápsulas a partir de su prefab en las esquinas vacías del Suelo.

El resultado podría ser similar a este:



Y ahora, de igual manera que hicimos con las monedas, vamos a modificar JugadorController de modo que compruebe si ha colisionado con un objeto cuyo tag sea Capsula. Si es así, debemos iniciar un contador de 10 segundos durante el cual la potencia de salto se verá modificada. El código de JugadorController modificado sería como sigue:


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

public class JugadorController : MonoBehaviour {

//Declarlo la variable de tipo RigidBody que luego asociaremos a nuestro Jugador
private Rigidbody rb;

//Declaro la variable pública velocidad para poder modificarla desde la Inspector window
[Range(1,10)]
public float velocidad = 5;

//Declaro la variable pública salto para poder modificarla desde la Inspector window
[Range(1,10)]
public float salto = 7;

//Límites en X y Z del Suelo
int limiteSuperior = 15;
int limiteInferior = -15;

//Variable para el número de vidas
int vidas = 3;

//Variable para asociar el objeto Texto Vidas
public Text textoVidas;

//variable para la posición inicial del jugador
Vector3 posicionInicial;

//Variable para asociar el objeto Mensajes
public Text textoMensajes;

//Variable para comprobar si debo seguir incrementando el tiempo transcurrido
public bool isTiempo = true;

//Variable para contabilizar las monedas
int monedas = 20;

//Variable para asociar el objeto Texto Coleccionables (que mostrará las monedas restantes)
public Text textoColeccionables;

//Variables para poder obtener el tiempo transcurrido del script Tiempo
public GameObject canvas;
Tiempo scriptTiempo;

//Variables para contar y activar el tiempo transcurrido de salto extra e incrementar la potencia
float tiempoSalto = 0;
bool isSaltoExtra = false;
int saltoExtra = 3;

void Start () {

//Capturo el rigidbody del jugador al iniciar el juego
rb = GetComponent<Rigidbody>();

//Inicializo el texto del contador de vidas
textoVidas.text = "Vidas: " + vidas;

//Inicio el texto de mensajes a vacío
textoMensajes.text = "";

//Capturo la posición inicial del jugador para cuando pierda una vida
posicionInicial = transform.position;

//Inicializo el texto del contador de monedas
textoColeccionables.text = "Monedas: " + monedas;

//Capturo el componente Tiempo del canvas
scriptTiempo = canvas.GetComponent<Tiempo>();

}

void FixedUpdate () {

if (vidas > 0 && monedas > 0){
//Muevo el jugador (si tiene vidas y monedas pendientes)
moverJugador();
//Compruebo si se ha salido del suelo en X o Z
if (transform.position.x > limiteSuperior ||
transform.position.x < limiteInferior || 
transform.position.z > limiteSuperior ||
transform.position.z < limiteInferior){

//Quito una vida
quitarVida();
}
}
else if (vidas == 0){
//Muestro mensaje (si no tiene vidas)
textoMensajes.text = "Juego Terminado";
if (isTiempo)
{
StartCoroutine(FadeInOutText(textoMensajes, 0.5f, 5.0f, false));
}
//Pongo isTiempo a false para que deje de contar el script Tiempo
isTiempo = false;
}
else if (monedas == 0){
//Muestro mensaje (si ha completado el juego)
textoMensajes.text = "¡Has completado el juego en " + scriptTiempo.formatearTiempo();
textoMensajes.color = new Color(0, 255, 0); //Color verde
if (isTiempo)
{
StartCoroutine(FadeInOutText(textoMensajes, 0.5f, 5.0f, false));
}
//Pongo isTiempo a false para que deje de contar el script Tiempo
isTiempo = false;
}

//Compruebo si tiene potencia de salto extra
if (isSaltoExtra){
//Incremento tiempo
tiempoSalto += Time.deltaTime;
//Compruebo si llega a 10 segundos
if (tiempoSalto >= 10){
salto -= saltoExtra; //Asigno la potencia de salto original
tiempoSalto = 0; //Reseteo el contador de tiempo de salto extra
isSaltoExtra = false; //Asigno el boolenao de salto extra a false
}
}


}

//Compruebo si el jugador está en el suelo antes de saltar (para que no vuele)
private bool isSuelo(){

//Genero el array de colisiones de la esfera/jugador pasando su centro y su radio
Collider[] colisiones = Physics.OverlapSphere(transform.position, 0.5f);
//Recorro ese array y si está colisionando con el suelo devuelvo true
foreach (Collider colision in colisiones){
if (colision.tag == "Suelo"){
return true;
}
}
return false;

}

//Quito una vida y muevo al jugador a la posición inicial
void quitarVida(){

//Resto una vida
vidas--;
//Actualizo el contador de vidas
textoVidas.text = "Vidas: " + vidas;
//Devuelvo el Jugador a su posición inicial y le quito la fuerza
transform.position = posicionInicial;
rb.velocity = Vector3.zero;

}

//Lógica necesaria para mover al jugador
void moverJugador(){

//Capturo el movimiento en horizontal y vertical de nuestro teclado
float movimientoH = Input.GetAxis("Horizontal");
float movimientoV = Input.GetAxis("Vertical");

//Genero el vector de movimiento asociado, teniendo en cuenta la velocidad
Vector3 movimiento = new Vector3(movimientoH * velocidad, 0.0f, movimientoV * velocidad);

//Aplico ese movimiento al RigidBody del jugador
rb.AddForce(movimiento);

//Si pulsa el botón de saltar y está en el suelo
if (Input.GetButtonDown("Jump") && isSuelo()){
//Aplico el movimiento vertical con la potencia de salto
rb.velocity += Vector3.up * salto;
}

}

//Mostrar (y ocultar) texto con fade in/out
private IEnumerator FadeInOutText(Text texto, float duracionIn, float duracionOut, bool ocultar){

//Fade in
texto.color = new Color(texto.color.r, texto.color.g, texto.color.b, 0); //opacidad a 0
while (texto.color.a < 1.0f){
//Voy incrementando la opacidad hasta llegar a 1
texto.color = new Color(texto.color.r, texto.color.g, texto.color.b, texto.color.a + duracionIn * Time.deltaTime);
yield return null;
}

//Fade out
if (ocultar){
texto.color = new Color(texto.color.r, texto.color.g, texto.color.b, 1); //opacidad a 1
while (texto.color.a > 0.0f){
//Voy decrementando la opacidad hasta llegar a 0
texto.color = new Color(texto.color.r, texto.color.g, texto.color.b, texto.color.a - duracionOut * Time.deltaTime);
yield return null;
}
}

}

//Se ejecuta al entrar a un objeto con la opción isTrigger seleccionada
void OnTriggerEnter(Collider other) {

if (other.gameObject.CompareTag ("Moneda")){

//Desactivo el objeto
other.gameObject.SetActive (false);
//Decremento el contador de monedas en uno (también se puede hacer como monedas = monedas -1)
monedas--;
//Actualizo el texto del contador de monedas
textoColeccionables.text = "Monedas: " + monedas;

}

else if (other.gameObject.CompareTag ("Capsula")){

//Desactivo el objeto
other.gameObject.SetActive (false);
//Incremento potencia de salto
salto += saltoExtra;
//Activo el booleano isSaltoExtra
isSaltoExtra = true;
}

}

}


No obstante, habíamos dicho que mientras durara la potencia de salto, le íbamos a aplicar a la bola un efecto. Para ello vamos a hacer uso del sistema de partículas de Unity o Particle System. Añade a Jugador un objeto Effects > Particle System y en la Inspector Window realiza los siguientes cambios:

  • Duration: 1.00
  • Start Color: Naranja
  • Simulation Space: World
  • Max particles: 100
  • Shape > Shape: Sphere

Esto es solo un ejemplo, trastea con las diferentes opciones hasta buscar el efecto que te guste, el mío es más o menos así:



Ahora lo único que queda es modificar el JugadorController para que el sistema de partículas esté desactivado por defecto y solo se active mientras dure la potencia de salto extra:


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

public class JugadorController : MonoBehaviour {

//Declarlo la variable de tipo RigidBody que luego asociaremos a nuestro Jugador
private Rigidbody rb;

//Declaro la variable pública velocidad para poder modificarla desde la Inspector window
[Range(1,10)]
public float velocidad = 5;

//Declaro la variable pública salto para poder modificarla desde la Inspector window
[Range(1,10)]
public float salto = 7;

//Límites en X y Z del Suelo
int limiteSuperior = 15;
int limiteInferior = -15;

//Variable para el número de vidas
int vidas = 3;

//Variable para asociar el objeto Texto Vidas
public Text textoVidas;

//variable para la posición inicial del jugador
Vector3 posicionInicial;

//Variable para asociar el objeto Mensajes
public Text textoMensajes;

//Variable para comprobar si debo seguir incrementando el tiempo transcurrido
public bool isTiempo = true;

//Variable para contabilizar las monedas
int monedas = 20;

//Variable para asociar el objeto Texto Coleccionables (que mostrará las monedas restantes)
public Text textoColeccionables;

//Variables para poder obtener el tiempo transcurrido del script Tiempo
public GameObject canvas;
Tiempo scriptTiempo;

//Variables para contar y activar el tiempo transcurrido de salto extra e incrementar la potencia
float tiempoSalto = 0;
bool isSaltoExtra = false;
int saltoExtra = 3;

//Variable para el sistema de partículas
public ParticleSystem particulas;


void Start () {

//Capturo el rigidbody del jugador al iniciar el juego
rb = GetComponent<Rigidbody>();

//Inicializo el texto del contador de vidas
textoVidas.text = "Vidas: " + vidas;

//Inicio el texto de mensajes a vacío
textoMensajes.text = "";

//Capturo la posición inicial del jugador para cuando pierda una vida
posicionInicial = transform.position;

//Inicializo el texto del contador de monedas
textoColeccionables.text = "Monedas: " + monedas;

//Capturo el componente Tiempo del canvas
scriptTiempo = canvas.GetComponent<Tiempo>();

//Paro el sistema de partículas del jugador
particulas.Stop();


}

void FixedUpdate () {

if (vidas > 0 && monedas > 0){
//Muevo el jugador (si tiene vidas y monedas pendientes)
moverJugador();
//Compruebo si se ha salido del suelo en X o Z
if (transform.position.x > limiteSuperior ||
transform.position.x < limiteInferior || 
transform.position.z > limiteSuperior ||
transform.position.z < limiteInferior){

//Quito una vida
quitarVida();
}
}
else if (vidas == 0){
//Muestro mensaje (si no tiene vidas)
textoMensajes.text = "Juego Terminado";
if (isTiempo)
{
StartCoroutine(FadeInOutText(textoMensajes, 0.5f, 5.0f, false));
}
//Pongo isTiempo a false para que deje de contar el script Tiempo
isTiempo = false;
}
else if (monedas == 0){
//Muestro mensaje (si ha completado el juego)
textoMensajes.text = "¡Has completado el juego en " + scriptTiempo.formatearTiempo();
textoMensajes.color = new Color(0, 255, 0); //Color verde
if (isTiempo)
{
StartCoroutine(FadeInOutText(textoMensajes, 0.5f, 5.0f, false));
}
//Pongo isTiempo a false para que deje de contar el script Tiempo
isTiempo = false;
}

//Compruebo si tiene potencia de salto extra
if (isSaltoExtra){
//Incremento tiempo
tiempoSalto += Time.deltaTime;
//Compruebo si llega a 10 segundos
if (tiempoSalto >= 10){
salto -= saltoExtra; //Asigno la potencia de salto original
tiempoSalto = 0; //Reseteo el contador de tiempo de salto extra
isSaltoExtra = false; //Asigno el boolenao de salto extra a false
particulas.Stop(); //Paro el sistema de partículas del jugador
}
}


}

//Compruebo si el jugador está en el suelo antes de saltar (para que no vuele)
private bool isSuelo(){

//Genero el array de colisiones de la esfera/jugador pasando su centro y su radio
Collider[] colisiones = Physics.OverlapSphere(transform.position, 0.5f);
//Recorro ese array y si está colisionando con el suelo devuelvo true
foreach (Collider colision in colisiones){
if (colision.tag == "Suelo"){
return true;
}
}
return false;

}

//Quito una vida y muevo al jugador a la posición inicial
void quitarVida(){

//Resto una vida
vidas--;
//Actualizo el contador de vidas
textoVidas.text = "Vidas: " + vidas;
//Devuelvo el Jugador a su posición inicial y le quito la fuerza
transform.position = posicionInicial;
rb.velocity = Vector3.zero;

}

//Lógica necesaria para mover al jugador
void moverJugador(){

//Capturo el movimiento en horizontal y vertical de nuestro teclado
float movimientoH = Input.GetAxis("Horizontal");
float movimientoV = Input.GetAxis("Vertical");

//Genero el vector de movimiento asociado, teniendo en cuenta la velocidad
Vector3 movimiento = new Vector3(movimientoH * velocidad, 0.0f, movimientoV * velocidad);

//Aplico ese movimiento al RigidBody del jugador
rb.AddForce(movimiento);

//Si pulsa el botón de saltar y está en el suelo
if (Input.GetButtonDown("Jump") && isSuelo()){
//Aplico el movimiento vertical con la potencia de salto
rb.velocity += Vector3.up * salto;
}

}

//Mostrar (y ocultar) texto con fade in/out
private IEnumerator FadeInOutText(Text texto, float duracionIn, float duracionOut, bool ocultar){

//Fade in
texto.color = new Color(texto.color.r, texto.color.g, texto.color.b, 0); //opacidad a 0
while (texto.color.a < 1.0f){
//Voy incrementando la opacidad hasta llegar a 1
texto.color = new Color(texto.color.r, texto.color.g, texto.color.b, texto.color.a + duracionIn * Time.deltaTime);
yield return null;
}

//Fade out
if (ocultar){
texto.color = new Color(texto.color.r, texto.color.g, texto.color.b, 1); //opacidad a 1
while (texto.color.a > 0.0f){
//Voy decrementando la opacidad hasta llegar a 0
texto.color = new Color(texto.color.r, texto.color.g, texto.color.b, texto.color.a - duracionOut * Time.deltaTime);
yield return null;
}
}

}

//Se ejecuta al entrar a un objeto con la opción isTrigger seleccionada
void OnTriggerEnter(Collider other) {

if (other.gameObject.CompareTag ("Moneda")){

//Desactivo el objeto
other.gameObject.SetActive (false);
//Decremento el contador de monedas en uno (también se puede hacer como monedas = monedas -1)
monedas--;
//Actualizo el texto del contador de monedas
textoColeccionables.text = "Monedas: " + monedas;

}

else if (other.gameObject.CompareTag ("Capsula")){

//Desactivo el objeto
other.gameObject.SetActive (false);
//Incremento potencia de salto
salto += saltoExtra;
//Activo el booleano isSaltoExtra
isSaltoExtra = true;
//Inicio el sistema de partículas del jugador
particulas.Play();
}

}

}


Por supuesto, no olvides asociar el objeto Particle System a la variable Particulas.

Ganar una vida

Para terminar, vamos a añadir al juego la lógica necesaria para que si el jugador recoge las 10 primeras monedas en menos de 30 segundos le añada una vida adicional. Esto lo realizaremos de nuevo modificando el código de JugadorController, en el que recuperaremos la variable tiempo que lleva el tiempo transcurrido y si antes de que llegue a 30 segundos el contador de monedas es menor o igual que 10, añadiremos una vida al contador de vidas y mostraremos un mensaje temporal que lo indique:


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

public class JugadorController : MonoBehaviour {

//Declarlo la variable de tipo RigidBody que luego asociaremos a nuestro Jugador
private Rigidbody rb;

//Declaro la variable pública velocidad para poder modificarla desde la Inspector window
[Range(1,10)]
public float velocidad = 5;

//Declaro la variable pública salto para poder modificarla desde la Inspector window
[Range(1,10)]
public float salto = 7;

//Límites en X y Z del Suelo
int limiteSuperior = 15;
int limiteInferior = -15;

//Variable para el número de vidas
int vidas = 3;

//Variable para asociar el objeto Texto Vidas
public Text textoVidas;

//variable para la posición inicial del jugador
Vector3 posicionInicial;

//Variable para asociar el objeto Mensajes
public Text textoMensajes;

//Variable para comprobar si debo seguir incrementando el tiempo transcurrido
public bool isTiempo = true;

//Variable para contabilizar las monedas
int monedas = 20;

//Variable para asociar el objeto Texto Coleccionables (que mostrará las monedas restantes)
public Text textoColeccionables;

//Variables para poder obtener el tiempo transcurrido del script Tiempo
public GameObject canvas;
Tiempo scriptTiempo;

//Variables para contar y activar el tiempo transcurrido de salto extra e incrementar la potencia
float tiempoSalto = 0;
bool isSaltoExtra = false;
int saltoExtra = 3;

//Variable para el sistema de partículas
public ParticleSystem particulas;

//Boolenao para no asignar más de una vida
bool isVida = false;


void Start () {

//Capturo el rigidbody del jugador al iniciar el juego
rb = GetComponent<Rigidbody>();

//Inicializo el texto del contador de vidas
textoVidas.text = "Vidas: " + vidas;

//Inicio el texto de mensajes a vacío
textoMensajes.text = "";

//Capturo la posición inicial del jugador para cuando pierda una vida
posicionInicial = transform.position;

//Inicializo el texto del contador de monedas
textoColeccionables.text = "Monedas: " + monedas;

//Capturo el componente Tiempo del canvas
scriptTiempo = canvas.GetComponent<Tiempo>();

//Paro el sistema de partículas del jugador
particulas.Stop();


}

void FixedUpdate () {

if (vidas > 0 && monedas > 0){
//Muevo el jugador (si tiene vidas y monedas pendientes)
moverJugador();
//Compruebo si se ha salido del suelo en X o Z
if (transform.position.x > limiteSuperior ||
transform.position.x < limiteInferior || 
transform.position.z > limiteSuperior ||
transform.position.z < limiteInferior){

//Quito una vida
quitarVida();
}
}
else if (vidas == 0){
//Muestro mensaje (si no tiene vidas)
textoMensajes.text = "Juego Terminado";
if (isTiempo)
{
StartCoroutine(FadeInOutText(textoMensajes, 0.5f, 5.0f, false));
}
//Pongo isTiempo a false para que deje de contar el script Tiempo
isTiempo = false;
}
else if (monedas == 0){
//Muestro mensaje (si ha completado el juego)
textoMensajes.text = "¡Has completado el juego en " + scriptTiempo.formatearTiempo();
textoMensajes.color = new Color(0, 255, 0); //Color verde
if (isTiempo)
{
StartCoroutine(FadeInOutText(textoMensajes, 0.5f, 5.0f, false));
}
//Pongo isTiempo a false para que deje de contar el script Tiempo
isTiempo = false;
}

//Compruebo si tiene potencia de salto extra
if (isSaltoExtra){
//Incremento tiempo
tiempoSalto += Time.deltaTime;
//Compruebo si llega a 10 segundos
if (tiempoSalto >= 10){
salto -= saltoExtra; //Asigno la potencia de salto original
tiempoSalto = 0; //Reseteo el contador de tiempo de salto extra
isSaltoExtra = false; //Asigno el boolenao de salto extra a false
particulas.Stop(); //Paro el sistema de partículas del jugador
}
}

//Compruebo si tengo que añadirle una vida
if (!isVida && monedas <= 10 && scriptTiempo.tiempo <= 30){
vidas++; //Añado una vida
//Muestro mensaje
textoMensajes.text = "Has ganado una vida";
if (!isVida)
{
StartCoroutine(FadeInOutText(textoMensajes, 0.5f, 0.3f, true));
}
//Para añadir solo una vida
isVida = true;

}

}

//Compruebo si el jugador está en el suelo antes de saltar (para que no vuele)
private bool isSuelo(){

//Genero el array de colisiones de la esfera/jugador pasando su centro y su radio
Collider[] colisiones = Physics.OverlapSphere(transform.position, 0.5f);
//Recorro ese array y si está colisionando con el suelo devuelvo true
foreach (Collider colision in colisiones){
if (colision.tag == "Suelo"){
return true;
}
}
return false;

}

//Quito una vida y muevo al jugador a la posición inicial
void quitarVida(){

//Resto una vida
vidas--;
//Actualizo el contador de vidas
textoVidas.text = "Vidas: " + vidas;
//Devuelvo el Jugador a su posición inicial y le quito la fuerza
transform.position = posicionInicial;
rb.velocity = Vector3.zero;

}

//Lógica necesaria para mover al jugador
void moverJugador(){

//Capturo el movimiento en horizontal y vertical de nuestro teclado
float movimientoH = Input.GetAxis("Horizontal");
float movimientoV = Input.GetAxis("Vertical");

//Genero el vector de movimiento asociado, teniendo en cuenta la velocidad
Vector3 movimiento = new Vector3(movimientoH * velocidad, 0.0f, movimientoV * velocidad);

//Aplico ese movimiento al RigidBody del jugador
rb.AddForce(movimiento);

//Si pulsa el botón de saltar y está en el suelo
if (Input.GetButtonDown("Jump") && isSuelo()){
//Aplico el movimiento vertical con la potencia de salto
rb.velocity += Vector3.up * salto;
}

}

//Mostrar (y ocultar) texto con fade in/out
private IEnumerator FadeInOutText(Text texto, float duracionIn, float duracionOut, bool ocultar){

//Fade in
texto.color = new Color(texto.color.r, texto.color.g, texto.color.b, 0); //opacidad a 0
while (texto.color.a < 1.0f){
//Voy incrementando la opacidad hasta llegar a 1
texto.color = new Color(texto.color.r, texto.color.g, texto.color.b, texto.color.a + duracionIn * Time.deltaTime);
yield return null;
}

//Fade out
if (ocultar){
texto.color = new Color(texto.color.r, texto.color.g, texto.color.b, 1); //opacidad a 1
while (texto.color.a > 0.0f){
//Voy decrementando la opacidad hasta llegar a 0
texto.color = new Color(texto.color.r, texto.color.g, texto.color.b, texto.color.a - duracionOut * Time.deltaTime);
yield return null;
}
}

}

//Se ejecuta al entrar a un objeto con la opción isTrigger seleccionada
void OnTriggerEnter(Collider other) {

if (other.gameObject.CompareTag ("Moneda")){

//Desactivo el objeto
other.gameObject.SetActive (false);
//Decremento el contador de monedas en uno (también se puede hacer como monedas = monedas -1)
monedas--;
//Actualizo el texto del contador de monedas
textoColeccionables.text = "Monedas: " + monedas;

}

else if (other.gameObject.CompareTag ("Capsula")){

//Desactivo el objeto
other.gameObject.SetActive (false);
//Incremento potencia de salto
salto += saltoExtra;
//Activo el booleano isSaltoExtra
isSaltoExtra = true;
//Inicio el sistema de partículas del jugador
particulas.Play();

}

}

}


Con esto estaría terminada la receta, espero que te haya resultado útil.

Puedes comprobar su funcionamiento haciendo clic AQUÍ.
Fecha de publicación: 19/09/2020
Asignaturas: desarrollo de entornos interactivos multidispositivo
Temas: unity
Utilizamos cookies propias y de terceros para mejorar su experiencia en la navegación. Al seguir navegando entendemos que acepta su uso.
Si lo desea, consulte nuestras políticas de privacidad y cookies
ENTENDIDO
[X] Cerrar

Contacta conmigo


[X] Cerrar

Acceso alumnos