sábado, 27 de abril de 2013

Arrastrar objetos en Unity (Drag & Drop).



Saludos amigos.

Alguna vez me han preguntado como se haría para arrastrar un objeto en un juego(Drag & Drop), sobre todo para algún tipo de puzle o juego 2D. En este ejemplo trato de resolver alguna de esas dudas.

La escena consta de unas primitivas que utilizaremos como si de nuestras fichas se tratara y como podréis ver en el vídeo sería válido, tanto para juegos 2D como 3D. Tened en cuenta que se trata de un ejemplo básico que deberéis adaptar a vuestro tipo de juego.

Los scripts incluyen una variable con un numero entero para realizar un filtrado de objetos,
con la cual, permitir o no la colocación de la supuesta ficha en su lugar correspondiente.
Tiene la capacidad de colocar un icono en lugar de nuestra ficha cuando se esta arrastrando
y también realiza un Lerp entre dos colores en el momento del arrastre y cuando se sitúa el cursor sobre el objeto que admite el mismo.

Las variables estáticas que guardan la información de los objetos con los cuales estamos realizando dichas operaciones, se guardan en un script aparte en un objeto vacío. Teniendo la posibilidad de ser ampliado según nos haga falta.

Por ejemplo, si queremos realizar varias operaciones del mismo tipo y deseamos que se mantenga el valor de dichas variables, solo seria cuestión de duplicarlas con otro nombre y cambiar el nombre en los scripts de los objetos que arrastramos.

static var objetoArrastrado2 : GameObject;
static var objetoQuieto2 : GameObject;
static var tipo2 : int;



Espero que os sea útil.

Enjoy!!!






//DragTest.js


#pragma strict
var camara : Camera;
var tipo : int = 0;
private var pos : Vector3;
private var pos2 : Vector2;

private var clon : GameObject;
var iconoClon : GameObject;
private var posClon : Vector3;

private var bol : boolean = false;
private var distancia : float;
var distProfundidadIcono : float = 5;
private var rayo : Ray;

var color1 : Color = Color.red;
var color2 : Color = Color.yellow;
var materialClon : Material;
private var materialOriginal : Material;
var duration : float = 1.0;

var velocidad : float = 4;

function OnGUI() {
 var e : Event = Event.current;
 if (e.isMouse) {
  pos2 = e.mousePosition;
 }
}

function OnMouseUp () {
    
    Debug.Log("Drag ended!");
    renderer.material = materialOriginal;
    Destroy(clon);
    clon = null;
    bol = false;
    if(CNTdrag.objetoQuieto != null && CNTdrag.tipo == tipo){
     transform.position = CNTdrag.objetoQuieto.transform.position;
    }
    CNTdrag.objetoQuieto = null;
}

function OnMouseDrag () {
    
    Test ();
    actualizado = true;
}

function Start () {
 
 Inicializa ();
 pos = transform.position;
 posClon = transform.position;
 materialOriginal = renderer.material;
}

function Update() {
    
    pos = transform.position;
    if(clon){
     if(Rigidbody){
      Destroy(clon.rigidbody);
     }
     if(Collider){
      Destroy(clon.collider);
     }
     clon.transform.position = posClon;
     Colores ();
     
     vec = Vector3 (xClon,yClon,camara.nearClipPlane+(zClon));
     DibujaClon ();
     if(actualizado){
      Inicializa ();
     }
     xClon += Input.GetAxis("Mouse X")  * velocidad * 100 * Time.deltaTime;
     yClon += Input.GetAxis("Mouse Y")  * velocidad * 100 * Time.deltaTime;
    }
 Rayo ();
 w = Screen.width;
 h = Screen.height;

}

private var p : Vector3;
private var m : Matrix4x4;

function Test () {
 if(Input.GetButton ("Fire1") ){
  m = camara.cameraToWorldMatrix;
  p = m.MultiplyPoint (Vector3(0,0,distancia));
  posClon = camara.WorldToScreenPoint (p);
  if(!bol){
      if(iconoClon){
       clon = Instantiate (iconoClon, posClon, Quaternion.identity);
      }else{
       clon = Instantiate (gameObject, posClon, Quaternion.identity);
      }
      bol = true;
     }
 }
}

function Rayo () {
 
 rayo.origin = camara.transform.position;
    rayo.direction = transform.position;
    distancia = Vector3.Distance(rayo.origin, rayo.direction);
    
}

function Colores () {
 
 var lerp : float = Mathf.PingPong (Time.time, duration) / duration;
    if(!materialClon){
     clon.renderer.material = new Material(Shader.Find("Transparent/Diffuse"));
     clon.renderer.material.color = Color.Lerp (color1, color2, lerp);
    }else{
     clon.renderer.material = materialClon;
    }
    renderer.material = new Material(Shader.Find("Transparent/Diffuse"));
 color1.a = 0.5;
 color2.a = 0.5;
 renderer.material.color = Color.Lerp (color1, color2, lerp);
 
}

private var vec : Vector3;
private var xClon : float = pos2.x;
private var yClon : float = pos2.y;
private var zClon : float = distProfundidadIcono;
 
function DibujaClon () {
    var p1 : Vector3 = camara.ScreenToWorldPoint (vec);
    clon.transform.position = p1;

}

private var actualizado : boolean = false;
private var w = Screen.width;
private var h = Screen.height;
    
function Inicializa () {
 
 xClon = pos2.x;
 yClon = h-(pos2.y);
 zClon = distProfundidadIcono;
 actualizado = false;
}




