- Home /
4.6 UI Image follow mouse position?
So in my inventory I have this Picker object that's supposed to pick up items and have them follow the mouse. The picker is an empty object with a background (and eventually the picked up item) as children. The "Picker" is a child of "Inventory" which is a child of my "UI" canvas object. So UI/Inventory/Picker. I was making the picker follow the mouse with:
transform.localPosition = Input.mousePosition - myCanvas.transform.localPosition;
Everything was working fine until I later made some pivot-related changes to the slots and inventory, now the picker doesn't follow the cursor 'unless' I make it a direct parent to UI instead of Inventory, so then I would have UI/Inventory, and UI/Picker, i.e.
UI
-- Inventory
-- Picker
as opposed to:
UI
-- Inventory
---- Picker
not just that, I also have to anchor the picker to the bottom left and use the same code or just say:
rectTransform.anchoredPosition = Input.mousePosition;
I would like for the Picker to be a child of Inventory and not UI and still be able to follow the mouse position. The new UI isn't making it easy with all its pivot/anchors, etc concepts.
I thought initially I could just say:
picker.transform.position = Camera.main.ScreenToWorldPoint(Input.mousePosition);
but it's not that simple it seems...
Here's a video demonstrating the issue https://www.youtube.com/watch?v=TgCfF71OeT4 - notice how the picker doesn't follow the exact position of the cursor when I put it under Inventory.
What do I have to do to make the picker follow the mouse's exact position when the picker is a child of Inventory instead of UI?
Any help is greatly appreciated. Thanks.
NOTE: Inventory is anchored with 'middle - center' and has a pivot of '0, 1'
Like I mentioned if I parent the "Picker" under "Inventory" ins$$anonymous$$d of "UI" it won't follow the mouse's exact position, it become offsetted a bit. See the video
Thanks - this blog helped me code tooltips for Chicken Assassin $$anonymous$$aster of Humiliation :) :) :). Very helpful.
Answer by troien · Dec 08, 2014 at 01:43 PM
Well, if your Canvas its RenderMode is set to ScreenSpaceOverlay, this will actually do :p
transform.position = Input.mousePosition;
But sinse this breaks if you change the Canvas Render mode, the best way I found was
Vector2 pos;
RectTransformUtility.ScreenPointToLocalPointInRectangle(myCanvas.transform as RectTransform, Input.mousePosition, myCanvas.worldCamera, out pos);
transform.position = myCanvas.transform.TransformPoint(pos);
It feels like there should be a better way, but I'm not able to find another that works for all 3 RenderMode's yet. :( If you use a different render mode for your canvas (Like World Space), this code will only work if the 'Event Camera' of the Canvas is not null ;)
Thanks will try it out. See that's the thing that bugs men, there's hundreds of conversion methods and stuff that it just gets frustrating.
Can't believe I missed the simple position = mouse;
- Works when the picker is a child of UI or Inventory. THAN$$anonymous$$S!
But the question now is, why does it work? why does the simple position = mouse; work? i.e. why don't I need to do some crazy conversion shenanigans?
Because, when you set the Canvas Render$$anonymous$$ode to 'Screen space overlay'.
The Rect Transform's height and width are set to Screen.width and Screen.Height.
The x/y position is set to half the width/height.
Which basically means that the RectTransform it's values are set so that it is equal to Screen Space. (1 unit in Unity will be equal to 1 pixel, which is the reason why the canvas is so huge compared to the other objects in the Scene).
World position [0,0] will be in the lower left corner of the Rect of the canvas.
World position [Screen.width,Screen.height] will be at the upper right corner
Sinse Input.mousePosition is in screen space, no conversion is needed.
thanks, I couldn't get anything with positions to work with the canvas scaler. this fixed it :D
Answer by LordYabo · Feb 25, 2015 at 09:26 PM
My tooltip won't follow my mouse. It mostly follows it, but it's off.
After two hours of reading, trying crap with the canvas scaler, I found the 100% guaranteed way to do it when you have canvas scaler and screen space overlay:
CanvasScaler scaler = GetComponentInParent<CanvasScaler>();
thingToFollowMouse.anchoredPosition = new Vector2(Input.mousePosition.x * scaler.referenceResolution.x / Screen.width, Input.mousePosition.y * scaler.referenceResolution.y / Screen.height);
My reference resolution is 1920x1080 but when I run it in Unity it is 1200x675. I was surprised CanvasScaler.scaleFactor = 1f during runtime in these circumstances, I had thought that was the way to scale my mouse position..
This works well and it's nice and simple. If you're still having problems be sure to check that the aspect ratio of your editor window matches the aspect ratio of your reference resolution.
This solution worked perfect for me. Was able to use the second line of code to modify mouse position vectors I was using and gave me the desired behavior I was looking for. Thanks!
Just a re$$anonymous$$der in case anybody wants to follow this solution. Make sure that the object you want to follow the mouse position is anchored to the bottom left of the canvas, otherwise this solution wont work properly.
Answer by RChrispy · Jun 09, 2015 at 10:37 AM
Hey I stumbled across a similar problem and thought lets see where I can go. Made some Extensions vor the "CANVAS" you can try them out may be there are some bugs included I tested them only once!!!!! :D
If someone finds a bug or fixes it please post here. ( The names of the extensions are realy long but you know what it does XD )
#region Canvas
/// <summary>
/// Calulates Position for RectTransform.position from a transform.position. Does not Work with WorldSpace Canvas!
/// </summary>
/// <param name="_Canvas"> The Canvas parent of the RectTransform.</param>
/// <param name="_Position">Position of in world space of the "Transform" you want the "RectTransform" to be.</param>
/// <param name="_Cam">The Camera which is used. Note this is useful for split screen and both RenderModes of the Canvas.</param>
/// <returns></returns>
public static Vector3 CalculatePositionFromTransformToRectTransform(this Canvas _Canvas, Vector3 _Position, Camera _Cam)
{
Vector3 Return = Vector3.zero;
if (_Canvas.renderMode == RenderMode.ScreenSpaceOverlay)
{
Return = _Cam.WorldToScreenPoint(_Position);
}
else if (_Canvas.renderMode == RenderMode.ScreenSpaceCamera)
{
Vector2 tempVector = Vector2.zero;
RectTransformUtility.ScreenPointToLocalPointInRectangle(_Canvas.transform as RectTransform, _Cam.WorldToScreenPoint(_Position), _Cam, out tempVector);
Return = _Canvas.transform.TransformPoint(tempVector);
}
return Return;
}
/// <summary>
/// Calulates Position for RectTransform.position Mouse Position. Does not Work with WorldSpace Canvas!
/// </summary>
/// <param name="_Canvas">The Canvas parent of the RectTransform.</param>
/// <param name="_Cam">The Camera which is used. Note this is useful for split screen and both RenderModes of the Canvas.</param>
/// <returns></returns>
public static Vector3 CalculatePositionFromMouseToRectTransform(this Canvas _Canvas, Camera _Cam)
{
Vector3 Return = Vector3.zero;
if (_Canvas.renderMode == RenderMode.ScreenSpaceOverlay)
{
Return = Input.mousePosition;
}
else if (_Canvas.renderMode == RenderMode.ScreenSpaceCamera)
{
Vector2 tempVector = Vector2.zero;
RectTransformUtility.ScreenPointToLocalPointInRectangle(_Canvas.transform as RectTransform, Input.mousePosition, _Cam, out tempVector);
Return = _Canvas.transform.TransformPoint(tempVector);
}
return Return;
}
/// <summary>
/// Calculates Position for "Transform".position from a "RectTransform".position. Does not Work with WorldSpace Canvas!
/// </summary>
/// <param name="_Canvas">The Canvas parent of the RectTransform.</param>
/// <param name="_Position">Position of the "RectTransform" UI element you want the "Transform" object to be placed to.</param>
/// <param name="_Cam">The Camera which is used. Note this is useful for split screen and both RenderModes of the Canvas.</param>
/// <returns></returns>
public static Vector3 CalculatePositionFromRectTransformToTransform(this Canvas _Canvas, Vector3 _Position, Camera _Cam)
{
Vector3 Return = Vector3.zero;
if (_Canvas.renderMode == RenderMode.ScreenSpaceOverlay)
{
Return = _Cam.ScreenToWorldPoint(_Position);
}
else if (_Canvas.renderMode == RenderMode.ScreenSpaceCamera)
{
RectTransformUtility.ScreenPointToWorldPointInRectangle(_Canvas.transform as RectTransform, _Cam.WorldToScreenPoint(_Position), _Cam, out Return);
}
return Return;
}
#endregion