Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

RTS Style Selector

Discussion in 'Scripting' started by ubormaci, Oct 23, 2019.

  1. ubormaci

    ubormaci

    Joined:
    Oct 21, 2019
    Posts:
    1
    I'd like to make an RTS Style Selector to my game, but I don't have many experience in programming, so questioned google, but everything he gave me was very complicated. So, just wanted to know, if you have an easy solution for this.
     
  2. Boz0r

    Boz0r

    Joined:
    Feb 27, 2014
    Posts:
    419
    You'll have to explain what you mean with RTS Style Selector. Do you mean to drag and draw a rectangle, and select all units in that rectangle?
     
  3. MadeFromPolygons

    MadeFromPolygons

    Joined:
    Oct 5, 2013
    Posts:
    3,875
    There isnt really an 'easy' solution for that, if by easy you mean not using a lot of programming. Your going to have to write some code to get it done, with some problem solving done on your part. That said, I can outline what you need to do so that you have an easier time breaking it down into google-able queries :)

    The easiest solution would be to create some sort of bounding box in world space based on the box that is drawn and then get anything inside of that box and "select" them.

    Break it down into steps:

    1. Get point on screen user has clicked

    2. Determine delta (difference from original) from initial click point to determine if a drag was initiated

    3. Draw a box from initial click to current position, you will have to work out what to use as corners based on drag direction

    4. Now that you have a box in screen space, convert those corner positions to world space (potentially using raycasting or something similar) so that you have them as points on the "ground" in the world instead of on the screen

    5. Use the worldspace corner positions to generate a bounding box. Give it a very high height so it catches everything including units in the air.

    6. Use that bounding box to test for anything intersecting it or contained within it and add to a list.

    7. Use that list to iterate through and select each unit, using whatever selection function you have created in your unit scripts. For testing just set them another color or something easy to see.


    That may not be most performant way but itll work. None of the concepts I have outlined above are too difficult, and you will be able to find various examples and tutorials for each step by googling them. Good luck :)
     
    SparrowGS likes this.
  4. SparrowGS

    SparrowGS

    Joined:
    Apr 6, 2017
    Posts:
    2,536
    easy solution - buy a RTS kit on the asset store

    or spend some time learning how to do it, I got a working prototype for this (I think you mean the interface for single click selection, hold shift to add, click & drag to box select, etc.) in a couple of hours after researching this for about an hour.

    if you want i can plop some code, but it wouldn't be of any use to you, it's not a plug and play type deal here.
     
    MadeFromPolygons likes this.
  5. Lethn

    Lethn

    Joined:
    May 18, 2015
    Posts:
    1,583
    Code Monkey did a tutorial on this feature, it's not an 'easy' mechanic to implement.

     
  6. Mortalanimal

    Mortalanimal

    Joined:
    Jun 7, 2014
    Posts:
    558
    Code Monkey Advised me to avoid ECS as a noob. I managed to do what the OP is asking for as a noob, but it wasnt easy and it took a lot of head smashing against the wall. And it took a lot of help from this forum.
     
  7. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,741
    I see this all the time in "how do I make an RTS" threads (which are incredibly common), and it's entirely backwards. Converting screenspace coordinates to a worldspace box is mathematically difficult, computationally inefficient, and from the user's perspective will be very flaky (especially if you actually use 3 dimensions - flying units would be an absolute nightmare. Users would need to drag-select their shadows rather than the units - gross)

    Instead, convert your units' coordinates to screen space, and then just use rect.Contains to determine if they are selected.
     
    MadeFromPolygons and Boz0r like this.
  8. Boz0r

    Boz0r

    Joined:
    Feb 27, 2014
    Posts:
    419
    I'll go out on a limb here and say that converting two screenspace coordinates to world space is cheaper than converting N world space coordinates to screenspace. But I'd agree that it would be a more intuitive behavior.
     
    MadeFromPolygons likes this.
  9. Mortalanimal

    Mortalanimal

    Joined:
    Jun 7, 2014
    Posts:
    558

    Its a good thing I wont be Using any flying units :D
     
  10. blu3drag0n

    blu3drag0n

    Joined:
    Nov 9, 2018
    Posts:
    94
    This is an old post, but when I was looking for a solution to get a selection rectangle drawing in game mode, also in a build version, then there were not really satisfying answers. Most tried via some assets packages or either Line Renderer or Shaders, which I found to be overloaded for what I was trying to achieve.

    I finally managed to build it myself with very few code and want to share for everyone else googling in the future, enjoy:
    Code (CSharp):
    1.  
    2. using UnityEngine;
    3. /// <summary>
    4. /// Draws a selection rectangle on the left mouse button down & dragging
    5. ///
    6. /// You only need an InputReceiverManager that basically tracks
    7. /// - if the left mouse button is currently down and saves it in "LeftMouseButtonDown"
    8. /// - saves the initial click position when mouse button was clicked  and saves it in "InitialMousePositionOnLeftClick"
    9. /// - updates the current mouse position and saves it in "CurrentMousePosition"
    10. ///
    11. /// </summary>
    12. public class SelectionRectangleDrawer : MonoBehaviour
    13. {
    14.     //set color via inspector for the selection rectangles filler color
    15.     public Color SelectionRectangleFillerColor;
    16.     //set color via inspector for the selection rectangles border color
    17.     public Color SelectionRectangleBorderColor;
    18.     //set selection rectangles  border thickness
    19.     public int SelectionRectangleBorderThickness = 2;
    20.     private Texture2D _selectionRectangleFiller;
    21.     private Texture2D _selectionRectangleBorder;
    22.     private bool _drawSelectionRectangle;
    23.     private float _x1, _x2, _y1, _y2;
    24.     private Vector2 pos1, pos2;
    25.     void Start()
    26.     {
    27.         _selectionRectangleFiller = new Texture2D(1, 1);
    28.         _selectionRectangleFiller.SetPixel(0, 0, SelectionRectangleFillerColor);
    29.         _selectionRectangleFiller.Apply();
    30.         _selectionRectangleFiller.wrapMode = TextureWrapMode.Clamp;
    31.         _selectionRectangleFiller.filterMode = FilterMode.Point;
    32.         _selectionRectangleBorder = new Texture2D(1, 1);
    33.         _selectionRectangleBorder.SetPixel(0, 0, SelectionRectangleBorderColor);
    34.         _selectionRectangleBorder.Apply();
    35.         _selectionRectangleBorder.wrapMode = TextureWrapMode.Clamp;
    36.         _selectionRectangleBorder.filterMode = FilterMode.Point;
    37.     }
    38.     void Update()
    39.     {
    40.         if (InputReceiverManager.Instance.LeftMouseButtonDown && !Mathf.Approximately(Vector2.Distance(InputReceiverManager.Instance.CurrentMousePosition,
    41.                                                                                                        InputReceiverManager.Instance.InitialMousePositionOnLeftClick), 0f))
    42.             _drawSelectionRectangle = true;
    43.         else if (!InputReceiverManager.Instance.LeftMouseButtonDown && _drawSelectionRectangle)
    44.             _drawSelectionRectangle = false;
    45.     }
    46.     private void OnGUI()
    47.     {
    48.         if (_drawSelectionRectangle)
    49.             drawSelectionRectangle();
    50.     }
    51.     private void drawSelectionRectangle()
    52.     {
    53.         pos1 = InputReceiverManager.Instance.InitialMousePositionOnLeftClick;
    54.         pos2 = InputReceiverManager.Instance.CurrentMousePosition;
    55.         //check initial mouse position on X axis versus dragging mouse position
    56.         if (pos1.x < pos2.x)
    57.         {
    58.             _x1 = pos1.x;
    59.             _x2 = pos2.x;
    60.         }
    61.         else
    62.         {
    63.             _x1 = pos2.x;
    64.             _x2 = pos1.x;
    65.         }
    66.         //check initial mouse position on Y axis versus dragging mouse position
    67.         if (pos1.y < pos2.y)
    68.         {
    69.             _y1 = pos1.y;
    70.             _y2 = pos2.y;
    71.         }
    72.         else
    73.         {
    74.             _y1 = pos2.y;
    75.             _y2 = pos1.y;
    76.         }
    77.         //filler
    78.         GUI.DrawTexture(new Rect(_x1, Screen.height - _y1, _x2 - _x1, _y1 - _y2), _selectionRectangleFiller, ScaleMode.StretchToFill);
    79.         //top line
    80.         GUI.DrawTexture(new Rect(_x1, Screen.height - _y1, _x2 - _x1, -SelectionRectangleBorderThickness), _selectionRectangleBorder, ScaleMode.StretchToFill);
    81.         //bottom line
    82.         GUI.DrawTexture(new Rect(_x1, Screen.height - _y2, _x2 - _x1, SelectionRectangleBorderThickness), _selectionRectangleBorder, ScaleMode.StretchToFill);
    83.         //left line
    84.         GUI.DrawTexture(new Rect(_x1, Screen.height - _y1, SelectionRectangleBorderThickness, _y1 - _y2), _selectionRectangleBorder, ScaleMode.StretchToFill);
    85.         //right line
    86.         GUI.DrawTexture(new Rect(_x2, Screen.height - _y1, -SelectionRectangleBorderThickness, _y1 - _y2), _selectionRectangleBorder, ScaleMode.StretchToFill);
    87.     }
    88. }
    89.  
    90.  
    91.