//CNTdrag.js

#pragma strict

static var objetoArrastrado : GameObject;
static var objetoQuieto : GameObject;
static var tipo : int;


function Start () {
 
 
 
}

function Update () {
 
 
 
}





//AdmiteDrag.js

#pragma strict

var tipo : int = 0;
var color1 : Color = Color.red;
var color2 : Color = Color.yellow;
private var lerp : float;
var duration : float = 1.0;
private var materialOriginal : Material;

function OnMouseOver () {
 
 CNTdrag.tipo = tipo;
 CNTdrag.objetoQuieto = gameObject;
 renderer.material = new Material(Shader.Find("Transparent/Diffuse"));
 color1.a = 0.5;
 color2.a = 0.5;
 renderer.material.color = Color.Lerp (color1, color2, lerp);
 
}

function OnMouseExit () {
 
 CNTdrag.objetoQuieto = null;
 CNTdrag.tipo = -1;
 renderer.material = materialOriginal;
 
}

function Start () {
 
 materialOriginal = renderer.material;
 
}

function Update () {
 
 lerp = Mathf.PingPong (Time.time, duration) / duration;
 
}

13 comentarios:

  1. Muchas gracias, me ayudo mucho en lo que estoy haciendo

    ResponderEliminar
  2. Ey, estoy haciendo un juego tipo amnesia, ¿esto me serviría para hacer las puertas, los objetos, cajones, puertas de armario, etc...?

    ResponderEliminar
  3. gracias por el gran tutorial aun no lo pruebo en lo que hago. Me gustaria que me ayudaras un poco mas pues de script no se mucho, y lo que quisiera, es que al poner el objeto que muevo en el lugar que quiero que tenga un limite para que no se pase y si se pasa que centre en el area. (como si pusieras la esfera ensima del cubo y que solo encima se pueda poner) te agradesco mucho de antemano.

    ResponderEliminar
  4. gracias por el enorme tuto me fue muy util aunque todavía no lo uso esta estupendo.
    me gustaría que me ayudaras un poco mas, es que de scipt no se mucho. lo que quisiera es que a la hora de poner un objeto en un lugar que no se saliera del limite y si se sale del limite que lo corrija centrándolo. Como si pusieras la esfera en la superficie y si la pones abajo o al lado del cubo valla arriba automáticamente como si corrigiera un herror ) te agradezco de antemano.

    ResponderEliminar
    Respuestas
    1. Me alegra que te sea de utilidad.

      Si te fijas en la función OnMouseUp (), del script DragTest.js dóde dice:

      if(CNTdrag.objetoQuieto != null && CNTdrag.tipo == tipo){
      transform.position = CNTdrag.objetoQuieto.transform.position;
      }
      Se comprueba si hay objeto y si es del mismo tipo. Una vez comprobado le asigna la posición del objeto quieto.
      Lo que puedes hacer el cambiar esto y añadir un vector3 que se sume a la posición del objeto.
      Bien... y como hacer esto ;)

      En CNTdrag añade una nueva variable:
      static var posFIX : Vector3;

      En AdmiteDrag añade una nueva variable:
      var posFIX : Vector3;
      En la función OnMouseOver () añade:
      CNTdrag.posFIX = posFIX ;
      En la función OnMouseExit () añade:
      CNTdrag.posFIX = Vector3.zero;

      Y ahora en el if que vimos, antes cámbialo por esto:
      if(CNTdrag.objetoQuieto != null && CNTdrag.tipo == tipo){
      transform.position = CNTdrag.objetoQuieto.transform.position + CNTdrag.posFIX;
      }

      No lo probé pero te debería funcionar.
      Saludos.

      Eliminar
  5. Hola me gustaría saber como podría posicionar la esfera cobre el cubo, es decir que al arrastrarlo se poscione arriba del cubo y no al centro.
    gracias y saludos.

    ResponderEliminar
  6. Gracias por su magnifico Tutorial. Me resulta muy util para los juegos que planteo en clase con mis alumnos en la pizarra digital. Sin embargo, a la hora de exportarlos pierdo las caracteristicas de PARPADEO de Color cambiante y CLON de DESPLAZAMIENTO que funcionan perfectamente en la ventana Game del programa. ¿Alguna sugerencia ? porque yo me he rendido ...
    Le reitero mi agradecimiento en cualquier caso.

    ResponderEliminar
    Respuestas
    1. Saludos Angel.
      Siento la tardanza pero ando bastante liado y no tengo tiempo.
      Por lo que me comentas, los problemas pueden estar relacionados con que yo utilizo las funciones de OnMouse... que tienen que ver con el ratón.
      Mira la clase Touch el la documentación de Unity a ver si cambiando esto se soluciona.

      Eliminar
  7. Hola, muy buen tutorial, me gustaría saber como podría adaptar esas funcionalidades a Móvil, porque estoy haciendo un juego y en una escena debo hacer el Drag and Drop, pero como es móvil, para celulares, no me funciona, en computador si pero en celulares no funciona, gracias.

    ResponderEliminar
    Respuestas
    1. Saludos Jonathan.
      Te digo lo mismo que a Angel el problema puede ser que utilizo OnMouse().
      La verdad es que aun no he trabajado con dispositivos móviles ni pantallas táctiles pero no debería ser difícil adaptar el código para ellos.
      Mira en la documentación Input.GetTouch() a ver si te ayuda.

      Eliminar