Comedores de Mana / HIKARI entertainment

Programación Orientada a Objetos (Tower defense - kingdom rush)

Moderator: julianmartinez16

User avatar
Xti
Posts: 11
Joined: Tue Jan 22, 2019 2:10 pm

Re: Comedores de Mana / HIKARI entertainment

Post by Xti » Fri May 17, 2019 11:18 am

Image
Soldado Enemigo Ataque

Image
Soldado Enemigo Idle

Image
Soldado Enemigo Caminata

Image
Soldado Aliado Idle

Image
Soldado Aliado Caminata

Image
Soldado Aliado Ataque
Xti

User avatar
danhercha
Posts: 37
Joined: Wed Jan 30, 2019 3:07 pm
Location: Medellín

Re: Comedores de Mana / HIKARI entertainment

Post by danhercha » Wed May 22, 2019 1:05 pm

¿Qué hemos hecho?
Cambiamos las clases de EnemyMovement y EnemyManager a las clases
- Arquero
- Golem
- Espadachin

Las cuales fueron clases heredadas de:
- Enemigo (nueva clase, clase padre)

Luego creamos cada tipo de enemigo (prefab con sprites y animaciones) y reemplazamos enemyhealth por golem/espadachin/arquero

Finalmente en enemy manager en el campo de enemies arrastramos cada uno de esos prefabs.

¿Qué vamos a hacer?
- Terminaremos de hacer las diapositivas para al entrega, incluyendo lo que hicimos hoy.

¿Qué dificultades hemos tenido?
- Gasta ahora ninguna, todo ha salido bien.

---> La explicación del código está en los comentarios
Last edited by danhercha on Wed May 22, 2019 1:12 pm, edited 1 time in total.
Daniela Hernández Chavarro

User avatar
danhercha
Posts: 37
Joined: Wed Jan 30, 2019 3:07 pm
Location: Medellín

Re: Comedores de Mana / HIKARI entertainment

Post by danhercha » Wed May 22, 2019 1:12 pm

CLASE ENEMIGO

Code: Select all

using UnityEngine;
using UnityEngine.AI;

public class Enemy : MonoBehaviour
{
    [SerializeField]private int startingHealth = 100;
    [SerializeField] private int currentHealth;

    public AudioClip deathClip; // separar 

    [SerializeField] private int cantidadDaño = 20;   //Cantidad de daño RECIBIDO (No proporcionado)
    float timer; //suma los segundos
    [SerializeField] private float tiempoEntreDaño;

    GameObject controlJ;

    AudioSource enemyAudio;
    bool isDead;
    UnityEngine.AI.NavMeshAgent nav;    //acceder al navMsh para cambiar su velocidad
    int valorEnemigo; //Nos dira cuantas monedas nos dar{an por vencer ese enemigo

    public GameObject enemigo1; //para activar cual sprite se vera
    public GameObject enemigo2;
    public GameObject enemigo3;
    GameObject textoX;

    int tipoEnemigo;        //Cual de los 3 enemigos es este ... influye en daño, vida y velocidad

    Light colorLuz;

    GameObject zonaActiva;
    int cantidadEnemigos;   //Numero por el que será dividido el daño (cuantos enemigos hay dentro del área)
    int cantidadAliados;    //Numero por el que será multiplicado el daño (cuantos aliados hay dentro del área)

    #region Properties

    public NavMeshAgent Nav
    {
        get
        {
            return nav;
        }

        set
        {
            nav = value;
        }
    }

    public float TiempoEntreDaño
    {
        get
        {
            return tiempoEntreDaño;
        }

        set
        {
            tiempoEntreDaño = value;
        }
    }

    public int CantidadDaño
    {
        get
        {
            return cantidadDaño;
        }

        set
        {
            cantidadDaño = value;
        }
    }

    public int StartingHealth
    {
        get
        {
            return startingHealth;
        }

        set
        {
            startingHealth = value;
        }
    }

    public int CurrentHealth
    {
        get
        {
            return currentHealth;
        }

        set
        {
            currentHealth = value;
        }
    }

    public Light ColorLuz
    {
        get
        {
            return colorLuz;
        }

        set
        {
            colorLuz = value;
        }
    }

    public int ValorEnemigo
    {
        get
        {
            return valorEnemigo;
        }

        set
        {
            valorEnemigo = value;
        }
    }
    #endregion
    void Awake() //se ejecuta en el primer primer fotograma
    {
        enemyAudio = GetComponent<AudioSource>();

        Random aleatorio = new Random();

        nav = GetComponent<UnityEngine.AI.NavMeshAgent>();


        colorLuz = GetComponent<Light>();

    }
    private void Start() //se ejecuta en el primer fotograma
    {
        controlJ = GameObject.FindGameObjectWithTag("GameController"); //Para entrar luego y sumarle a las monedas
        textoX = GameObject.FindGameObjectWithTag("xMuerte");
       
    }

    /*
    El timer es un timeDeltaTime, y en el Update, en cada fotograma
    se va a sumar segundo en un segundo, y así con 2, 3, 4.
    */

    void Update()
    {
        timer += Time.deltaTime; //que sume 1 por segundo

        cantidadEnemigos = zonaActiva.GetComponent<contadorEnemigos>().nEnemigos;
        cantidadAliados = zonaActiva.GetComponent<contadorEnemigos>().nAliados;
    }

    void OnTriggerStay(Collider other)
    {
        if (isDead)
            return;

        /*El tag es para nosotros poder mencionar algo dentro del código y 
        que sepa a qué nos referimos dentro del juego.

        Si yo le digo al código que me busque algo con el tag de enemigo, y 
        tengo más de un enemigo en el mapa, solamente va a encontrar uno.
        
        Si el otro tiene el tag de zonaAtaque y el tiempo es mayor o igual 
        al tiempo entre daño, se ejecuta lo de adentro.
        */

        if (other.CompareTag("zonaAtaque") && timer >= tiempoEntreDaño)
        {
            zonaActiva = other.gameObject;
            //contadro enemigos es otro codigo que cuenta la cantidad de enemigos y aliados que hay en la zona
            //nEnemigos contiene la cantidad de enemigos (entero) que los cuenta en la clase contadorEnemigos
            cantidadEnemigos = other.GetComponent<contadorEnemigos>().nEnemigos;
            cantidadAliados = other.GetComponent<contadorEnemigos>().nAliados;

            //cuenta la cantidad de aliados mas 1

            int resta;
            if (cantidadEnemigos > 0)
            {
                resta = (cantidadDaño / cantidadEnemigos) * (cantidadAliados / 2);
                //dividio 2 porque el codigo sumaba un aliado a la cantidad que estaba
            }
            else resta = 0;

            currentHealth -= resta;
            timer = 0; //se tiene que reiniciar para que el tiempo entre el daño se cumpla

            //Debug.Log(resta);
            //Debug.Log("recive daño"+" "+(cantidadDaño/cantidadEnemigos)*cantidadAliados);
        }

        if (currentHealth <= 0)
        {
            Death();
            //controlJ.GetComponent<aliadoManager>().Ganancia(valorEnemigo);
            //GetComponent<UnityEngine.AI.NavMeshAgent>().enabled = false;

            //enemyAudio.clip = deathClip;
            // enemyAudio.Play();
        }
    }

    void Death()
    {
        textoX.GetComponent<xContador>().Suma(1);
        Debug.Log("Enemigo entra en Death");
        controlJ.GetComponent<aliadoManager>().Ganancia(valorEnemigo); //al morir, vaya a aliadoManager.Ganancia  ejecute Ganancia y sumele valorEnemigo
        isDead = true;
        //Debug.Log ("funciona");
        GetComponent<Rigidbody>().isKinematic = true;
        GetComponent<UnityEngine.AI.NavMeshAgent>().enabled = false;
        Destroy(gameObject, 2f);
        enemyAudio.clip = deathClip;
        enemyAudio.Play();
        zonaActiva.GetComponent<contadorEnemigos>().enemigosResta();
    }
}
CLASE ARQUERO

