Last active
October 19, 2021 16:46
-
-
Save bzgeb/8dd186bbdd532f43fe6c7615f036cc19 to your computer and use it in GitHub Desktop.
Quick and dirty Unity tool to place an object
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEditor; | |
using UnityEditor.EditorTools; | |
using UnityEditor.UIElements; | |
using UnityEngine; | |
using UnityEngine.UIElements; | |
[EditorTool("Place Object Tool")] | |
public class PlaceObjectTool : EditorTool | |
{ | |
[SerializeField] Texture2D m_ToolIcon; | |
GUIContent m_IconContent; | |
VisualElement toolRootElement; | |
Toggle useCurrentSelection; | |
ObjectField prefabObjectField; | |
bool receivedClickDownEvent; | |
bool receivedClickUpEvent; | |
public override GUIContent toolbarIcon => m_IconContent; | |
public override void OnActivated() | |
{ | |
m_IconContent = new GUIContent | |
{ | |
image = m_ToolIcon, | |
text = "Place Object Tool", | |
tooltip = "Place Object Tool" | |
}; | |
var sv = SceneView.lastActiveSceneView; | |
SceneView.beforeSceneGui += BeforeSceneGUI; | |
toolRootElement = new VisualElement(); | |
toolRootElement.style.width = 200; | |
var titleLabel = new Label("Place Object Tool"); | |
toolRootElement.Add(titleLabel); | |
prefabObjectField = new ObjectField {allowSceneObjects = true, objectType = typeof(GameObject)}; | |
useCurrentSelection = new Toggle {label = "Use Current Selection"}; | |
useCurrentSelection.RegisterValueChangedCallback(evt => { prefabObjectField.visible = !evt.newValue; }); | |
toolRootElement.Add(useCurrentSelection); | |
toolRootElement.Add(prefabObjectField); | |
sv.rootVisualElement.Add(toolRootElement); | |
sv.rootVisualElement.style.flexDirection = FlexDirection.ColumnReverse; | |
} | |
public override void OnWillBeDeactivated() | |
{ | |
SceneView.beforeSceneGui -= BeforeSceneGUI; | |
toolRootElement?.RemoveFromHierarchy(); | |
} | |
public void BeforeSceneGUI(SceneView sceneView) | |
{ | |
if (ToolManager.IsActiveTool(this)) | |
{ | |
if (useCurrentSelection.value && Selection.activeGameObject == null) | |
{ | |
receivedClickDownEvent = false; | |
receivedClickUpEvent = false; | |
return; | |
} | |
if (!useCurrentSelection.value && prefabObjectField?.value == null) | |
{ | |
receivedClickDownEvent = false; | |
receivedClickUpEvent = false; | |
return; | |
} | |
if (Event.current.type == EventType.MouseDown && Event.current.button == 0) | |
{ | |
receivedClickDownEvent = true; | |
Event.current.Use(); | |
} | |
if (receivedClickDownEvent && Event.current.type == EventType.MouseUp && Event.current.button == 0) | |
{ | |
receivedClickDownEvent = false; | |
receivedClickUpEvent = true; | |
Event.current.Use(); | |
} | |
} | |
} | |
public override void OnToolGUI(EditorWindow window) | |
{ | |
if (!(window is SceneView sceneView)) | |
return; | |
if (ToolManager.IsActiveTool(this)) | |
{ | |
if (useCurrentSelection.value && Selection.activeGameObject == null) | |
{ | |
return; | |
} | |
if (!useCurrentSelection.value && prefabObjectField?.value == null) | |
{ | |
return; | |
} | |
Handles.DrawWireDisc(GetCurrentMousePositionInScene(), Vector3.up, 1f); | |
if (receivedClickUpEvent) | |
{ | |
var newObject = useCurrentSelection.value ? Selection.activeGameObject : prefabObjectField.value; | |
PrefabUtility.IsPartOfPrefabInstance(newObject); | |
var newPrefabInstance = (GameObject) PrefabUtility.InstantiatePrefab(newObject); | |
if (newPrefabInstance == null) | |
{ | |
if (PrefabUtility.IsPartOfPrefabInstance(newObject)) | |
{ | |
var prefabPath = PrefabUtility.GetPrefabAssetPathOfNearestInstanceRoot(newObject); | |
var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(prefabPath); | |
newPrefabInstance = (GameObject) PrefabUtility.InstantiatePrefab(prefab); | |
} | |
else | |
{ | |
newPrefabInstance = Instantiate((GameObject) newObject); | |
} | |
} | |
newPrefabInstance.transform.position = GetCurrentMousePositionInScene(); | |
Event.current.Use(); | |
Undo.RegisterCreatedObjectUndo(newPrefabInstance, "Place new object"); | |
receivedClickUpEvent = false; | |
} | |
} | |
} | |
Vector3 GetCurrentMousePositionInScene() | |
{ | |
Vector3 mousePosition = Event.current.mousePosition; | |
var placeObject = HandleUtility.PlaceObject(mousePosition, out var newPosition, out var normal); | |
return placeObject ? newPosition : HandleUtility.GUIPointToWorldRay(mousePosition).GetPoint(10); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment