2
\$\begingroup\$

Problem

I have a spawn manager written in c# which spawns my game object, i use screen.width, to set the maximum screen with and -screen.width to set the minimum screen width for the spawning, but my game object spawns way off the screen.

I am using a portrait camera 2:3 instead of free aspect as my camera view, as i want my game to be in portrait mode

how do i make my game object spawn within the camera widths(max and min)?

my code

public class SpawnManager : MonoBehaviour {

    public int maxBalloons = 100;
    public GameObject balloon;
    public float horizontalMin = -Screen.width;
    public float horizontalMax = Screen.width;
    public float verticalMin = -5.0f;
    public float verticalMax = 1.0f;


    private Vector2 originPosition;


    void Start () {

        originPosition = transform.position;
        Spawn ();

    }

    void Spawn()
    {
        for (int i = 0; i < maxBalloons; i++)
        {
            Vector2 randomPosition = originPosition + new Vector2 (Random.Range(horizontalMin, horizontalMax), Random.Range (verticalMin, verticalMax));

            Instantiate(balloon, randomPosition, Quaternion.identity);
            originPosition = randomPosition;
        }
    }

}
\$\endgroup\$
  • \$\begingroup\$ If you're still looking for help on this, can you please specify whether your camera is orthographic or perspective? \$\endgroup\$ – DMGregory Mar 22 '18 at 12:28
  • \$\begingroup\$ my camera is orthographic \$\endgroup\$ – Kennedy May 13 '18 at 12:21
6
\$\begingroup\$

Screen.width and .height give you the current sizes of your game's display/window in pixels.

For positioning objects in our world, we want to work in worldspace units.

When you're using an orthographic camera, camera.orthographicSize gives you the verical half-height of the camera in world units (the distance from the center of the view to the top).

Multiplying that by the camera's width:height aspect ratio, camera.aspect, gives us our half-width in worldspace units.

So you can create your horizontalMin & Max like so:

Camera camera = Camera.main;
float halfHeight = camera.orthographicSize;
float halfWidth = camera.aspect * halfHeight;

horizontalMin = -halfWidth;
horizontalMax =  halfWidth;

For completeness, here's how you'd do it with a perspective camera that gets wider the further back in depth you go. For this we'll need an input depth value representing how far from the camera we want to spawn our objects, along the camera's forward vector.

float halfFieldOfView = camera.fieldOfView * 0.5f * Mathf.Deg2Rad;
float halfHeightAtDepth = depth * Mathf.Tan(halfFieldOfView);
float halfWidthAtDepth = camera.aspect * halfHeightAtDepth;

 // And the rest is the same.

Or you can just compute your desired position in viewport space (from (0,0) in the bottom-left of the camera's view to (1,1) at the top-right) and convert it o a world space position with Camera.ViewportToWorldPoint(), passing your desired depth as the third coordinate. This will automatically handle both perspective and orthographic cameras.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ error CS0236: A field initializer cannot reference the nonstatic field, method, or property thats the error i get \$\endgroup\$ – Kennedy May 24 '18 at 22:03
  • \$\begingroup\$ @Kennedy Don't do this in a field initializer. Do it inside a method. \$\endgroup\$ – DMGregory May 24 '18 at 22:19
  • \$\begingroup\$ please how can i do this \$\endgroup\$ – Kennedy May 24 '18 at 22:24
  • \$\begingroup\$ Make a method, maybe one like Vector3 GetRandomPointOnScreen() {...} and put your logic that computes the desired point inside that method. Then call it when you want a new random point. \$\endgroup\$ – DMGregory May 24 '18 at 22:26
  • \$\begingroup\$ Vector3 GetRandomPointOnScreen() { Camera camera = Camera.main; float halfHeight = camera.orthographicSize; float halfWidth = camera.aspect * halfHeight; float horizontalMin = -halfWidth; float horizontalMax = halfWidth; } what i did \$\endgroup\$ – Kennedy May 24 '18 at 23:25
0
\$\begingroup\$

You need to use Vector3 randomPosition = Camera.main.ScreenToWorldPoint(originPosition + new Vector2 (Random.Range(horizontalMin, horizontalMax), Random.Range (verticalMin, verticalMax))); or you can try Camera.main.ViewportToWorldPoint as well

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ still the same result \$\endgroup\$ – Kennedy Dec 25 '17 at 15:00
0
\$\begingroup\$

To find the "screen width" at the point of any transform, simply use this

using UnityEngine;
using System.Collections;

public static class ExtensionsMeasures {

    public static float NominalScreenWidthAt(this Camera c, Transform t) {
        float yFromCamera = t.transform.position.z - c.transform.position.z;

        return
            c.ViewportToWorldPoint(new Vector3(1f, 1f, yFromCamera)).x
            - c.ViewportToWorldPoint(new Vector3(0f, 1f, yFromCamera)).x;
    }

    public static float NominalScreenHeightAt(this Camera c, Transform t) {
        float yFromCamera = t.transform.position.z - c.transform.position.z;

        return
            c.ViewportToWorldPoint(new Vector3(0f, 1f, yFromCamera)).y
            - c.ViewportToWorldPoint(new Vector3(0f, 0f, yFromCamera)).y;
    }

Note that, of course, any such extension must work with any camera projection ...

conventional, orthographic or some custom frustum shape.

An example of using the call,

    layers = new List<Transform>();
    foreach (Transform t in transform) {

        layers.Add(t);
        float widthOfLayer = t.GetComponent<Renderer>().bounds.size.x;
        float widthOfScreenThere = Camera.main.NominalScreenWidthAt(t);
        Debug.Log("w layer, screen " + widthOfLayer + " " + widthOfScreenThere);

(Footnote - generally, avoid using Unity's hokey "Camera.main"; of course, you'd have the specific camera in question in a variable somehow.)

In almost all scrolling-type games (whether 2D, 3D or anything else) when the game launches you have the difficult issue of what to do about different physical device aspect ratios. (Players on wider screens will "see enemies sooner" that players on narrower screens, so to speak.) Whatever strategy you adopt to solve this difficult issue, the first step is always getting the screen width/height (at the position of your enemies, background, or whatever the case may be) and then adopting your approach to the problem.

| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.