Code: Select all

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

public class Arquero : Enemy {
    void Awake()
    {
        CurrentHealth = 50;
        CantidadDaño = 30;
        TiempoEntreDaño = 1;
        Nav.speed = 1.5f;
        ColorLuz.color = Color.green;
        ValorEnemigo = 15;
    }
}
CLASE ESPADACHIN

Code: Select all

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

public class Espadachin : Enemy {
	void Awake () {
        CurrentHealth = 100;   //vida actual y en este caso inicial  
        CantidadDaño = 20;      //Cuanto daño recibe
        TiempoEntreDaño = 1;    //cada cuanto lo recibe
        Nav.speed = 1f;         //velocidad del enemigo
        ColorLuz.color = Color.blue;     //color caracteristico con el cual alumbra
        ValorEnemigo = 20; //lo que se suma en las monedas
    }
}
CLASE GOLEM

Code: Select all

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

public class Golem : Enemy {
    void Awake()
    {
        CurrentHealth = 150;
        CantidadDaño = 20;
        TiempoEntreDaño = 2;
        Nav.speed = 0.5f;
        ColorLuz.color = Color.red;
        ValorEnemigo = 25;
    }
}
Last edited by danhercha on Fri May 24, 2019 11:14 am, edited 1 time in total.
Daniela Hernández Chavarro

User avatar
danhercha
Posts: 37
Joined: Wed Jan 30, 2019 3:07 pm
Location: Medellín

Re: Comedores de Mana / HIKARI entertainment

Post by danhercha » Fri May 24, 2019 10:22 am

Last edited by danhercha on Fri May 24, 2019 10:33 am, edited 1 time in total.
Daniela Hernández Chavarro

User avatar
danhercha
Posts: 37
Joined: Wed Jan 30, 2019 3:07 pm
Location: Medellín

Re: Comedores de Mana / HIKARI entertainment

Post by danhercha » Fri May 24, 2019 10:33 am

Daniela Hernández Chavarro

User avatar
danhercha
Posts: 37
Joined: Wed Jan 30, 2019 3:07 pm
Location: Medellín

Re: Comedores de Mana / HIKARI entertainment

Post by danhercha » Fri May 24, 2019 10:47 am

Daniela Hernández Chavarro

User avatar
danhercha
Posts: 37
Joined: Wed Jan 30, 2019 3:07 pm
Location: Medellín

Re: Comedores de Mana / HIKARI entertainment

Post by danhercha » Fri May 24, 2019 11:13 am

Clase Control Enemigo

Code: Select all

public class ControlEnemigo : MonoBehaviour
{

    public GameObject enemigo;

    void Start()
    {
        StartCoroutine(ControlOleadas());
    }

    void Update()
    {
    


    }

    IEnumerator Oleada(float tiempoDiferencia, int cantidadEnemigos)
    {
        for (int i = 0; i < cantidadEnemigos; i++)
        {
            Instantiate(enemigo, transform.position + Vector3.up * Random.Range(-1f, 1f), transform.rotation);
            yield return new WaitForSeconds(tiempoDiferencia);
        }

    }

    IEnumerator ControlOleadas()
    {
        //Oleada 1
        StartCoroutine(Oleada(5, 5));
        yield return new WaitForSeconds(25);

        yield return new WaitForSeconds(5);
        //Oleada 2
        StartCoroutine(Oleada(4, 7));
        yield return new WaitForSeconds(25);

        yield return new WaitForSeconds(5);
        //Oleada 3
        StartCoroutine(Oleada(4, 10));
        yield return new WaitForSeconds(25);

        yield return new WaitForSeconds(5);
        //Oleada 4
        StartCoroutine(Oleada(3, 20));
        yield return new WaitForSeconds(25);

        yield return new WaitForSeconds(5);

        //Oleada 5
        StartCoroutine(Oleada(2, 20));
        yield return new WaitForSeconds(25);

        yield return new WaitForSeconds(5);

    }

}
Clase Cristal

