No tienes acceso a esta clase

隆Contin煤a aprendiendo! 脷nete y comienza a potenciar tu carrera

Bajar caramelos en cascada cuando un grupo es eliminado

19/31
Recursos

Vamos a programar la funcionalidad de hacer caer caramelos cuando otro grupo de 3 o m谩s caramelos ha sido eliminado.

Debemos consultar todos los elementos vac铆os de la grilla y cambiar su posici贸n para rellenar el espacio vac铆o. As铆, vamos a rellenar todos los espacios de la zona de abajo de nuestra grilla de caramelos.

Para esto, vamos a crear un m茅todo llamado FindNullCandies que debe detectar los caramelos con la propiedad spriteRenderer igual a null y llamar a todos los vecinos hac铆a arriba y cambiar su posici贸n para completar los campos vac铆os de abajo. Obviamente, solo logramos que los espacios vac铆os pasen a las posiciones de arriba de la grilla pero, no te preocupes que, en la pr贸xima clase, vamos a generar nuevos caramelos para completar estos nuevos espacios.

Aportes 12

Preguntas 2

Ordenar por:

Los aportes, preguntas y respuestas son vitales para aprender en comunidad. Reg铆strate o inicia sesi贸n para participar.

脷ltimamente se complico mucho mas el c贸digo

Hay algo en el c贸digo de esta clase que me crashea el unity .
Ejecuta bien y me deja seleccionar el dulce pero cuando lo muevo a otra posici贸n en la que se juntan 3 del mismo dulce crashea (que es donde deber铆an caer en cascada)

Borre el c贸digo de abajo y ya me dejo de crashear pero no hace lo que debe (es basicamente el codigo que se lleva hasta la clase pasada)

