0
\$\begingroup\$

Potentially relevant points:

I'm using a perspective camera with a 70 degree x rotation so it is almost a top-down view but not quite 90 degrees.

Using OnGUI, I'm drawing a rectangle from the mouse click position to the current position of the mouse when click is being held down. This is for a standard kind of box or drag selecting that you see in RTS games or games with multiple unit selection. (I've been made aware of the problems with OnGUI, and will try to use some other method, but for the time being, let's assume OnGUI is okay). The rectangle gets drawn properly, no issues here.

I also have selectable objects in the game with selection indicators under them. When an object is selected, I activate the indicator, and when it becomes deselected, I deactivate it. My goal is just to get my box selection to activate the selection indicators of every selectable object that is contained in the drawn rectangle. If there are 5 units under that rectangle, I want each of their indicators to be activated.

I have a simple script attached to each selectable object which transforms its position from world space to screen space so I can test to see if its screen position is contained in the drawn rectangle. Debugging this Vector2 value shows that it's working properly. I'll get values like x = 230.5, y = 98.3965.

The problem:

Even though the objects are visibly inside of the rectangle, the test often fails. The indicators remain inactive. Now, sometimes it works, but it's highly inaccurate. I have to make big boxes and usually I can select the objects. Sometimes even this doesn't work and I have to scroll my camera to "center" the objects I'm trying to select. In other words, it's harder to select these objects if they are at the edge of the screen. Sometimes, my box doesn't even visibly contain an object, but it gets highlighted (if the box is big enough).

I've noticed that I might have a higher chance of selecting an object if I begin my box as close to 0,0 as possible and drag until I'm barely passed the objects. I'm really not sure why this is happening though since the rectangle always gets drawn properly, so it seems like it should always contain what is visibly underneath it, given that the object underneath it properly reports its screen coordinates. Also, if there is an issue with the screen space of the rectangle itself, I would think that it would not draw properly.

Box selection code:

public class BoxSelection : MonoBehaviour 
{
    Vector2 boxStartPos;
    Vector2 boxEndPos;
    Rect selectionArea;
    public Texture texture;

    // public for now to set references through inspector (change later)
    public List<GameObject> selectableObjects;

    void Update()
    {
        // if left mouse button is being clicked or held down
        if (Input.GetMouseButton(0))
        {
            // called on the first update in which the left mouse button is clicked
            if (Input.GetMouseButtonDown(0))
            {
                boxStartPos = Input.mousePosition;
            }
            // called on all other updates in which the left mouse button is held down
            else
            {
                boxEndPos = Input.mousePosition;
            }

            selectionArea = new Rect(boxStartPos.x, Screen.height - boxStartPos.y, 
                                     boxEndPos.x - boxStartPos.x, -1 * ((Screen.height - boxStartPos.y) - (Screen.height - boxEndPos.y)));
        }
        // if left mouse button is neither being clicked nor held down
        else 
        {
            // handle unit selection
            Debug.Log(selectionArea);

            foreach (GameObject selectableObject in selectableObjects)
            {
                WorldSpaceToScreenSpace worldSpaceToScreenSpace = selectableObject.GetComponent<WorldSpaceToScreenSpace>();
                GameObject selectionIndicator = selectableObject.transform.Find("Selection Indicator").gameObject;

                if (selectionArea.Contains(worldSpaceToScreenSpace.screenCoordinates, true))
                {
                    selectionIndicator.SetActive(true);
                }
            }
            // Reset box positions
            boxStartPos = Vector2.zero;
            boxEndPos = Vector2.zero;
        }
    }

    void OnGUI()
    {
        // if box positions are not zero
        if (boxStartPos != Vector2.zero && boxEndPos != Vector2.zero)
        {
            Color textureColor = GUI.color;
            textureColor.a = 0.25f;
            GUI.color = textureColor;

            GUI.DrawTexture(selectionArea, texture);
        }
    }
}

Screen position code:

public class WorldSpaceToScreenSpace : MonoBehaviour 
{
    public Vector2 screenCoordinates;

    void Update()
    {
        screenCoordinates = Camera.main.WorldToScreenPoint(transform.position);
    }
}
\$\endgroup\$
  • 1
    \$\begingroup\$ I recommend ditching OnGui and using the new UI. Also, post some code. \$\endgroup\$ – Draco18s Jul 21 '17 at 2:25
  • 1
    \$\begingroup\$ This will be difficult for us to debug without your screen position and selection box code. \$\endgroup\$ – DMGregory Jul 21 '17 at 3:02
  • \$\begingroup\$ @DMGregory Edited and added code. \$\endgroup\$ – embracethefuture Jul 21 '17 at 3:39

Your Answer

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

Browse other questions tagged or ask your own question.