Code: Select all

public class Cristal : MonoBehaviour
{

    public int vida;
    public GameObject gameOver;
    public bool fin;

    void Start()
    {
        gameOver.SetActive(false);
        vida = 1000;
    }

    void Update()
    {

        if (vida <= 0)
        {
            gameOver.SetActive(true);
            fin = true;
        }

        if (fin && Input.GetKeyDown(KeyCode.R))
        {
            SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
        }
    }
}

Clase Enemigo

Code: Select all

public class Enemigo : MonoBehaviour
{

    public float speed;
    public int vida;
    public int daño;
    public int ubicacion;
    public GameObject[] waypoints;
    public GameObject cristal;
    public bool atancando;

    void Start()
    {

        vida = 100;

        waypoints = new GameObject[GameObject.FindGameObjectsWithTag("WayPoints").Length];

        foreach (GameObject way in GameObject.FindGameObjectsWithTag("WayPoints"))
        {
            waypoints[int.Parse(way.name)] = way;
        }

        cristal = GameObject.Find("Cristal");

        StartCoroutine(Daño());
    }

    void Update()
    {

        transform.position += (waypoints[ubicacion].transform.position - transform.position).normalized * Time.deltaTime * speed;
        if ((waypoints[ubicacion].transform.position - transform.position).magnitude < 1)
        {
            if (ubicacion < waypoints.Length - 1) ubicacion++;

        }

        if ((cristal.transform.position - transform.position).magnitude < 1)
        {
            atancando = true;
        }
        else
        {
            atancando = false;
        }

        if (vida <= 0) Destroy(gameObject);
    }

    IEnumerator Daño()
    {
        yield return new WaitForSeconds(1);
        if (atancando) cristal.GetComponent<Cristal>().vida -= daño;
        StartCoroutine(Daño());
    }
}

Clase Menu

Code: Select all

public class MainMenu : MonoBehaviour
{

    public void jugar()
    {
        SceneManager.LoadScene(SceneManager.GetActiveScene().build.Index + 1);

    }

    public void SalirJuego()
    {
        Application.Quit();

    }
}
Clase MoveEnemy

Code: Select all

public class MoveEnemy : MonoBehaviour
{

    //VARIABLES
    [HideInInspector]
    public GameObject[] waypoints; //UN ARRAY QUE TOMA LOS PUNTOS A RECORRER PARA EL ENEMIGO
    private int currentWaypoint = 0; //EL PUNTO RECIENTE DESDE DONDE VA A COMENZAR A MOVERSE EL ENEMIGO
    private float lastWaypointSwitchTime;
    public float speed = 1.0f; //VELOCIDAD DEL ENEMIGO


    void Start()
    {
        lastWaypointSwitchTime = Time.time; //INICIALIZAR LA VARIABLE DESDE EL ÚLTIMO PUNTO DEL RECORRIDO DEL ENEMIGO
                                            //COMO RECIÉN VA A EMPEZAR SU RECORRIDO, ESTE VALOR SERÁ 0, ES DECIR, DESDE EL PUNTO 0 EMPEZARÁ A CAMINAR   
    }


    void Update() //PROCESO DE MOVIMIENTO DEL ENEMIGO SIGUIENDO LOS PUNTOS TRAZADOS EN EL ENTORNO
    {
        // 1 
        Vector3 startPosition = waypoints[currentWaypoint].transform.position;
        Vector3 endPosition = waypoints[currentWaypoint + 1].transform.position;
        // 2 
        float pathLength = Vector3.Distance(startPosition, endPosition);
        float totalTimeForPath = pathLength / speed;
        float currentTimeOnPath = Time.time - lastWaypointSwitchTime;
        gameObject.transform.position = Vector2.Lerp(startPosition, endPosition, currentTimeOnPath / totalTimeForPath);
        // 3 
        if (gameObject.transform.position.Equals(endPosition))
        {
            if (currentWaypoint < waypoints.Length - 2)
            {
                // 3.a 
                currentWaypoint++;
                lastWaypointSwitchTime = Time.time;
                // TODO: Rotate into move direction
            }
            else
            {
                // 3.b 
                Destroy(gameObject); //CUANDO YA LLEGUE AL ÚLTIMO PUNTO DEL RECORRIDO SE DESTRUYE EL ENEMIGO

            }
        }
    }
    public float DistanceToGoal()
    {
        float distance = 0;
        distance += Vector2.Distance(
            gameObject.transform.position,
            waypoints[currentWaypoint + 1].transform.position);
        for (int i = currentWaypoint + 1; i < waypoints.Length - 1; i++)
        {
            Vector3 startPosition = waypoints[i].transform.position;
            Vector3 endPosition = waypoints[i + 1].transform.position;
            distance += Vector2.Distance(startPosition, endPosition);
        }
        return distance;
    }
}
Clase SpawnEnemy

Code: Select all

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

public class SpawnEnemy : MonoBehaviour
{
    public GameObject[] waypoints; //PUNTOS DE RECORRIDO QUE VA A SEGUIR LOS ENEMIGOS PARA LLEGAR A LA BASE
    public GameObject testEnemyPrefwaypoints;

    [System.Serializable]
    public class Wave
    {
        public GameObject enemyPrefab; //TOMA EL PREFAB DEL ENEMIGO QUE SE VA A DESPLAZAR
        public float spawnInterval = 2;
        public int maxEnemies = 20;
    }

    public Wave[] waves; //PREFABS DE LAS OLEADAS, YA QUE CADA OLEADA PUEDE SER UN ENEMIGO DIFERENTE, YA SEA EN ESTÉTICA O EN DAÑO
    public int timeBetweenWaves = 5;

    private GameManagerBehavior gameManager;

    private float lastSpawnTime; //VARIABLE PARA TOMAR EL TIEMPO QUE LE TOMA A LAS OLEADAS APARECER EN EL ENTORNO
    private int enemiesSpawned = 0;


    // Start is called before the first frame update
    void Start()
    {
        lastSpawnTime = Time.time;
        gameManager =
            GameObject.Find("GameManager").GetComponent<GameManagerBehavior>();

    }

    // Update is called once per frame
    void Update() //PROCEDIMIENTO PARA EL DESPLAZAMIENTO DE LOS ENEMIGOS, LA CANTIDAD DE LA OLEADA Y DE A CUANTOS SEGUNDOS APARECERÁ CADA ENEMIGO DE LA OLEADA
    {
        // 1
        int currentWave = gameManager.Wave;
        if (currentWave < waves.Length)
        {
            // 2
            float timeInterval = Time.time - lastSpawnTime;
            float spawnInterval = waves[currentWave].spawnInterval;
            if (((enemiesSpawned == 0 && timeInterval > timeBetweenWaves) ||
                 timeInterval > spawnInterval) &&
                enemiesSpawned < waves[currentWave].maxEnemies)
            {
                // 3  
                lastSpawnTime = Time.time;
                GameObject newEnemy = (GameObject)
                    Instantiate(waves[currentWave].enemyPrefab);
                newEnemy.GetComponent<MoveEnemy>().waypoints = waypoints;
                enemiesSpawned++;
            }
            // 4 
            if (enemiesSpawned == waves[currentWave].maxEnemies &&
                GameObject.FindGameObjectWithTag("Enemy") == null)
            {
                gameManager.Wave++;
                enemiesSpawned = 0;
                lastSpawnTime = Time.time;
            }
            // 5 
        }
        else
        {
            gameManager.gameOver = true; //PROCEDIMIENTO PARA EL "GAME OVER" DEL JUEGO (EN PROCESO...)
            GameObject gameOverText = GameObject.FindGameObjectWithTag("GameWon");
            gameOverText.GetComponent<Animator>().SetBool("gameOver", true);
        }

    }

}

Clase Torre

Code: Select all

public class Torre : MonoBehaviour
{
    public Transform spawnPoin;
    public Transform pointToWalk;
    public GameObject prefAliado;
    public float timeToCreat;
    public float elapsedTimeCreation;
    public bool isReady;

    // Start is called before the first frame update
    void Start()
    {
        isReady = false;
    }

    // Update is called once per frame
    void Update()
    {

        if (elapsedTimeCreation < timeToCreat)
            elapsedTimeCreation += Time.deltaTime;
        else
        {
            isReady = true;
        }


    }

    private void OnMouseDown()
    {
        Debug.Log("Click");

        if (!isReady)
            return;

        CreatAlie();
        elapsedTimeCreation = 0;
        isReady = false;

    }


    public void CreatAlie()
    {
        GameObject tempAlie = Instantiate(prefAliado, spawnPoin.position, spawnPoin.rotation);
        tempAlie.GetComponent<Alies>().NewDestination(spawnPoin.position, pointToWalk.position);

Clase Ubicar Torretas

Code: Select all


public class UbicarTorretas : MonoBehaviour
{

    public GameObject TorretasDefensivasPrefab;
    private GameObject TorretasDefensivas;

    private bool CanPlaceTorretasDefensivas()
    {
        return TorretasDefensivas == null;
    }
    //1
    void OnMouseUp() //PROCESO EN EL QUE SI SE HACE CLICK EN EL BOX COLLIDER QUE POSEE LA "X", APARECERÁ UNA DEFENSA
    {
        //2
        if (CanPlaceTorretasDefensivas())
        {
            //3
            TorretasDefensivas = (GameObject)
              Instantiate(TorretasDefensivasPrefab, transform.position, Quaternion.identity); //MÉTODO PARA QUE APAREZCAN LAS DEFENSAS UNA VEZ SE HACE CLICK SOBRE LAS "X"

        }
    }
}

arquero

Code: Select all

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

public class Arquero : Enemy {
    void Awake()
    {
        CurrentHealth = 50;
        CantidadDaño = 30;
        TiempoEntreDaño = 1;
        Nav.speed = 1.5f;
        ColorLuz.color = Color.green;
        ValorEnemigo = 15;
    }
}
espadachin

Code: Select all

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

public class Espadachin : Enemy {
	void Awake () {
        CurrentHealth = 100;   //vida actual y en este caso inicial  
        CantidadDaño = 20;      //Cuanto daño recibe
        TiempoEntreDaño = 1;    //cada cuanto lo recibe
        Nav.speed = 1f;         //velocidad del enemigo
        ColorLuz.color = Color.blue;     //color caracteristico con el cual alumbra
        ValorEnemigo = 20; //lo que se suma en las monedas
    }
}
golem

Code: Select all

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

public class Golem : Enemy {
    void Awake()
    {
        CurrentHealth = 150;
        CantidadDaño = 20;
        TiempoEntreDaño = 2;
        Nav.speed = 0.5f;
        ColorLuz.color = Color.red;
        ValorEnemigo = 25;
    }
}
Daniela Hernández Chavarro

User avatar
danhercha
Posts: 37
Joined: Wed Jan 30, 2019 3:07 pm
Location: Medellín

Re: Comedores de Mana / HIKARI entertainment

Post by danhercha » Fri May 31, 2019 9:07 pm

ENTREGA FINAL

Poster
Image

Imágenes del Proyecto
Image

Image

Image

Nuevo escenario del juego (Se cambió con el fin de mejorar las dimensiones del juego)
Image

Diagrama del Juego
Image

Ejecutable (Versión Antigua)
---> El ejecutable se llama "Juego DD en la casa"
https://es.padlet.com/dani_hernandez22/7uh1y8xyhh0e

Ejecutable (Versión Mejorada y la que se Presentó el Viernes)
---> El ejecutable se llama "Juego DD en la casa"
https://es.padlet.com/dani_hernandez22/ojx8p57yoocu
Daniela Hernández Chavarro

Post Reply