Sempre me perguntei se é possível mostrar um ponto arrastável na cena para posicionar
Por exemplo, supondo que eu tenha um script que deve gerar um certo pré-fabricado na cena com uma determinada posição:
using UnityEngine;
using System.Collections;
public class ExampleBehavior : MonoBehaviour {
public Vector3 SpawnPosition;
public GameObject SpawnableObject;
public void Spawn() {
Instantiate(SpawnableObject, SpawnPosition, Quaternion.identity);
}
}
Meu objetivo era tornar mais fácil mover o SpawnPosition
ponto dentro da cena. Minha primeira abordagem foi usar o OnGizmosSelected
método e mostrar uma esfera colorida no editor de cena para indicar a posição do ponto. No entanto, não foi tão confortável editar.
Inspecionando este ótimo plugin , descobri a excelente API Handles do Editor Unity
Portanto, tentei definir um script de editor personalizado para mostrar um Handle
ponto genérico, para poder reutilizá-lo em muitos scripts facilmente.
Em primeiro lugar, defini um novo PropertyAttribute
, para que possa usá-lo para habilitar esse comportamento no editor:
public class DraggablePoint : PropertyAttribute {}
Em seguida, defini um script de editor personalizado, para todos MonoBehaviors
, que itera cada propriedade em busca de um DraggablePoint
, mostrando um identificador para ele:
[CustomEditor(typeof(MonoBehaviour), true)]
public class DraggablePointDrawer : Editor {
readonly GUIStyle style = new GUIStyle();
void OnEnable(){
style.fontStyle = FontStyle.Bold;
style.normal.textColor = Color.white;
}
public void OnSceneGUI () {
var property = serializedObject.GetIterator ();
while (property.Next (true)) {
if (property.propertyType == SerializedPropertyType.Vector3) {
var field = serializedObject.targetObject.GetType ().GetField (property.name);
if (field == null) {
continue;
}
var draggablePoints = field.GetCustomAttributes (typeof(DraggablePoint), false);
if (draggablePoints.Length > 0) {
Handles.Label(property.vector3Value, property.name);
property.vector3Value = Handles.PositionHandle (property.vector3Value, Quaternion.identity);
serializedObject.ApplyModifiedProperties ();
}
}
}
}
}
Observe que:
- Estou passando
true
como segundo parâmetro paraCustomEditor
. Isso diz à unidade para instanciar este script do Editor para todas as classes que herdam de MonoBehavior (cada componente do script de unidade). - Estou usando para iterar em cada propriedade do script.
serializedObject.GetIterator ()
- Eu uso o Reflection para verificar se há algum
PropertyAttribute
tipoDraggableType
definido na propriedade do objeto atual. - Eu uso
serializedObject.ApplyModifiedProperties ();
para aplicar o movimento feito pela alça. Ele também cria uma entrada de histórico, para que você possa usarctrl+z
para reverter o movimento
Eu acho que o resultado é muito legal!
Aqui está um exemplo:
E aqui está o exemplo de código completo:
https://gist.github.com/ProGM/226204b2a7f99998d84d755ffa1fb39a
Estou usando este script para meu videogame. Confira!
Espero que você possa achar isso útil!