- Home /
I need to get a Vector3 of the mouse position while i'm editing in the scene view.
I need it to be relative to the origin point of the world. I want to use it to snap an object to a grid.
[ExecuteInEditMode]
[CanEditMultipleObjects]
class Snap : MonoBehaviour
{
public string tagName = "Tile";
public bool alignEverything = false;
Vector3 mousePos;
Vector3 mPRange;
private void Update()
{
mousePos = ;//code to get mouse Position;
mPRange = new Vector3(((mousePos.x % 1) >= 0.5) ? 1 : -1, ((mousePos.y % 1) >= 0.5) ? 1 : -1, ((mousePos.z % 1) >= 0.5) ? 1 : -1);
//This finds all gameObjects I can move
foreach (GameObject g in Selection.GetFiltered(typeof(GameObject), SelectionMode.TopLevel | SelectionMode.Editable))
{
//These splits the GameObject into a Transform and SpriteRenderer
SpriteRenderer spr = g.GetComponent<SpriteRenderer>();
Transform t = g.transform;
//This ternary operator skips the tag check if alignEverything is set to true
if (((alignEverything && spr != null) ? (true) : (g.tag == tagName)) && Selection.Contains(g))
{
//This changes the objects transform to align to the grid in unity
g.transform.position = new Vector3( (t.position.x - (t.position.x % 1)) + (mPRange.x * spr.bounds.extents.x),
(t.position.y - (t.position.y % 1)) + (mPRange.y * spr.bounds.extents.y),
(t.position.z - (t.position.z % 1)) + (mPRange.z * spr.bounds.extents.z));
}
}
}
}
you will probably want to use Camera.main.ScreenToWorldPoint() https://docs.unity3d.com/ScriptReference/Camera.ScreenToWorldPoint.html and Input.mousePosition https://docs.unity3d.com/ScriptReference/Input-mousePosition.html
Note that the input to ScreenToWorldPoint is a Vector3; so in addition to the mouse/screen position (x,y), you will need to have some way for the user to specify the distance from the camera(z). This is because a single screen point actually represents a LINE of points through your 3D world-space.
I need the script to work while in the unity editor. This script only works while in play mode.
[ExecuteInEdit$$anonymous$$ode]
public class SnapToGrid : $$anonymous$$onoBehaviour
{
public string tagName = "Tile";
public bool alignEverything = false;
Vector3 mousePos;
Vector3 mPRange;
static float range;
private void Update()
{
Vector3 screen$$anonymous$$ousePos = Input.mousePosition;
screen$$anonymous$$ousePos.z = range;
mousePos = Camera.main.ScreenToWorldPoint(screen$$anonymous$$ousePos);
mPRange = new Vector3((mousePos.x % 1) >= 0.5f ? ((mousePos.x % 1) - 0.5f) : -((mousePos.x % 1) - 0.5f),
(mousePos.y % 1) >= 0.5f ? ((mousePos.y % 1) - 0.5f) : -((mousePos.y % 1) - 0.5f),
(mousePos.z % 1) >= 0.5f ? ((mousePos.z % 1) - 0.5f) : -((mousePos.z % 1) - 0.5f));
//This finds all gameObjects I can move
foreach (GameObject g in Selection.GetFiltered(typeof(GameObject), Selection$$anonymous$$ode.TopLevel | Selection$$anonymous$$ode.Editable))
{
range = g.GetComponent<Transform>().position.z;
//This ternary operator skips the tag check if alignEverything is set to true
if (((alignEverything && g.GetComponent<SpriteRenderer>() != null) && Selection.Contains(g) ? (true) : (g.tag == tagName)))
{
//This changes the objects transform to align to the grid in unity
g.transform.position = new Vector3(mousePos.x + mPRange.x,
mousePos.y + mPRange.y,
mousePos.z + mPRange.z);
}
}
}
}
It already was, I just forgot to paste that part into this forum. I'm changing it now.
I guess you could put this as an extending Editor script, and get the current selection and snap it to grid by using this https://docs.unity3d.com/ScriptReference/Selection.html
Answer by Bill9009 · Mar 09, 2017 at 02:43 AM
Okay thank you for the information and finally I have found the answer. I got it on this page Editor script help for finding mouse position in Scene view.
Thanks for all the assistance. I modified the code for my situation and got:
[CustomEditor(typeof(SnapToGrid))]
public class SnapToGridEditor : Editor
{
private static Vector3 position;
public static Vector3 Position
{
get { return position; }
}
static SnapToGridEditor()
{
SceneView.onSceneGUIDelegate += UpdateView;
}
private static void UpdateView(SceneView sceneView)
{
if (Event.current != null)
{
position = SceneView.currentDrawingSceneView.camera.ScreenToWorldPoint(Event.current.mousePosition);
//This makes the mouse position adjust so it is relative to the world position
position.y = -(position.y - (2 * SceneView.currentDrawingSceneView.camera.transform.position.y));
}
}
}
ScreenToWorldPoint won't give you the right position. Screen space has it's origin at the bottom left while GUI space has it's origin at the top left. As i said in my answer Event.current.mousePosition returns the mouse position in GUI space. You would need to invert the y-axis (subtracting it from the sceneview height) to get screen space coordinates.
O$$anonymous$$G you are an absolute lifesave !!! I was about to give up on my problem to get reliable Tilemap coordinates from cliking in the scene view and google for over 6 hours for it AND YOU my fried are the first person who was able to bring a solution to this issue!! No I can start my Editor $$anonymous$$ode designing with all my custom tiles, thank you so much!! I want to share an article later and hope you are not against, that I'm using this to help everybody facing the same issue! Greets !
Answer by Bunny83 · Mar 09, 2017 at 02:14 AM
The "ExecuteInEditMode" attribute is not ment to turn a runtime script into an editor script. It's main purpose is to get live feedback of the runtime functionality inside the editor while you're not playing the game. For example particle systems would use this so you can actually see how it looks like while editing,
Again, it's not ment to implement any editor extension. While it is possible to some extend it's very limited. Also MonoBehaviour classes are runtime classes. So implementing a MonoBehaviour that is only used inside the editor makes not much sense,
You may want to implement an actual editor script. In general there are four different kinds of editor scripts:
CustomInspector (Editor class)
EditorWindow
PropertyDrawer / DecoratorDrawer
Other / general purpose
Most extensions that involve the sceneview are implemented inside custom inspectors. A custom inspecter has an OnSceneGUI callback which allows you to directly hook into the drawing and event processing of the SceneView. Though OnSceneGUI of a custom inspector is only run while an object that uses this custom inspector is currently inspected (visible in the inspector). If you deselect the object.
From all other kinds of editor scripts you can subscribe a method to the static "onSceneGUIDelegate" event of the SceneView class. SceneView.onSceneGUIDelegate += YourMethod
.
This let you handle SceneView events on a global scale.
Inside the sceneview callback you can use the usual IMGUI event system. So Event.current.mousePosition
returns the current mouse position in GUI space relative to the sceneview. If you want a world space position you usually use GUIPointToWorldRay from the HandleUtility class. To get an actual point you either use GetPoint of that ray with a certain distance, cast a ray against colliders in the scene using the Physics class or use the Plane class to define an infinite plane you can raycast against.
It's hard to tell what exact purpose the script has and how it's supposed to be used. You have no conditions for your "movement", so currently everything that is selected will be affected "every frame". The fractional mouse position will determine if the objects move in one direction or the other. At no point the objects don't move. This seems very strange to me.
If you want to implement a special edit move / tool (like Unity's move / rotate / view tool) you might want to create an editorwindow where you can enable / disable your tool. For this it usually makes sense to use the Tools class and set current to Tool.None while your tool is active. Though the question is how deep do you want to go into editor / tool programming? As general referemce my GUI crash course.
Btw: The attribute "CanEditMultipleObjects" only makes sense for custom inspectors. Custom inspectors without that attribute will not show up when you have multiple objects selected.
Thanks to your comment, I got this working:
Ray mouseRay = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition);
Vector3 mousePosition = mouseRay.GetPoint(0f);
Nothing else that I had read on several posts before had worked.
Thanks to your comment, I got this working:
Ray mouseRay = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition); Vector3 mousePosition = mouseRay.GetPoint(0f);
Nothing else that I had read on several posts before had worked.
Same Thank you!
Your answer
Follow this Question
Related Questions
Multiple Cars not working 1 Answer
How to Draw in Scene View "unconditionally"? 0 Answers
Distribute terrain in zones 3 Answers