Puzzle con RayCast en Unity 3D

Curso de Unity 3D

21.  
40.  

Por 9.99€ al mes tendrás acceso completo a todos los cursos. Sin matrícula ni permanencia.

Seleccionar una pieza (lanzar un rayo 2D y 3D)

Para que funcionen los rayos, cada pieza con la que va a colisionar el rayo debe tener un BoxCollider.

GameObject pieza;

void Update(){
	if(Input.GetMouseButtonDown(0)){
		SeleccionarPieza ();
	}
}

void SeleccionarPieza(){
	//Si estamos trabajando con Colliders 2D
	//RaycastHit2D hit = Physics2D.Raycast(Camera.main.ScreenToWorldPoint(Input.mousePosition), Vector2.zero);
	//if (hit)

	//Si estamos trabajando con Colliders 3D
	Ray rayo = Camera.main.ScreenPointToRay (Input.mousePosition);
	RaycastHit hit;
	if (Physics.Raycast (rayo, out hit)) {
		if (hit.collider.gameObject.tag == "piezapuzzle") {
			distanciaRayo = hit.distance; //distanciaRayo será un valor que utilizaremos más adelante
			pieza = hit.collider.gameObject;
			Debug.Log (pieza);
		}	
	}
	
}

Mover pieza con RayCast

void SeleccionarPieza(){
	...
	estaPulsado=true;
	...
}	

void Update(){
	if(estaPulsado){
		MoverPieza ();
	}	
}

void MoverPieza(){
	Ray rayo = Camera.main.ScreenPointToRay (Input.mousePosition);
	Vector3 limiteRayo = rayo.GetPoint (distanciaRayo);
	limiteRayo = new Vector3 (limiteRayo.x, limiteRayo.y, 0);
	pieza.transform.position = limiteRayo;
}

Explicación del método mover pieza.

Un rayo es infinito. Nos interesa mover la pieza al punto correcto de profundidad; por eso utilizamos la variable longitudRayo.

limiteRayo será el segmento que va desde la cámara, hasta el punto en que colisionamos con el bounding box de la pieza. Sin embargo, si la pieza tiene profundidad z=0, la bounding box tendrá una profundidad diferente y cada vez que llamemos a moverPieza() cambiaremos su ubicación, porque el origen de coordenadas de la pieza no coincide con el punto de impacteato, y la pieza se desplazará.

Unity 3D bounding box

Poner las piezas que se están moviendo por delante

    void SeleccionarPieza(){
	...
	if (hit){
		...
		ultimaFichaOrden++;
		pieza.GetComponent<SpriteRenderer>().sortingOrder = ultimaFichaOrden;

Arrastrar y soltar

...
	if (Input.GetMouseButtonUp (0)) {
		SoltarPieza ();
	}
...
void SoltarPieza(){
	if (estaPulsado) {
		estaPulsado = false;
		pieza = null;
	}
}

Comprobar si he dejado la pieza en la posición correcta

Tendré dos listas de piezas: fichasMoviles (que serán las que el usuario desplazará) y fichasSolución (cuyo componente SpriteRenderer desactivaré para que no se vean y que contendrá las piezas en su ubicación final).

public List<GameObject> fichasMoviles;
public List<GameObject> fichasSolucion;
public void ComprobarDrop(){
	for (int i = 0; i < fichasSolucion.Count; i++){
		if (pieza.name == fichasSolucion[i].name){
			if (Vector2.Distance(pieza.transform.position, fichasSolucion[i].transform.position) < 1){
				pieza.transform.position = fichasSolucion[i].transform.position;
				break;
			}   
		}   
	}
}

Detectar cuando el puzzle está completo

public void ComprobarDrop(){
	...
				contadorSolucionesCorrectas++;
				if (contadorSolucionesCorrectas == fichasMoviles.Count){
					Debug.Log("Ganaste");
				}
				pieza.GetComponent<BoxCollider2D>().enabled = false;
	...
}

Desordenar piezas

void Desordenar(){
	for (int i = 0; i < fichasMoviles.Count; i++) {
		fichasMoviles[i].transform.position = new Vector3 (Random.Range(-5,5), Random.Range(-2,2), 0);
	}
}

Desordenar piezas al cabo de un tiempo

Creamos el atributo global permitirJugar para que si el jugador pulsa sobre una pieza antes de que estas se desordenen no sea tenido en cuenta en el recuento de piezas movidas correctamente.

void Update(){
	if (Input.GetMouseButtonDown(0) && permiteJugar){
		...
	}
}

void Desordenar(){
	...
	permitirJugar = true;
}

Invoke("Desordenar", 2.0f);

Por 9.99€ al mes tendrás acceso completo a todos los cursos. Sin matrícula ni permanencia.