Neugier Battles - Wintergarnele Studios

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

Moderator: julianmartinez16

Post Reply
User avatar
Gamba04
Posts: 25
Joined: Tue Jan 22, 2019 12:14 pm
Location: Medellín

Neugier Battles - Wintergarnele Studios

Post by Gamba04 » Tue Jan 22, 2019 12:38 pm

Integrantes:

Juan Camilo Quintero

Martin Jaramillo

Link repositorio:
viewtopic.php?f=29&t=1811#top
Last edited by Gamba04 on Sun Feb 03, 2019 11:02 pm, edited 1 time in total.
Juan Camilo Quintero

POO1

User avatar
wintuh
Posts: 33
Joined: Tue Jan 22, 2019 12:13 pm
Location: Medellín

Re: Neugier Battles - Wintergarnele Studios

Post by wintuh » Tue Jan 22, 2019 12:39 pm

Image
Last edited by wintuh on Mon Feb 04, 2019 12:23 am, edited 1 time in total.
Programación y diseño orientado a objetos (pdoo1)

Martín Jaramillo Nicholls

User avatar
wintuh
Posts: 33
Joined: Tue Jan 22, 2019 12:13 pm
Location: Medellín

Re: Neugier Battles - Wintergarnele Studios

Post by wintuh » Tue Jan 29, 2019 11:33 am

Last edited by wintuh on Mon Feb 04, 2019 12:21 am, edited 2 times in total.
Programación y diseño orientado a objetos (pdoo1)

Martín Jaramillo Nicholls

User avatar
wintuh
Posts: 33
Joined: Tue Jan 22, 2019 12:13 pm
Location: Medellín

Re: Neugier Battles - Wintergarnele Studios

Post by wintuh » Mon Feb 04, 2019 12:13 am

Sprint #1

Fecha de inicio: 31/01/2019
Fecha de finalización: 06/02/2019

Actividad #1
Conceptualización de Neugier Battles
  • Desarrolo de la historia (Martín y Juan Camilo) :: 2
  • Diseño de mecánicas (Martín) :: 4
  • Tipos de tropas (Juan Camilo) :: 2
  • Digitalización Concept (Martín) :: 3
Actividad #2
Inicio de programación
  • Movimiento de tropas (Juan Camilo) :: 5
  • Navegación (Juan Camilo y Martín) :: 2
Seguimiento

¿Qué hemos hecho?
  • Se dejó listo los temas relacionados con la empresa Wintergarnele y se llegó a un nombre y concepto definitivo para el juego. Nos pusimos de acuerdo con las mecánicas que se iban a implementar para jugar de a 2 personas, definiendo qué va a ser las funciones para enviar tropas y controlar sus posiciones, a su vez, como las torres se iban a construir. La historia quedó clara y lista para ser trabajada. Se inició también la programación de las mecánicas base, a su vez, planeamos 3 tipos de tropas para implementar.
Image
Image
Image
Image

¿Qué vamos a hacer?
  • Vamos a digitalizar el concept de las tropas y torres base. Vamos a desarrollar más a fondo la navegación y movilidad de las tropas.
Dificultades
  • Al comienzo, tuvimos un conflicto en cuanto la ideación del input de los usuarios ya que queremos hacer un tower defense de 2 jugadores en tiempo real, y no se pueden tener 2 mouse a la vez. Se llegó a la conclusión de que habría que encontrar una manera de controlar un tower defense solo con un teclado.
Programación y diseño orientado a objetos (pdoo1)

Martín Jaramillo Nicholls

User avatar
Gamba04
Posts: 25
Joined: Tue Jan 22, 2019 12:14 pm
Location: Medellín

Re: Neugier Battles - Wintergarnele Studios

Post by Gamba04 » Sun Feb 10, 2019 10:54 pm

Sprint #2

Fecha de inicio: 7/02/2019
Fecha de finalización: 14/02/2019


Actividad #1
Programación: Tropas y torretas
  • Spawning de tropas (Juan Camilo) :: 2
  • Escojer entre tipos de tropas (Juan Camilo) :: 4
  • Colocación torretas en espacios disponibles (Juan Camilo) :: 2
  • Escojer entre tipos de torretas (Juan Camilo) :: 3
  • Programar animaciones de las tropas (Martín) ::
Actividad #2
Apartado Gráfico
  • Animación 1 tropa idle (Martín) :: 2
  • Animación tropa movimiento (Martín) :: 3
  • Slot torreta (Juan Camilo) :: 3
  • Torreta 1 (Martín) :: 4
