Last active
January 31, 2023 13:47
-
-
Save lordlycastle/82e4523aba6e4fd272e890e41ab68522 to your computer and use it in GitHub Desktop.
Casts a ray from the scene view camera and draws a line from transform to the hits. Can be used for selection in scene view.
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
#if UNITY_EDITOR | |
using System; | |
using System.Collections.Generic; | |
using Sirenix.OdinInspector; | |
using Sirenix.OdinInspector.Editor; | |
using UnityEditor; | |
using UnityEngine; | |
using System.Linq; | |
using Sirenix.Serialization; | |
public class RaycastPlacer : MonoBehaviour | |
{ | |
[Serializable] | |
public class RaycastPlacerModel | |
{ | |
[TitleGroup("Hit Objects")] | |
[ShowInInspector] | |
public RaycastHit raycastHit; | |
[ShowInInspector, HideLabel, LabelWidth(0)] | |
public Transform HitTransform => raycastHit.transform; | |
// [ShowInInspector] | |
private GameObject HitGameObject => raycastHit.transform.gameObject; | |
[ShowInInspector] | |
public Vector3 HitPoint => raycastHit.point; | |
private Transform _transform; | |
public RaycastPlacerModel(RaycastHit raycastHit, Transform transform) | |
{ | |
this.raycastHit = raycastHit; | |
_transform = transform; | |
} | |
[ButtonGroup, Button] | |
public void AlignX() | |
{ | |
var transformPosition = _transform.position; | |
transformPosition.x = raycastHit.point.x; | |
ChangeTransformPosition(transformPosition); | |
} | |
[ButtonGroup] | |
public void AlignY() | |
{ | |
var transformPosition = _transform.position; | |
transformPosition.y = raycastHit.point.y; | |
ChangeTransformPosition(transformPosition); | |
} | |
[ButtonGroup] | |
public void AlignZ() | |
{ | |
var transformPosition = _transform.position; | |
transformPosition.z = raycastHit.point.z; | |
ChangeTransformPosition(transformPosition); | |
} | |
[ButtonGroup] | |
public void AlignXYZ() | |
{ | |
ChangeTransformPosition(raycastHit.point); | |
} | |
public void ChangeTransformPosition(Vector3 transformPosition) | |
{ | |
Undo.RecordObject(_transform, "Move Transform"); | |
_transform.position = transformPosition; | |
} | |
private Editor editor; | |
[OnInspectorGUI] | |
private void OnInspectorGUI() | |
{ | |
if (editor == null || editor.target != HitGameObject) | |
{ | |
editor = HitGameObject == null ? null : Editor.CreateEditor(HitGameObject); | |
} | |
Rect rect = GUILayoutUtility.GetRect(100, 100); | |
editor?.DrawPreview(rect); | |
} | |
} | |
[ShowInInspector] | |
public static LayerMask raycastLayers = int.MaxValue; | |
public float maxDistance = 100f; | |
[HideInInspector] | |
public bool isRaycasting; | |
[OdinSerialize, ListDrawerSettings(HideAddButton = true, DraggableItems = false, ShowPaging = false), PropertyOrder(99)] | |
public List<RaycastPlacerModel> raycastHits = new List<RaycastPlacerModel>(); | |
private Ray mouseRay; | |
[Button(ButtonSizes.Medium)] | |
public void ToggleRaycasting() => isRaycasting = !isRaycasting; | |
private void UpdateRaycast(SceneView sceneView) | |
{ | |
Vector3 mousePosition = Event.current.mousePosition; | |
mousePosition.y = SceneView.currentDrawingSceneView.camera.pixelHeight - mousePosition.y; | |
mousePosition = SceneView.currentDrawingSceneView.camera.ScreenToWorldPoint(mousePosition); | |
mousePosition.y = -mousePosition.y; | |
mouseRay = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition); | |
raycastHits = Physics.RaycastAll(mouseRay, maxDistance) | |
.Select(hit => new RaycastPlacerModel(hit, transform)) | |
.ToList(); | |
if (raycastHits.Count > 0) | |
{ | |
// Debug.Log($"Hit {raycastHits.Count} objects."); | |
DrawRays(transform.position, raycastHits); | |
} | |
SceneView.onSceneGUIDelegate -= UpdateRaycast; | |
} | |
private void DrawRays(Vector3 origin, List<RaycastPlacerModel> objects) | |
{ | |
Handles.color = Color.magenta; | |
foreach (var o in objects) | |
{ | |
Handles.DrawLine(origin, o.raycastHit.point); | |
} | |
} | |
private void OnDrawGizmosSelected() | |
{ | |
if (isRaycasting == false) return; | |
SceneView.onSceneGUIDelegate += UpdateRaycast; | |
Gizmos.color = Color.yellow; | |
// Debug.Log($"Ray: {mouseRay.origin} dir: {mouseRay.direction}"); | |
} | |
} | |
[CustomEditor(typeof(RaycastPlacer))] | |
class RaycastPlacerEditor : OdinEditor | |
{ | |
private void OnSceneGUI() | |
{ | |
if (target is RaycastPlacer raycastPlacer) | |
{ | |
// Retrieve the control Id | |
int controlId = GUIUtility.GetControlID(FocusType.Passive); | |
if (Event.current.type == EventType.MouseDown && Event.current.button == 0 && raycastPlacer.isRaycasting) | |
{ | |
raycastPlacer.isRaycasting = false; | |
// Tell the UI your event is the main one to use, it override the selection in the scene view | |
GUIUtility.hotControl = controlId; | |
Event.current.Use(); | |
// Debug.Log("Event Used."); | |
} | |
} | |
} | |
} | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment