How to place randomly scattered UI elements in screen through scripts?

I am trying to scatter UI elements in screen.

so I did this:

            for (int i = 0; i < posts.Length; i++)
                bubble = Resources.Load("Prefabs/Bubbles") as GameObject;

                bubble.GetComponentInChildren<Text>().text = posts*.postContent;*

bubble.GetComponent().anchorMin = new Vector2(0.5f, 0.5f);
bubble.GetComponent().anchorMax = new Vector2(0.5f, 0.5f);
bubble.GetComponent().pivot = new Vector2(0.5f, 0.5f);

GameObject myBubble = Instantiate(bubble, new Vector3(Random.Range(-Screen.width, Screen.width), Random.Range(-Screen.height, Screen.height), Random.Range(-14, 0)), Quaternion.identity) as GameObject;
myBubble.transform.SetParent(panel.transform, false);
Inspector for Main Camera:
Inspector for Canvas:
But everytime I run it in Game scene, UI elements are placed out of my screen. What am I missing?

You need to transfrom the screen pixels to world(3d) vector.

Camera.ScreenToViewportPoint documenation

If the bottom left is pixel x: 0 and pixel y: 0, then you need to adjust your randomness and transform it in your instantiate call.

GameObject myBubble = Instantiate(bubble, new Vector3(Camera.main.ScreenToViewportPoint(Random.Range(0, Screen.width)), Camera.main.ScreenToViewportPoint(Random.Range(0, Screen.height),) Random.Range(-14, 0)), Quaternion.identity) as GameObject;

also not sure why z is being affected in the above call when it’s 2d elements…

I built something for this matter not long ago.
The main idea was to create a UI panel scaled with screen size (so the grid would fit any screen) and just spawn randomly in any of the boxes (I think I had a sort of list of any boxes, you count it down and you have your “random.range”)
Then you just have to spawn at “box.position”.

The real cool thing about it is that you can visualize your different spawn points, and that you can see them scaled with screen sizes.

Hope it helps.

as @Landern pointed out, you need to transfrom the screen coordinates to world coordinates. For this conversion we will use the ScreenToWorldPoint method. This method takes screen coordinates not in a Vector2 format (as you would expect for the screen xy plane), but actually it also requires a “z” value that measure the z-distance to the camera position. This is because your UI camera is a perspective camera, and thus perspective projection applies from world → screen and screen-> world. In this projection what happens is that infinite number of world points are projected into the same screen point, therefore going backwards, if you request a world point from a screen point, without any other information, unity doesn’t know which world point associated to that screen point is the one you want. That is why the “z” component is needed.

If you have setup your camera, lets say at (0,0,-20), then requesting

Vector3 worldpos = camera.ScreenToWorldPoint( new Vector3(x,y,10) );

means that from the screen coordinates (x,y) the worldpos that you want, is the one that has a distance from the camera of 10. Since the camera is -20, worldpos will have z=-20+10 =-10.

So coming back to your problem, you have:

new Vector3(Random.Range(-Screen.width, Screen.width), Random.Range(-Screen.height, Screen.height), Random.Range(-14, 0))

That has two problems:

  1. you are not using ScreenToWorldPoint as mentioned before.
  2. you are using Random.Range(-14, 0), but your camera is also at (0,0,0) so some points will be actually be positioned at the same depth as the camera, which in this case will not be rendered (will be out of the view frustum)

To address both problems I will suggest to try something like this:

float UIPlaneZDepth = 10; //change as needed 

Vector3 randomScreenPos = new Vector3(Random.Range(0,Screen.width), Random.Range(0, Screen.height), Random.Range(UIPlaneZDepth, UIPlaneZDepth + 14));

Vector3 randomWorldPos = Camera.ScreenToWorldPoint(randomScreenPos);

GameObject myBubble = Instantiate(bubble, randomWorldPos, Quaternion.identity) as GameObject;

As a final note, the line:

myBubble.transform.SetParent(panel.transform, false);

is correctly being used to place the new UI Object in the canvas hierarchy while maintaining the world position. So that is not your problem.