Juan Camilo Quintero

POO1

User avatar
Gamba04
Posts: 25
Joined: Tue Jan 22, 2019 12:14 pm
Location: Medellín

Re: Neugier Battles - Wintergarnele Studios

Post by Gamba04 » Tue Feb 12, 2019 3:43 pm

Seguimiento

¿Qué hemos hecho?
  • Programación: Se tiene una navegación efectiva que se alterna entre modo torretas, el cual permite navegar entre los slots de las torretas, y tropas, el cual permite instanciar tropas desde la base, navegar entre las diferentes posiciones a las cuales se puede comandar las tropas a que vayan, y consecuentemente comandarlas en cualquier momento a que se dirijan a dicha ubicación.

    Se mejoró el sistema de movilidad de las tropas, el cual funciona organizando a las tropas en diferentes grupos independientes, los cuales controlan la ubicación (que previamente se habia desarrollado con un sistema que transforma un float que alterna entre 0 y 100 a una ubicación correspondiente en la escena, manejando luego dos ubicaciones, una adelante de la otra, para que las tropas se ubiquen en medio de las dos ubicaciones, dándole mayor fluidez al movimiento en las curvas), y las tropas tienen constantemente una fuerza que va hacia la ubicación del grupo en todo momento. Esto le da aún mayor fluidez en especial cuando se realizan cambios de dirección.
    De esta manera, cada que se genera una nueva tropa automáticamente se le agrega un nuevo grupo independiente, y automáticamente comienza a transportarse hacia la dirección indicada (en caso de ser diferente a la base). Cuando se detecta que dos grupos están en una ubicación muy cercana (menor a 1 unidad del float de la ubicación) y la suma de las tropas no es mayor a 20, los grupos se fusionan, eliminando un grupo y readoptando el grupo sobrante a las nuevas tropas. Esto previene que se formen grupos sobrecargados de tropas, para que en caso de que hayan muchas tropas, lo que pasa es que no se elimina el grupo llegante, sino que este se pone en "cadena", manteniéndose 1.5 unidades del float de la ubicación más atrás que el grupo de adelante. De esta manera se puede tener un ejercito muy grande sin salirse del camino, haciendo fila y conservando un movimiento fluido a lo largo del recorrido(hacia atrás y hacia adelante). Finalmente se le agregaron colliders en todos los bordes del camino, para que cuando se forman grupos grandes las tropas no se salgan del camino, y también hay un debug adicional en caso de que una tropa quede atrapada lejos del grupo se teletransporta al centro del grupo.

    Junto con esto se realizaron procesos de optimización transladando funciones que podian no estar en el script del grupo, que se va a repetir entre más de estos objetos hayan, a otro script que no se va a replicar, llamado ControlGeneral, al igual que con el script de cada tropa, para dejar estos objetos con la menor cantidad de código para que pueda funcionar, y solucionando los problemas de rendimiento que se generaban al instanciar muchas tropas.
¿Qué vamos a hacer?
  • Para el jueves se planea terminar la programación del instanciamiento de torretas en los slots, reconociendo cuando se ocupa un espacio y sólo permitiendo colocar torretas en los espacios disponibles. Se terminará también de programar todas las mecánicas básicas, incluyendo seleccionar el tipo de tropas a crear y el tipo de torretas a construir. Aparte de esto, se espera terminar las actividades del apartado gráfico.

    Para futuros sprints se adaptará el sistema de una tropa constructora que se instancie como un tipo de tropa (con un límite de 3 de estas tropas vivas al tiempo, las cuales pueden morir como las demás tropas)y que este encargada de ir hacia las torretas para contruir, mejorar, eliminar o reparar la torreta, y futuras funciones, antes de adaptarle el sistema de recursos(dinero) y el segundo jugador(con las funciones de daño entre las tropas), y futuramente mejoras de nivel de las torretas y demás.
Dificultades
  • Un gran reto que hubo en este sprint fue lograr optimizar efectivamente los scripts de las tropas y los grupos que las controlan. Y además, reestructurar los scripts para que hayan varios grupos independientes, los cuales se fusionen en caso de haber pocas tropas y organizarse en cadena en caso de haber muchas tropas.


Códigos:

Tropa.cs

Code: Select all

public class Tropa : MonoBehaviour {

    public float dist;
    public int mascercano;
    public GameObject grupo;

	void Start () {
        //adoptamiento de grupo
        dist = Mathf.Abs((transform.position - FindObjectsOfType<Translacion>()[0].transform.position).magnitude);
        for (int i = 0; i < FindObjectsOfType<Translacion>().Length; i++)
        {
            if (Mathf.Abs((transform.position - FindObjectsOfType<Translacion>()[i].transform.position).magnitude) < dist)
            {
                dist = Mathf.Abs((transform.position - FindObjectsOfType<Translacion>()[i].transform.position).magnitude);
                mascercano = i;
            }
        }
        grupo = FindObjectsOfType<Translacion>()[mascercano].gameObject;
    }
	
	void Update () {
        //readopatmiento de grupo en caso de que se elimine
        if (grupo == null)
        {
            mascercano = 0;
            dist = Mathf.Abs((transform.position - FindObjectsOfType<Translacion>()[0].transform.position).magnitude);
            for (int i = 0; i < FindObjectsOfType<Translacion>().Length; i++)
            {
                if (Mathf.Abs((transform.position - FindObjectsOfType<Translacion>()[i].transform.position).magnitude) < dist)
                {
                    dist = Mathf.Abs((transform.position - FindObjectsOfType<Translacion>()[i].transform.position).magnitude);
                    mascercano = i;
                }
            }
            grupo = FindObjectsOfType<Translacion>()[mascercano].gameObject;
        }
        //atraccion al grupo
        GetComponent<Rigidbody2D>().AddForce((grupo.transform.position - transform.position) * 20 * Random.Range(0, 20));

    }
}
Translacion.cs

Code: Select all

public class Translacion : MonoBehaviour {


    public GameObject[] nodos;
    public float ubicacionfrontal;
    public float ubicaciontrasera;
    public float separacion;
    public Vector3 frente;
    public Vector3 atras;

    public int nodoactivo;
    public float magnitudactual;
    public float diferenciaubicaciones;



    void Start () {

        diferenciaubicaciones = 5;
        ubicacionfrontal = 0;

    }

    void Update() {
        //información de ControlGeneral
        nodos = FindObjectOfType<ControlGeneral>().nodos;
        nodoactivo = FindObjectOfType<ControlGeneral>().nodoactivo;
        
        //float ubicación --> posición real
        for (int i = 0; i < nodos.Length - 1; i++)
        {

            if (ubicacionfrontal >= i * 100f / (nodos.Length - 1) && ubicacionfrontal <= (i + 1) * 100f / (nodos.Length - 1))
            {
                frente = nodos[i].transform.position + (nodos[i + 1].transform.position - nodos[i].transform.position) * ((ubicacionfrontal - i * 100f / (nodos.Length - 1)) / (100f / (nodos.Length - 1)));
                magnitudactual = (nodos[i + 1].transform.position - nodos[i].transform.position).magnitude;
            }

            if (ubicaciontrasera >= i * 100f / (nodos.Length - 1) && ubicaciontrasera <= (i + 1) * 100f / (nodos.Length - 1))
            {
                atras = nodos[i].transform.position + (nodos[i + 1].transform.position - nodos[i].transform.position) * ((ubicaciontrasera - i * 100f / (nodos.Length - 1)) / (100f / (nodos.Length - 1)));

            }

        }

        //voy a hacerme las pastas, anda viendo el codigo <<<<<
        
        //movimiento hacia nodoactivo
            if (ubicacionfrontal < nodoactivo * 100 / (nodos.Length - 1) + 2.5f) ubicacionfrontal += 0.05f * separacion / magnitudactual;
        if (ubicacionfrontal > nodoactivo * 100 / (nodos.Length - 1) + 2.5f) ubicacionfrontal -= 0.05f * separacion / magnitudactual;

        //limites de ubicacion frontal
        if (ubicacionfrontal < 0) ubicacionfrontal = 0;
        if (ubicacionfrontal > 100) ubicacionfrontal = 100;

        //separacion ubicaciones
        diferenciaubicaciones += (5 / magnitudactual - diferenciaubicaciones) * 0.01f;
        ubicaciontrasera = ubicacionfrontal - diferenciaubicaciones;

        //limite ubicacion trasera
        if (ubicaciontrasera < 0) ubicaciontrasera = 0;

        //posicion grupo
        transform.position = atras + (frente - atras) * 0.5f;


        Debug.DrawRay(atras, frente - atras, Color.white);

        //fusion grupos
        for (int i = 0; i < FindObjectsOfType<Translacion>().Length; i++)
        {
            if (this == FindObjectsOfType<Translacion>()[i])
            {
                for (int o = 0; o < FindObjectsOfType<Translacion>().Length; o++)
                {
                    if (Mathf.Abs(this.ubicacionfrontal - FindObjectsOfType<Translacion>()[o].ubicacionfrontal) < 1 && i < o)
                    {
                        Destroy(FindObjectsOfType<Translacion>()[i].gameObject);
                    }

                }
            }

        }
    }
}
ControlGeneral.cs

Code: Select all

public class ControlGeneral : MonoBehaviour {

    public GameObject grupo;
    public GameObject tropa;
    public bool modotropas;
    public int seleccionnodo;
    public int nodoactivo;
    public GameObject[] espaciostorretas;
    public int seleccionespacio;
    public int espacioarriba;
    public int espacioabajo;
    public int espacioderecha;
    public int espacioizquierda;
    public GameObject[] nodos;

    void Start () {
        modotropas = true;
        espaciostorretas = GameObject.FindGameObjectsWithTag("Turret Slot");
        //organizacion del array de nodos
        GameObject[] nodosorigen;
        nodosorigen = GameObject.FindGameObjectsWithTag("Path");
        nodos = new GameObject[nodosorigen.Length];

        for (int i = 0; i < nodosorigen.Length; i++)
        {
            nodos[int.Parse(nodosorigen[i].name)] = nodosorigen[i];
        }
    }
	
	void Update () {

        grupo = FindObjectsOfType<Translacion>()[0].gameObject;
        //spawn tropas
        if (Input.GetKeyDown(KeyCode.X))
        {
            Instantiate(grupo, transform.position, transform.rotation);
            Instantiate(tropa, transform.position, transform.rotation);

        }

        //viesualización del nodo seleccionado
        for (int i = 0; i < nodos.Length; i++)
        {

            if (i == seleccionnodo && modotropas) nodos[i].GetComponent<SpriteRenderer>().enabled = true;
            else nodos[i].GetComponent<SpriteRenderer>().enabled = false;
        }
        //alternar modo
        if (Input.GetKeyDown(KeyCode.G)) modotropas = !modotropas;

        //navegación nodo
        if (modotropas)
        {
            if (Input.GetKeyDown(KeyCode.D)) seleccionnodo++;
            if (Input.GetKeyDown(KeyCode.A)) seleccionnodo--;

            if (Input.GetKeyDown(KeyCode.F)) nodoactivo = seleccionnodo;
        }
        else
        {
            //navegación torretas
            for (int i = 0; i < espaciostorretas.Length; i++)
            {
                if (espaciostorretas[i].transform.position.y > espaciostorretas[seleccionespacio].transform.position.y + 1 && ((espaciostorretas[i].transform.position - espaciostorretas[seleccionespacio].transform.position).magnitude < (espaciostorretas[espacioarriba].transform.position - espaciostorretas[seleccionespacio].transform.position).magnitude || espaciostorretas[espacioarriba].transform.position.y <= espaciostorretas[seleccionespacio].transform.position.y + 1))
                {
                    espacioarriba = i;
                }
                if (espaciostorretas[i].transform.position.y < espaciostorretas[seleccionespacio].transform.position.y - 1 && ((espaciostorretas[i].transform.position - espaciostorretas[seleccionespacio].transform.position).magnitude < (espaciostorretas[espacioabajo].transform.position - espaciostorretas[seleccionespacio].transform.position).magnitude || espaciostorretas[espacioabajo].transform.position.y >= espaciostorretas[seleccionespacio].transform.position.y - 1))
                {
                    espacioabajo = i;
                }
                if (espaciostorretas[i].transform.position.x > espaciostorretas[seleccionespacio].transform.position.x + 1 && ((espaciostorretas[i].transform.position - espaciostorretas[seleccionespacio].transform.position).magnitude < (espaciostorretas[espacioderecha].transform.position - espaciostorretas[seleccionespacio].transform.position).magnitude || espaciostorretas[espacioderecha].transform.position.x <= espaciostorretas[seleccionespacio].transform.position.x + 1))
                {
                    espacioderecha = i;
                }
                if (espaciostorretas[i].transform.position.x < espaciostorretas[seleccionespacio].transform.position.x - 1 && ((espaciostorretas[i].transform.position - espaciostorretas[seleccionespacio].transform.position).magnitude < (espaciostorretas[espacioizquierda].transform.position - espaciostorretas[seleccionespacio].transform.position).magnitude || espaciostorretas[espacioizquierda].transform.position.x >= espaciostorretas[seleccionespacio].transform.position.x - 1))
                {
                    espacioizquierda = i;
                }

            }
            if (espaciostorretas[espacioarriba].transform.position.y <= espaciostorretas[seleccionespacio].transform.position.y + 1) espacioarriba = seleccionespacio;
            if (espaciostorretas[espacioabajo].transform.position.y >= espaciostorretas[seleccionespacio].transform.position.y - 1) espacioabajo = seleccionespacio;
            if (espaciostorretas[espacioderecha].transform.position.x <= espaciostorretas[seleccionespacio].transform.position.x + 1) espacioderecha = seleccionespacio;
            if (espaciostorretas[espacioizquierda].transform.position.x >= espaciostorretas[seleccionespacio].transform.position.x - 1) espacioizquierda = seleccionespacio;

            if (Input.GetKeyDown(KeyCode.W)) seleccionespacio = espacioarriba;
            if (Input.GetKeyDown(KeyCode.A)) seleccionespacio = espacioizquierda;
            if (Input.GetKeyDown(KeyCode.S)) seleccionespacio = espacioabajo;
            if (Input.GetKeyDown(KeyCode.D)) seleccionespacio = espacioderecha;

        }
        //visualizacion de slot seleccionado
        for (int i = 0; i < espaciostorretas.Length; i++)
        {
            if (i == seleccionespacio && !modotropas) espaciostorretas[i].GetComponent<SpriteRenderer>().enabled = true;
            else espaciostorretas[i].GetComponent<SpriteRenderer>().enabled = false;
        }
        //limites seleccion nodos
        if (seleccionnodo < 0) seleccionnodo = 0;
        if (seleccionnodo > nodos.Length - 1) seleccionnodo = nodos.Length - 1;
    }
}
Juan Camilo Quintero

