Noticias

¡RECUERDA QUE SI ERES UN NUEVO USUARIO, DEBES PRESENTARTE PARA PODER PUBLICAR MENSAJES! | TENEMOS CANAL OFICIAL DE TELEGRAM: t.me/unity3dspain

[Duda] Añadir componente en EditorMode a un seleccionado

Iniciado por Null, Mayo 08, 2017, 11:12:48 PM

Tema anterior - Siguiente tema
Mayo 08, 2017, 11:12:48 PM Ultima modificación: Mayo 09, 2017, 12:32:08 AM por pioj
Holas.
Resulta que tengo un script que hace que al tener un objeto seleccionado en Editor Mode y usar Ctrl+F, posiciona a dicho objeto a ras de suelo, o sobre cualquier otro objeto que éste tenga debajo, mediante raycast.
Es más que nada por comodidad, para hacerme la vida más fácil con algunos gameobjects que quedan flotando y que me dan pereza bajarlos manualmente con los gizmos, jeje.
 
Para ello uso 2 scripts, pero el problema es que para que funcione, el gameobject debe tener el script "PlaceToGround". Y pues tendría que añadir ese script a todos los objetos de la escena.
Entonces, mi plan era simplemente añadir el script al objeto que tenga seleccionado, mediante código, para después de de-seleccionarlo, quitárselo y aquí no pasó nada.
Todo funciona genial, pero pues lo de añadir el script al seleccionado no.
Alguna sugerencia? 
 
 
 
Este es el script que ejecuta el atajo de teclado:
 

using UnityEngine;
using Unit***itor;
public class Pereza : MonoBehaviour {
  [MenuItem("Comandos/A ras de suelo %f")]
  private static void SpecialCmd() {
    if (PlaceToGround.CanLand) {
      var offset = new Vector3(0f, -.2f, 0f);
      var selected = Selection.activeGameObject.transform;
     
      selected.SetPositionAndRotation(PlaceToGround.hit.point + offset, selected.transform.rotation);
    }
  }
}

 
 
 
Y este el que usa raycast y el cual deben tener los objetos:
 

using UnityEngine;
[ExecuteInEditMode]
public class PlaceToGround : MonoBehaviour {
  private static RaycastHit m_hit;
  private float m_maxDist = 100;
  private static bool m_canLand = false;
 
  public static RaycastHit Hit { get { return m_hit; } }
  public static bool CanLand { get { return m_canLand; } }
 
  private void Update() {
    Ray ray = new Ray(transform.position, Vector3.down * m_maxDist);
   
    if (Physics.Raycast(ray, out m_hit, m_maxDist)) {
      Debug.DrawRay(ray.origin, ray.direction * m_hit.distance, Color.red);
      m_canLand = true;
    } else {
      m_canLand = false;
    }
  }
}

 
 

Prueba esto a ver si te sirve, he cambiado el  "SetPositionAndRotation" por un rotation y un position normal, pues mi versión de unity no tenía ese método.
 
También cambié la estructura de los componentes, más que nada para evitar el Update de PlaceToGround y simplemente llamarlo por un método convencional y evitar los valores estáticos.
 
Pereza:
 

using UnityEngine;
using Unit***itor;
public class Pereza : MonoBehaviour
{
    [MenuItem("Comandos/A ras de suelo %f")]
    private static void SpecialCmd()
    {
        GameObject object_selected = Selection.activeGameObject;
        object_selected.AddComponent<PlaceToGround>();
        Vector3 hitPoint = object_selected.GetComponent<PlaceToGround>().Comienzo();
        Transform selected = object_selected.transform;
        if (hitPoint != Vector3.zero)
        {
            var offset = new Vector3(0f, -.2f, 0f);
            selected.position = hitPoint + offset;
            selected.rotation = selected.transform.rotation;
        }
        DestroyImmediate(object_selected.GetComponent<PlaceToGround>());
    }
}

 
 
 
PlaceToGround:
 

using UnityEngine;
[ExecuteInEditMode]
public class PlaceToGround : MonoBehaviour
{
    private float m_maxDist = 100;
    public Vector3 Comienzo()
    {
        RaycastHit m_hit;
        Ray ray = new Ray(transform.position, Vector3.down * m_maxDist);
        if (Physics.Raycast(ray, out m_hit, m_maxDist))
        {
            return m_hit.point;
        }
        return Vector3.zero;
    }
}

 
 

Cita de: Null date=1494277968el gameobject debe tener el script "PlaceToGround". Y pues tendría que añadir ese script a todos los objetos de la escena.
   


cual es ese script? osea ya se que lo subiste, pero es un script de la wiki esa famosa de Unity? osea posicionarlos solamente se podria hacer con un simple script de EditorWindow, abris tu ventana con un boton que diga "placeToground" por ejemplo, seleccionas un objeto, lo apretas y hace todo el proceso, el objeto en cuestion no debe tener ningun codigo extra, es un subordinado del proceso.

Mayo 09, 2017, 02:27:03 AM #3 Ultima modificación: Mayo 09, 2017, 02:27:37 AM por Null
Cita de: lightbug date=1494289169cual es ese script? osea ya se que lo subiste, pero es un script de la wiki esa famosa de Unity? osea posicionarlos solamente se podria hacer con un simple script de EditorWindow, abris tu ventana con un boton que diga "placeToground" por ejemplo, seleccionas un objeto, lo apretas y hace todo el proceso, el objeto en cuestion no debe tener ningun codigo extra, es un subordinado del proceso.
   


No, el script no es de ninguna wiki! Lo hice antes. Por cierto, a cual wiki famosa te refieres? xd

Es que en Unreal por ejemplo está esa función, que seleccionas algo, aprietas la tecla, que creo que era End (o Fin), y te lo colocaba a ras de suelo.


Voy a probar primero con la respuesta de Harsel  y luego sino probaré a hacerlo con una EditorWindow! :)

Cita de: Null date=1494289623No, el script no es de ninguna wiki! Lo hice antes. Por cierto, a cual wiki famosa te refieres? xd
   


http://wiki.unity3d.com/index.php/Scripts
 
Esta ^ ... bienvenido hermano, pasad ...pasad
 
Si yo te proponia mas reformular la idea, no solucionar la actual, ya que le estas agregando el script a algo que no tiene un comportamiento luego, algo que no tiene sentido que sea un monobehaviour.

Estoy de acuerdo con Lightbug, es innecesaria la creación de un monobehaviour y mucho más cuando se puede usar un CustomEditor y tomar los valores por EventType, incluso usando un Custom MenuItem te recomendaría simplemente crear un script único.
 
Te lo planteare de esta manera por ejemplo:
 

public class Pereza
{
    static float m_maxDist = 100f;
    [MenuItem("Comandos/A ras de suelo %f")]
    private static void SpecialCmd()
    {
            GameObject object_selected = Selection.activeGameObject;
            RaycastHit m_hit;
            Ray ray = new Ray(object_selected.transform.position, Vector3.down * 100f);
            if (Physics.Raycast(ray, out m_hit, m_maxDist))
            {
                var offset = new Vector3(0f, -.2f, 0f);
                object_selected.transform.position = m_hit.point + offset;
                object_selected.transform.rotation = object_selected.transform.rotation;
            }
    }
}

 
Otro método, sería hacerlo por CustomEditor, no obstante este último método que te planteo también es bastante más viable que andar con dos monobehaviour sin uso real.
 
Un saludo.

Cita de: Harsel date=1494292235Estoy de acuerdo con Lightbug, es innecesaria la creación de un monobehaviour y mucho más cuando se puede usar un CustomEditor y tomar los valores por EventType, incluso usando un Custom MenuItem te recomendaría simplemente crear un script único.
   
   
      Te lo planteare de esta manera por ejemplo:
   
   

public class Pereza
{
    static float m_maxDist = 100f;
    [MenuItem("Comandos/A ras de suelo %f")]
    private static void SpecialCmd()
    {
            GameObject object_selected = Selection.activeGameObject;
            RaycastHit m_hit;
            Ray ray = new Ray(object_selected.transform.position, Vector3.down * 100f);
            if (Physics.Raycast(ray, out m_hit, m_maxDist))
            {
                var offset = new Vector3(0f, -.2f, 0f);
                object_selected.transform.position = m_hit.point + offset;
                object_selected.transform.rotation = object_selected.transform.rotation;
            }
    }
}

   
      Otro método, sería hacerlo por CustomEditor, no obstante este último método que te planteo también es bastante más viable que andar con dos monobehaviour sin uso real.
   
   
      Un saludo.
   


Mil gracias!

Etiquetas: