Is there an easier way to convert from UI space to World Space? I feel like my solution is hacky at best.

So I have this cursor that is modified by user input. I found it strange that I had to subtract the vertical movement from it’s stored Y position, while adding the horizontal movement to the X, like so:

float h = Input.GetAxis ("Horizontal");
float v = Input.GetAxis ("Vertical");

xPos += Mathf.FloorToInt(h * speed);
yPos -= Mathf.FloorToInt(v * speed);  // Why do I have to subtract the Y instead of add???

Well, either way this was the solution that I finally found, but I feel like something is inherently wrong with it. Could one of the sages out there perhaps explain a better way? Or maybe I did it the right way on accident?

float diff = (Screen.height >> 1) - cursor.yPos;
float invertedDiff = diff + (Screen.height >> 1);

Vector3 pos = Camera.main.ScreenToWorldPoint(new Vector3(cursor.xPos, invertedDiff, 0));
    
pos.z = 0; // HACK?  I'm working in 2D.  Otherwise it converts to Z to -10
    
curPlayer.transform.position = pos;

Any help is appreciated. Many thanks in advance.

-BillyLemonZest

You could just use Input.mousePosition. :slight_smile:

Vector3 mouseWorldPos;

void Update()
{
	RaycastHit hit;
	Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
	Physics.Raycast(ray, out hit, Mathf.Infinity);
	mouseWorldPos = hit.point;
}

I take it you are trying to move a cursor which you have as an actual object in front of the camera and you want to do that with screen coordinates converted to the world coordinates?

You should not have to first substract the Y value and then invert it at all. The positive value of Y from your axis is probably up and the positive Y of the screen is also up so it should match.

So just doing this should work fine:

Vector3 pos = Camera.main.ScreenToWorldPoint(new Vector3(cursor.xPos, cursor.yPos, 0));
pos.z = 0;
 
curPlayer.transform.position = pos;

Do you get any specific odd results from this?

A note here on the Z value issue:
The Z value you supply in the ScreenToWorldPoint function refers to how far away from the camera you want the WorldPoint to be, so by supplying 0 there you will get the cameras actual world z value which is -10 in your case (which is a distance of 0 from the camera). Because you work in 2D as you say (and therefore probably orthographic camera), your “hack” works just fine with resetting the z value to be at 0 in the world.

There are four common coordinate systems in Unity: GUI, Screen, World and Viewport. Given that you are messing with the ‘Y’ value of your input position, I’m guessing you are drawing your cursor with GUI. You can convert from GUI to Screen by subtracting from Screen.height:

Vector3 posScreen = new Vector3 (posGUI.x, Screen.height - posGUI.y, 0.0);

As for the rest of your conversion code, The ‘z’ parameter in ScreenToWorldPoint() should be the distance in front of the camera. For what you are doing here, the distance is 10. Your method of setting ‘z’ to 0 after the conversion works because you are using an Orthographic camera, but it would fail with a perspective camera. So you will have something like:

posScreen.z = 10;  // Distance in front of the camera
Vector3 posWorld = Camera.main.ScreenToWorldPoint(posScreen); 

So you could make the conversion in two lines. Given a the GUI position:

Vector3 pos = new Vector3 (posGUI.x, Screen.height - posGUI.y, 10.0);
pos = Camera.main.ScreenToWorldPoint(pos);