POO1

User avatar
wintuh
Posts: 33
Joined: Tue Jan 22, 2019 12:13 pm
Location: Medellín

Re: Neugier Battles - Wintergarnele Studios

Post by wintuh » Thu Feb 14, 2019 11:02 pm

Evidencias de animación

  • Torre cañón
Image
  • Idle
Image
Programación y diseño orientado a objetos (pdoo1)

Martín Jaramillo Nicholls

User avatar
wintuh
Posts: 33
Joined: Tue Jan 22, 2019 12:13 pm
Location: Medellín

Re: Neugier Battles - Wintergarnele Studios

Post by wintuh » Fri Feb 15, 2019 8:12 pm

Evidencia en video

Programación y diseño orientado a objetos (pdoo1)

Martín Jaramillo Nicholls

User avatar
wintuh
Posts: 33
Joined: Tue Jan 22, 2019 12:13 pm
Location: Medellín

Re: Neugier Battles - Wintergarnele Studios

Post by wintuh » Sun Feb 17, 2019 5:09 pm

Sprint #3

Fecha inicio: 14/03/2019
Fecha de finalización: 21/03/2019

Actividad #1
Animación y diseño de personajes y hud
  • Animaciones básicas del constructor (Martín) :: 3
  • Terreno base del mapa (Martín) :: 3
  • Elementos para seleccionar donde se pondrán las torres y los amiguitos (hud) (Martín) :: 4
  • Diseñar elementos para el constructor (Juan Camilo) :: 2.0f
  • Info de tropas y torretas (Juan Camilo) :: 2
Actividad #2
Programación: segundo jugador y tropas
  • Adaptar al segundo jugador con otras teclas (Juan Camilo) :: 2
  • Programar ataque de las tropas (Juan Camilo) :: 4
  • Programar desplazamiento y colocamiento de torretas del constructor (Juan Camilo) :: 3
  • Adaptar al constructor como otra tropa y que sea máximo 3 (Juan Camilo) :: 2
  • Control independiente de los constructores (Martín) :: 2
  • Dar habilidades específicas a las tropas (Juan Camilo) :: 4
Programación y diseño orientado a objetos (pdoo1)

Martín Jaramillo Nicholls

User avatar
wintuh
Posts: 33
Joined: Tue Jan 22, 2019 12:13 pm
Location: Medellín

Re: Neugier Battles - Wintergarnele Studios

Post by wintuh » Tue Feb 19, 2019 11:04 pm

Evidencias del sprint #3 animación

Así se verá el constructor en juego

Image
Image
Image
Image
Image

Image
Programación y diseño orientado a objetos (pdoo1)

Martín Jaramillo Nicholls

Post Reply