public IEnumerator FindNullCandies()
    {
        for(int x = 0; x < xSize; xSize++){
            for(int y = 0; y < ySize; ySize++)
            {
                if(candies[x,y].GetComponent<SpriteRenderer>().sprite == null)
                {
                    yield return StartCoroutine(MakeCandiesFall(x, y));
                    break;
                }
            }
        }
    }

    private IEnumerator MakeCandiesFall(int x, int yStart, float shiftDelay= 0.0f) //el float es opcional porque esta inicializado automaticamente en el metodo
    {
        isShifting = true;

        List<SpriteRenderer> renders = new List<SpriteRenderer>();
        int nullCandies = 0;

        for(int y = yStart; y< ySize; y++)
        {
            SpriteRenderer spriteRenderer = candies[x, y].GetComponent<SpriteRenderer>();
            if(spriteRenderer.sprite == null)
            {
                nullCandies++;
            }
            renders.Add(spriteRenderer);
        }

        for(int i = 0; i< nullCandies; i++)
        {
            yield return new WaitForSeconds(shiftDelay);
            for (int j = 0; j <renders.Count-1; j++)
            {
                renders[j].sprite = renders[j + 1].sprite;
                renders[j + 1].sprite = GetNewCandies(x,ySize-1); 
            }
        }

        isShifting = false;

    }
    
    private Sprite GetNewCandies(int x, int y)
    {
        List<Sprite> possibleCandies = new List<Sprite>();
        possibleCandies.AddRange(prefabs);

        if (x > 0)
        {
            possibleCandies.Remove(candies[x - 1, y].GetComponent<SpriteRenderer>().sprite);
        }
            if(x<xSize - 1)
            {
                possibleCandies.Remove(candies[x + 1, y].GetComponent<SpriteRenderer>().sprite);
            }
            if(y > 0)
            {
                possibleCandies.Remove(candies[x, y - 1].GetComponent<SpriteRenderer>().sprite);
            }

            return possibleCandies[Random.Range(0, possibleCandies.Count)];
        
    }*/```

Hola!

Tengo un bug curioso, en algunas combinaciones al bajar los sprites estos desaparecen o se 鈥渉unden鈥

En el GIF en la segunda y tercera animaci贸n se ve perfecto:

Mire el c贸digo del repositorio y el del v铆deo

https://github.com/celismx/unityMovilesCurso/tree/master/Assets/Scripts

Mi c贸digo (lo a帽adido esta lecci贸n)

BoardManager

public IEnumerator FindNullCandies()
    {
        for (int x = 0; x < xSize; x++)
        {
            for (int y = 0; y < ySize; y++)
            {
                if (candies[x, y].GetComponent<SpriteRenderer>().sprite == null)
                {
                    yield return StartCoroutine(MakeCandiesFall(x, y));
                    break;
                }
            }
        }
    }

    private IEnumerator MakeCandiesFall(int x, int yStart, float shiftDelay=0.05f)
    {
        isShifting = true;

        List<SpriteRenderer> renderers = new List<SpriteRenderer>();
        int nullCandies = 0;
        for (int y = yStart; y < ySize; y++)
        {
            SpriteRenderer spriteRenderer = candies[x, y].GetComponent<SpriteRenderer>();
            if (spriteRenderer.sprite == null)
            {
                nullCandies++;
            }
            renderers.Add(spriteRenderer);
        }

        for (int i = 0; i < nullCandies; i++)
        {
            yield return new WaitForSeconds(shiftDelay);
            for (int j = 0; j < renderers.Count-1; j++)
            {
                renderers[j].sprite = renderers[j + 1].sprite;
                renderers[j + 1].sprite = null;
            }
        }

        isShifting = false;
    }

Candy

 private void OnMouseDown()
    {
        if (spriteRenderer.sprite == null ||
            BoardManager.sharedInstance.isShifting)
        {
            return;
        }
        if (isSelected)
        {
            DeselectCandy();
        }
        else
        {
            if (previousSelected == null)
            {
                SelectCandy();
            }
            else
            {
                if (CanSwipe())
                {
                    SwapSprites(previousSelected);
                    previousSelected.FindAllMatches(); //En caso de que lo elegido antes logre una combinacion
                    previousSelected.DeselectCandy();
                    FindAllMatches(); //En caso de que el elegido ahora sea el que hace la combinacion

                    StopCoroutine(BoardManager.sharedInstance.FindNullCandies());
                    StartCoroutine(BoardManager.sharedInstance.FindNullCandies());
                }
                else
                {
                    previousSelected.DeselectCandy();
                    SelectCandy();
                }
            }
        }
    }

驴Qu茅 puede estar pasando?

EXELENTE

Genial

Hola!! Ricardo Celis, igualmente se complica demasiado el c贸digo me eh visto 2 veces el curso de c# para v铆deojuegos y hasta ah铆 est谩 todo muy bien, hasta que llegamos a este punto (El curso de desarrollo de v铆deojuegos para m贸viles con unity) se complica ya que no se explica muy bien algunas cosas.. que tampoco se explicaron el el curso de c# para v铆deojuegos... Y con esto no digo que el profesor sea malo explicando por qu茅 para m铆 es el mejor profesor que puede haber... Ojal谩 se haga un curso con este profesor (si es que se puede) explicando cosas que no se explicaron en el curso de C# para videojuegos... Gracias!!

Hola鈥

Me sucede algo curioso y que no he visto soluci贸n en los comentarios, lo que sucede es que al hacer el match los caramelos no bajan, y al hacer otro match los caramelos del primer match bajan, pero con unas f铆sicas demasiado raras y los del segundo se quedan est谩ticos. Adjunto mis dos scripts.

CandyController (mi equivalente al script Candy)

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

public class CandyController : MonoBehaviour
{
    private static Color selectedColor = new Color(0.5f, 0.5f, 0.5f, 1.0f);
    private static CandyController 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 || GridManager.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);

                    StopCoroutine(GridManager.sharedInstance.FindNullCandies());
                    StartCoroutine(GridManager.sharedInstance.FindNullCandies());  
                }
                else
                {
                    previousSelected.DeselectCandy();
                    SelectCandy();
                }
            }
        }
    }

    private void Update()
    {
        //Invoke("FindAllMatches", 1f);

        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<CandyController>();
    }

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

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

        this.objective = candy.transform.position;
        candy.GetComponent<CandyController>().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);

        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 >= GridManager.MinCandiesToMatch)
        {
            foreach (GameObject candy in matchingCandies)
            {
                candy.GetComponent<SpriteRenderer>().sprite = null;
                spriteRenderer.sprite = null;
            }

            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);
    }

}

y el script GridManager (el equivalente al script BoardManager)

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

public class GridManager : MonoBehaviour
{
    public static GridManager sharedInstance;
    public List<GameObject> prefabs = new List<GameObject>();
    public GameObject currentCandy;
    public int xSize, ySize;
    public float paddingX, paddingY;
    private CandyController selecctedCandy;

    public const int MinCandiesToMatch = 2;

    private GameObject[,] candies;

    public bool isShifting {get; set;}

    void Start()
    {
        if(sharedInstance == null)
        {
            sharedInstance = this;
        }
        else
        {
            Destroy(gameObject);
        }

        Vector2 offset = new Vector2(currentCandy.GetComponent<BoxCollider2D>().size.x + paddingX, currentCandy.GetComponent<BoxCollider2D>().size.y + paddingY);
        CreateInitialBoard(offset);
    }

    private void CreateInitialBoard(Vector2 offset)
    {
        candies = new GameObject[xSize, ySize];

        float startX = this.transform.position.x;
        float startY = this.transform.position.y;

        int idx = -1;

        for(int x = 0; x < xSize; x++)
        {
            for(int y = 0; y < ySize; y++)
            {
                GameObject newCandy = Instantiate(currentCandy, new Vector3(startX + (offset.x * x), startY + (offset.y * y),0f), currentCandy.transform.rotation);
                newCandy.name = string.Format("Candy[{0}][{1}]", x, y);

                do 
                {
                    
                    idx = Random.Range(0, prefabs.Count);

                }while((x > 0 && idx == candies[x - 1, y].GetComponent<CandyController>().Id) ||
                        (y > 0 && idx == candies[x, y - 1].GetComponent<CandyController>().Id));

                GameObject candySprite = prefabs[Random.Range(0,prefabs.Count)];
                newCandy.GetComponent<SpriteRenderer>().sprite = candySprite.GetComponent<SpriteRenderer>().sprite;
                newCandy.GetComponent<CandyController>().Id = idx;

                newCandy.transform.parent = this.transform;
                candies[x, y] = newCandy;
            }
        }
    }

    public IEnumerator FindNullCandies()
    {
        for(int x = 0; x < xSize; x++)
        {
            for(int y = 0; y < ySize; y++)
            {
                if(candies[x,y].GetComponent<SpriteRenderer>().sprite == null)
                {
                    yield return StartCoroutine(MakeCandiesFall(x,y));
                    break;
                }
            }
        }
    }

    private IEnumerator MakeCandiesFall(int x, int yStart, float shiftDelay = 0.05f)
    {
        isShifting = true;

        List <SpriteRenderer> renderes = new List<SpriteRenderer>();
        int nullCandies = 0;

        for(int y = yStart; y < ySize; y++)
        {
            SpriteRenderer spriteRe = candies[x,y].GetComponent<SpriteRenderer>();
            if(spriteRe.sprite == null)
            {
                nullCandies++;
            }
            renderes.Add(spriteRe);
        }

        for(int i = 0; i < nullCandies; i++)
        {
            yield return new WaitForSeconds(shiftDelay);
            for(int j = 0; j < renderes.Count - 1; j++)
            {
                Debug.Log("Puede Caer");
                renderes[j].sprite = renderes[j + 1].sprite;
                renderes[j + 1].sprite = null;
            }
        }

        isShifting = false;
    }

    private GameObject GetNewCandies(int x, int y)
    {
        List <GameObject> possibleCandies = new List<GameObject>();
        possibleCandies.AddRange(prefabs);
    }

}

Para renombrar una variable globalmente pueden hacer click sobre el nombre de la variable y Ctrl + R (2 veces)

He notado que el segundo ciclo de la funci贸n MakeCandiesFall tiene un bucle de m谩s, ya que al siguiente c贸digo

for (int i = 0; i < nullCandies; i++)
        {
            yield return new WaitForSeconds(shiftDelay);
            for(int j = 0; j < renderers.Count-1; j++)
            {
                renderers[j].sprite = renderers[j+1].sprite;
                renderers[j+1].sprite = null;
            }
        }

se le puede quitar el primer bucle sin afectar su funcionalidad, as铆:

yield return new WaitForSeconds(shiftDelay);
for(int j = 0; j < renderers.Count-1; j++)
{
renderers[j].sprite = renderers[j+1].sprite;
renderers[j+1].sprite = null;
}

Por favor corriganme si estoy equivocado.

Detalle importante!!!
Si alguno de ustedes en el swipe candy, est谩 comparando con el id (as铆 como es mi caso), deben de igual forma pasar el id una casilla + , al momento de que los caramelos caigan en cascada. Ya que si no lo hacen, quedar谩n con el id equivocado. Igual si solo verifican por el sprite ser铆a lo mas recomendable hacerlo para evitar futuros problemas con el ID.

Deber铆a ser as铆:

 for (int i = 0; i < nullCandies; i++){
            yield return new WaitForSeconds(shiftDelay);
            for (int j = 0; j < renderes.Count - 1; j++)
            {
                renderes[j].sprite = renderes[j+1].sprite;
                renderes[j+1].sprite = null;

                candiesToFall[j].GetComponent<Candy>().id = renderes[j+1].GetComponent<Candy>().id;
                candiesToFall[j+1].GetComponent<Candy>().id = 0;
            }
        }

Hola compa帽eros, no se si les ocurri贸 lo mismo alguna vez.

Cuando estaba llamando el m茅todo FindNullCandies()me daba el siguiente error:

Estuve revisando y encontr茅 lo siguiente:

GameObject[,] candies = new GameObject[xSize, ySize];

Si pueden ver estaba RE DECLARANDO candies 馃憖. Tengan cuidado para que no les pase lo mismo.

Hola, siguiendo todos los pasos me funciona bien la primera vez, luego no hace nada, he revisado el c贸digo y parece que esta todo igual. Como puedo depurar o ver si hay alg煤n mensaje de error? Gracias.