- Home /
How can I define a box using Camera.ScreenToWorldPoint?
Alright, so what I'm trying to do with this script is to define a box (or rather, define a range of possible x and y coordinates) using Camera.ScreenToWorldPoint in a 2D game, as follows:
#pragma strict
var mainCam : Camera;
private var randomPointBox : Vector3 = new Vector3 (mainCam.ScreenToWorldPoint (new Vector3 (Screen.width * 1, 0, 0)).x, mainCam.ScreenToWorldPoint (new Vector3 (Screen.height *1, 0, 0)).y, 0);
private var pointB = Vector3;
function (Start)
{
pointB = new Vector3 (Random.Range (-randomPointBox.x, randomPointBox.x), Random.Range (-randomPointBox.y, randomPointBox.y), randomPointBox.z);
Debug.Log (pointB);
}
When I build or save the script, I get no errors, but when I attempt to drag my game object "MainCamera" into the "mainCam" variable I can't, initially anyway. If I create a prefab of the "MainCamera" game object, I can drag it in, but when I run the game, point B prints as (0.0, 0.0, 0.0), and I get a null reference exception:
NullReferenceException: Object reference not set to an instance of an object script..ctor () (at Assets/Scripts/Script.js:4)
which corresponds to line 4, my randomPointBox variable, and is therefore referring to "mainCam" not having an instance of the MainCamera, which makes total sense since I can only pull in the prefab of the main camera in the main Unity window.
I've watched a few tutorials where people use a similar technique, and just drag the main camera in from the hierarchy. What am I doing wrong?
Thanks again - I've only been with the Unity community for a few days and you've already been amazingly helpful. Hopefully soon I'll be able to start answering questions, not just asking them.
Answer by robertbu · Mar 13, 2014 at 11:44 PM
You have a number of issues here. The script above will not compile, which is likely why you could not do the drag and drop, or it could be the initialization you were attempting on line 4. Anyway, I believe this is where you are heading:
#pragma strict
var mainCam : Camera;
private var randomPointBox : Vector3;
private var pointB : Vector3;
function Start() {
randomPointBox = mainCam.ScreenToWorldPoint (Vector3 (Screen.width, Screen.height, 0));
pointB = new Vector3 (Random.Range (-randomPointBox.x, randomPointBox.x), Random.Range (-randomPointBox.y, randomPointBox.y), randomPointBox.z);
Debug.Log (pointB);
}
Note if you are using a perspective camera, you need to see the 'z' parameter of the Vector3 you pass to ScreenToWorldPoint() to a distance in front of the camera instead of 0.
Thanks so much, this works perfectly! Clearly I was just over-complicating things. The only change I made was to change the z location in pointB to 0 ins$$anonymous$$d of using the randomPointBox z value, as even with an orthographic camera it was returning a value of -10.0.
(For anyone checking up on this later, " mainCam.ScreenToWorldPoint (x, y, 0) " appears to always return the local z location of the camera in 3D space, no matter what projection is chosen on the camera or if the game project defaults are set to 2D or 3D.)
For clarification, would my script not compile because I initialized randomPointBox where I did, or because I seriously messed up the use of ScreenToWorldPoint?
The main thing I noticed was how you declared the Start() function. You have the '()' around Start rather than after Start. There are serious problems with doing the initialization on line 4 the way you did since it would try and execute this line before mainCam had a chance to be initialized by drag and drop, but that wouldn't stop a compile.
Oh dear, I don't even know how I managed that. I wrote the code at 4A$$anonymous$$ this morning, went to bed, got up, somehow managed to miss that problem - even until you pointed it out, and even while I was fixing it - and posted the question anyway. How embarrassing.
Thanks again!
Answer by Dep · Mar 13, 2014 at 11:44 PM
Now I did not understand what you are trying to achieve but here's two examples that might help you.
For further assistance, please specify your goal short and simple :)
using UnityEngine;
using System.Collections;
public class WorldPoint : MonoBehaviour {
public GameObject boxPrefab;
// Update is called once per frame
void Update () {
if (Input.GetMouseButtonDown(0))
{
ScreenToWorldPointTest();
ScreenPointToRayTest();
}
}
void ScreenToWorldPointTest()
{
// Note that the returned value will appear to be "behind" the camera due near clipping
// Also not very useful when using perspective projection
Debug.Log(Camera.main.ScreenToWorldPoint(Input.mousePosition));
}
void ScreenPointToRayTest()
{
// Cast a ray will hit whatever is under your mouse up to 100.0f and Instantiate a prefab there to make sure it works right
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if (Physics.Raycast(ray, out hit, 100.0f))
{
Instantiate(boxPrefab, hit.point, Quaternion.identity);
}
}
}
Thanks Dep, I actually figured it out using robertbu's answer, but I apologize if I was unclear when I explained it at the beginning. I was just trying to define a box using a Vector3 like this:
Vector 3 = x, y, z The box exists from -x to x and from -y to y, with z = 0 (it's just a 2d box)
And I wanted to do it using Camera.ScreenToWorldPoint so that the values of x and y in the Vector3 would change based on what the camera could see (for various aspect ratios/devices).
Then, the second part of my code just pulls a random point from that box (pointB) using Random.Range to pick from values between (x, -x) and (y, -y).