No tienes acceso a esta clase

¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera

Detectar coincidencias y destruir caramelos

18/31
Recursos

Aportes 15

Preguntas 0

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

Muchachos para los que se sienten un poco confundidos, hay que entender los conceptos y las reglas básicas del juego. Por eso, la etapa del Game Design es muy importante porque es la que nos va a guiar a medida del desarrollo sobre lo que tenemos que hacer o no en código.

  1. Principalmente es entender que jugamos con dos objetos siempre, Caramelo A y Caramelo B. El caramelo A es aquel que tu seleccionas de primero y el caramelo B es aquel con el que vas a hacer el cambio. Conociendo esto, casi toda la lógica se mueve en base a ambos.

  2. El caramelo A lo vas a distinguir porque siempre tiene el color sombreado. Cuando esta sombreado quiere decir que es nuestro PreviousSelected.

  3. Las combinaciones de tres caramelos o más se pueden dar por el Caramelo A o por el Caramelo B, de acuerdo a la dirección en la que se mueva.

  4. Importantísimo repasar el concepto de Estructuras de Datos. En este curso las utilizamos bastante, listas, arrays, etc. Un curso que podría recomendar de platzi para eso y donde se puede practicar bastante, es el curso básico de algoritmos.

  5. Ayudense bastante con las herramientas de debugging. En este caso, es bueno apoyarse de la consola y emplear el método Debug.log().

Aquí les dejo una función que conseguí por internet para imprimir el data de un gameObject en la consola de Unity:

    public static void DumpToConsole(object obj)
    {
        var output = JsonUtility.ToJson(obj, true);
        Debug.Log(output);
    }

Así como esta función hay muchísimas más por internet. Nunca duden en buscar cualquier duda que tengan y documentarse 💚

Para los que esten siguiendo la ruta de hacerlo con animaciones dejo el codigo de mi script de candy con un gif del resultado que obtuve.

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

public class Candy : MonoBehaviour
{
    private static Color selectedColor = new Color(0.5f, 0.5f, 0.5f, 1.0f);
    private static Candy previousSelected = null;

    private SpriteRenderer spriteRenderer;
    private bool isSelected = false;

    public int Id;

    private Vector2[] adjacentDirections = new Vector2[]
    {
        Vector2.down,
        Vector2.left,
        Vector2.up,
        Vector2.right,
    };

    public Vector3 objective;

    GameObject newCandy;

    private void Awake()
    {
        spriteRenderer = GetComponent<SpriteRenderer>();
        objective = Vector3.zero;
    }

    private void OnMouseDown()
    {
        if (spriteRenderer.sprite == null || BoardManager.sharedInstance.isShifting)
        {
            return;
        }

        if (isSelected)
        {
            DeselectCandy();
        }
        else
        {
            if (previousSelected == null)
            {
                SelectCandy();
            }
            else
            {
                if (CanSwipe())
                {
                    SwapSprite(previousSelected.gameObject);
                    previousSelected.Invoke("FindAllMatches", 0.25f);
                    previousSelected.DeselectCandy();
                    Invoke("FindAllMatches", 0.25f);
                }
                else
                {
                    previousSelected.DeselectCandy();
                    SelectCandy();
                }
            }
        }
    }

    private void Update()
    {
        if (objective != Vector3.zero)
        {
            this.transform.position = Vector3.Lerp(this.transform.position, objective, 5 * Time.deltaTime);
        }
    }

    private void SelectCandy()
    {
        isSelected = true;
        spriteRenderer.color = selectedColor;
        previousSelected = gameObject.GetComponent<Candy>();
    }

    private void DeselectCandy()
    {
        isSelected = false;
        spriteRenderer.color = Color.white;
        previousSelected = null;
    }

    public void SwapSprite(GameObject candy)
    {
        if (Id == candy.GetComponent<Candy>().Id)
        {
            return;
        }

        this.objective = candy.transform.position;
        candy.GetComponent<Candy>().objective = this.transform.position;
    }

    private GameObject GetNeighbor(Vector2 direction)
    {
        RaycastHit2D hit = Physics2D.Raycast(this.transform.position, direction);

        if(hit.collider != null)
        {
            return hit.collider.gameObject;
        }
        else
        {
            return null;
        }
    }

    private List<GameObject> GetAllNeighbors()
    {
        List<GameObject> neighbors = new List<GameObject>();

        foreach(Vector2 direction in adjacentDirections)
        {
            neighbors.Add(GetNeighbor(direction));
        }


        return neighbors;
    }

    private bool CanSwipe()
    {
        return GetAllNeighbors().Contains(previousSelected.gameObject);
    }

    //Consulta vecinos en direccion del parametro
    private List<GameObject> FindMatch(Vector2 direction)
    {
        List<GameObject> matchingCandies = new List<GameObject>();
        RaycastHit2D hit = Physics2D.Raycast(this.transform.position, direction);

        int i = 0;

        while (hit.collider != null && hit.collider.gameObject.GetComponent<SpriteRenderer>().sprite == spriteRenderer.sprite)
        {
            matchingCandies.Add(hit.collider.gameObject);
            hit = Physics2D.Raycast(hit.collider.gameObject.transform.position, direction);
        }

        return matchingCandies;
    }

    private bool ClearMatch(Vector2[] directions)
    {
        List<GameObject> matchingCandies = new List<GameObject>();

        foreach (Vector2 direction in directions)
        {
            matchingCandies.AddRange(FindMatch(direction));
        }

        if (matchingCandies.Count >= BoardManager.MinCandiesToMatch)
        {
            foreach (GameObject candy in matchingCandies)
            {
                candy.GetComponent<Animator>().SetBool("Combo", true);
                GetComponent<Animator>().SetBool("Combo", true);
            }

            return true;
        }

        return false;
    }

    public void FindAllMatches()
    {
        if (spriteRenderer.sprite == null)
        {
            return;
        }

        bool hMatch = ClearMatch(new Vector2[2]
        {
            Vector2.left,
            Vector2.right,
        });

        bool vMatch = ClearMatch(new Vector2[2]
        {
            Vector2.up,
            Vector2.down,
        });
    }

    public void DeleteCandy()
    {
        //Debug.Log("hey");
        Destroy(this.gameObject);
    }
}

Creo que estamos llevando muy lejos la “optimizacion” para movil a costa de los efectos graficos del juego, esta bien que no te consuma bateria, pero quitandole todo ese magico de animaciones y efectos de transicion vas a hacer que el usuario se aburra demasiado rapido.

muy complejo el candyCrush pff

if (hMatch || vMatch)
            {
                spriteRenderer.sprite = null;

            }

aki se podría cambiar el sprite por un “poder” como destruir una linea en esa cosa

Tengan cuidado con el codigo que escriban dentro del update del script Candy, tomen en cuenta que hay un monton de Caramelos instanciados, corriendo esa linea tantas veces su pc pueda por segundo y al sobrecargar feo a unity probablemente se les desconfigure algo, en mi caso se me desconfiguro la opcion que desmarcamos en la configuracion de fisicas 2D y estuve 5 horas con el juego crasheado hasta que se me ocurrio revisar eso.

estaba esperando con ansias hacer algo como esto pero como que a medida que pasa el curso se vuelve una tortura 😦

Dando una ojeada, creo que seguiré esta ruta. Great!

Intenté hacer el efecto cascada de los caramelos aplicando físicas (RigidBody a los caramelos y un piso para que no se caigan al vacío) pero me temblaban los caramelos y después se me complicaba el efecto swipe. Vamos a ver en la próxima clase como lo solucionan 🚀🚀

Consideraciones de optimización básicas para juegos en móvile.

en mi caso en lugar de usar:

Sprite hittedSprite = hit.collider.GetComponent<SpriteRenderer>().sprite;
while(hit.collider != null && hittedSprite == spriteBackground.sprite) {
	//logica
}

reviso el id que me parece que es mas preciso:

while(hit.collider != null && hit.collider.GetComponent<Candy>.id== this.id) {
	//logica
}

Alguien le sucede que cuando quieren eliminarlos con otro tipo de dulce no se elimina si no que tienen que hacerlo ustedes?

Les el diagrama de flujo que hice para entender como funciona el método de OnMouseDown().
https://drive.google.com/file/d/1ul6Kt1xAnIq-vj68MLzCmbYho8vD7FWU/view?usp=sharing

Muchos detalles aprendidos.

Les comparto el diagrama de flujo que hice para entender como funciona el algoritmo de selección de caramelos OnMouseDown().
https://drive.google.com/file/d/1ul6Kt1xAnIq-vj68MLzCmbYho8vD7FWU/view?usp=sharing