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.
publicIEnumeratorFindNullCandies(){for(int x =0; x < xSize; x++){for(int y =0; y < ySize; y++){if(candies[x, y].GetComponent<SpriteRenderer>().sprite==null){yieldreturnStartCoroutine(MakeCandiesFall(x, y));break;}}}}privateIEnumeratorMakeCandiesFall(int x, int yStart, float shiftDelay=0.05f){ isShifting =true;List<SpriteRenderer> renderers =newList<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++){yieldreturnnewWaitForSeconds(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
privatevoidOnMouseDown(){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 combinacionStopCoroutine(BoardManager.sharedInstance.FindNullCandies());StartCoroutine(BoardManager.sharedInstance.FindNullCandies());}else{ previousSelected.DeselectCandy();SelectCandy();}}}}
¿Qué puede estar pasando?
No sé si te diste cuenta pero a el le ocurre lo mismo
pudiste solucionarlo?
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!!
Te recomiendo tener el código del profesor abierto al lado del tuyo e ir comentando cada línea con todo lo que dice el profe, avanzaras más lento, pero entenderás cada cosa.
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)
publicIEnumeratorFindNullCandies(){for(int x =0; x < xSize; xSize++){for(int y =0; y < ySize; ySize++){if(candies[x,y].GetComponent<SpriteRenderer>().sprite==null){yieldreturnStartCoroutine(MakeCandiesFall(x, y));break;}}}}privateIEnumeratorMakeCandiesFall(int x, int yStart, float shiftDelay=0.0f)//el float es opcional porque esta inicializado automaticamente en el metodo{ isShifting =true;List<SpriteRenderer> renders =newList<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++){yieldreturnnewWaitForSeconds(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;}privateSpriteGetNewCandies(int x, int y){List<Sprite> possibleCandies =newList<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)];}*/```
Ya vi porque, en FindNullCandies los primeros for los tenia asi:
for(int x =0; x < xSize; xSize++){for(int y =0; y < ySize; ySize++)```
y es asi:
for(int x = 0; x < xSize; x++){
for(int y = 0; y < ySize; y++)```
yo supongo que crasheaba porque el for se volvía infinito en la primera manera
EXELENTE
Genial
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;publicclassCandyController:MonoBehaviour{privatestaticColor selectedColor =newColor(0.5f,0.5f,0.5f,1.0f);privatestaticCandyController previousSelected =null;privateSpriteRenderer spriteRenderer;private bool isSelected =false;public int Id;privateVector2[] adjacentDirections =newVector2[]{Vector2.down,Vector2.left,Vector2.up,Vector2.right,};publicVector3 objective;GameObject newCandy;privatevoidAwake(){ spriteRenderer =GetComponent<SpriteRenderer>(); objective =Vector3.zero;}privatevoidOnMouseDown(){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();}}}}privatevoidUpdate(){//Invoke("FindAllMatches", 1f);if(objective !=Vector3.zero){this.transform.position=Vector3.Lerp(this.transform.position, objective,5*Time.deltaTime);}}privatevoidSelectCandy(){ isSelected =true; spriteRenderer.color= selectedColor; previousSelected = gameObject.GetComponent<CandyController>();}privatevoidDeselectCandy(){ isSelected =false; spriteRenderer.color=Color.white; previousSelected =null;}publicvoidSwapSprite(GameObject candy){if(Id== candy.GetComponent<CandyController>().Id){return;}this.objective= candy.transform.position; candy.GetComponent<CandyController>().objective=this.transform.position;}privateGameObjectGetNeighbor(Vector2 direction){RaycastHit2D hit =Physics2D.Raycast(this.transform.position, direction);if(hit.collider!=null){return hit.collider.gameObject;}else{returnnull;}}privateList<GameObject>GetAllNeighbors(){List<GameObject> neighbors =newList<GameObject>();foreach(Vector2 direction in adjacentDirections){ neighbors.Add(GetNeighbor(direction));}return neighbors;}private bool CanSwipe(){returnGetAllNeighbors().Contains(previousSelected.gameObject);}//Consulta vecinos en direccion del parametroprivateList<GameObject>FindMatch(Vector2 direction){List<GameObject> matchingCandies =newList<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 =newList<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;}returntrue;}returnfalse;}publicvoidFindAllMatches(){if(spriteRenderer.sprite==null){return;} bool hMatch =ClearMatch(newVector2[2]{Vector2.left,Vector2.right,}); bool vMatch =ClearMatch(newVector2[2]{Vector2.up,Vector2.down,});}publicvoidDeleteCandy(){//Debug.Log("hey");Destroy(this.gameObject);}}
y el script GridManager (el equivalente al script BoardManager)
using System.Collections;using System.Collections.Generic;using UnityEngine;publicclassGridManager:MonoBehaviour{publicstaticGridManager sharedInstance;publicList<GameObject> prefabs =newList<GameObject>();publicGameObject currentCandy;public int xSize, ySize;public float paddingX, paddingY;privateCandyController selecctedCandy;publicconst int MinCandiesToMatch=2;privateGameObject[,] candies;public bool isShifting {get; set;}voidStart(){if(sharedInstance ==null){ sharedInstance =this;}else{Destroy(gameObject);}Vector2 offset =newVector2(currentCandy.GetComponent<BoxCollider2D>().size.x+ paddingX, currentCandy.GetComponent<BoxCollider2D>().size.y+ paddingY);CreateInitialBoard(offset);}privatevoidCreateInitialBoard(Vector2 offset){ candies =newGameObject[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,newVector3(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;}}}publicIEnumeratorFindNullCandies(){for(int x =0; x < xSize; x++){for(int y =0; y < ySize; y++){if(candies[x,y].GetComponent<SpriteRenderer>().sprite==null){yieldreturnStartCoroutine(MakeCandiesFall(x,y));break;}}}}privateIEnumeratorMakeCandiesFall(int x, int yStart, float shiftDelay =0.05f){ isShifting =true;List<SpriteRenderer> renderes =newList<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++){yieldreturnnewWaitForSeconds(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;}privateGameObjectGetNewCandies(int x, int y){List<GameObject> possibleCandies =newList<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++){yieldreturnnewWaitForSeconds(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í:
Si afecta la funcionalidad, cuando caen coinciden en vertical no cae, yo entiendo que se debe a que al faltarle un for , no recorre la matriz en ese sentido
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++){yieldreturnnewWaitForSeconds(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:
Si pueden ver estaba RE DECLARANDO candies :eyes:. 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.
No se muy bien a que te refieres, pero creo que deberías asegurarte de que el método MakeCandiesFall() termine con la línea de código isShifting = false; , ya que si no la pones en falso no hay ninguna interacción con el juego.