Search Unity

Rts unit selection problem

Discussion in 'Scripting' started by tet2brick, Nov 30, 2010.

  1. tet2brick

    tet2brick

    Joined:
    Jun 24, 2009
    Posts:
    77
    Hi guys,

    I found very little posts about selecting multiple units with a rectangle like in many rts.

    I used a script (heavily ^^) based on this one :
    http://forum.unity3d.com/threads/17634-C-amp-C-style-RTS-Community-Project-Generals

    To be short, a 2D GUI rectangle is drawed, two ray are fired, one from the top left corner of this rectangle, another from the bottom right corner, a unit is selected if it is between the x and z of the two rays. And it work quite well :)

    But there is a problem, if I rotate the camera on the Y axis (or any axis actually), the selection is not accurate anymore... (to be exact, if I rotate the camera to an angle other than 0, 90, 180, 270), I mean if a unit is in the 2D rectangle when the angle is not multiple of 90, sometime the unit is not selected, an sometime a unit outside of it is selected (more often on the fringes of the selection), If I pause the game and test the ray hit positions, it's normal, the units are not between them. But visually they are in the 2d rectangle.

    Do you have an idea how to correct it? (I suck at math, I think that's the main problem. :p)

    I was also thinking to put a cube with a collider and a triggered script on it, but I don't know how to make it match the 2D GUI rectangle shape.

    Thanks in advance ;)
     
  2. pakfront

    pakfront

    Joined:
    Oct 6, 2010
    Posts:
    551
    An idea:
    Do a SphereCastAll or (just use a Physics.OverlapSphere ) that entirely covers the selected area
    then test the returned hit objects screen coords using Camera.WorldToScreenPoint to make sure they are in the given rectangle.

    If you have a small list of selectable, then you could probably skip the Sphere test,

    I have to handle this case as well at some point in the future so am interested in what you find out.
     
  3. tet2brick

    tet2brick

    Joined:
    Jun 24, 2009
    Posts:
    77
    Hi,

    Thanks for your idea :)

    it didn't work as I hoped, the WorldToScreenPoint return positions outside the rectangle as well...

    But I found a solution, the four corners of my rectangle in 2D space create by raycasting the 4 courners a polygon (a trapezoid) in 3D world space, I just used a function (founded as is on the net) to know if a given point is in a polygon defined by an array of points.

    So I iterate trought an array with all my units, test them with the function, and if they are in the polygon, they are selected.

    And it work, if the unit is in the 2D gui rect, it's selected. I'm happy :D

    Here is the complete code I use :

    Code (csharp):
    1. //the mouse position when the user move it ("bottom right" corner of the rect if you start from left to right and from top to bottom)
    2. private var mouseButton1DownPoint : Vector2;
    3. //the mouse position where the user first click ("top left" corner of the rect if you start from left to right and from top to bottom)
    4. private var mouseButton1UpPoint : Vector2;
    5.  
    6. //the world position of the 4 corners
    7. private var topLeft : Vector3;
    8. private var topRight : Vector3;
    9. private var bottomLeft : Vector3;
    10. private var bottomRight : Vector3;
    11.  
    12. //the pointer moved where the user right-click (for moving unit(s))
    13. var target : Transform;
    14.  
    15. //the list of selected units
    16. private var listSelected = new Array ();
    17.  
    18. //the list of ALL units in the scene
    19. private var listAllUnits = new Array ();
    20.  
    21. private var hit:RaycastHit;
    22.  
    23. //boolean to know if the left mouse button is down
    24. private var leftButtonIsDown : boolean = false;
    25.  
    26. //cube placed at the 4 corner of the polygon, for visual debug
    27. private var topLeftCube;
    28. private var bottomRightCube;
    29. private var topRightCube;
    30. private var bottomLeftCube;
    31.  
    32. //the layer mask for walkable zones
    33. private  var layerMask = 1 << 9;
    34. //the layer mask for selectable objects
    35. private var selectableLayerMask = 1 << 10;
    36.  
    37. //width and height of the 2D rectangle
    38. var width : int;
    39. var height : int;
    40.  
    41. var debugMode : boolean = false;
    42.  
    43. var selectionTexture : Texture;
    44.  
    45. // range in which a mouse down and mouse up event will be treated as "the same location" on the map.
    46. private var mouseButtonReleaseBlurRange : int = 20;
    47.  
    48. function OnGUI() {
    49.     if (leftButtonIsDown) {
    50.        
    51.         width = mouseButton1UpPoint.x - mouseButton1DownPoint.x;
    52.         height = (Screen.height - mouseButton1UpPoint.y) - (Screen.height - mouseButton1DownPoint.y);
    53.         var rect : Rect = Rect(mouseButton1DownPoint.x, Screen.height - mouseButton1DownPoint.y, width, height);
    54.         GUI.DrawTexture (rect, selectionTexture, ScaleMode.StretchToFill, true);       
    55.        
    56.     }
    57. }
    58.  
    59.  
    60. function Start()
    61. {
    62.    
    63.     if(debugMode)
    64.     {
    65.         topRightCube = GameObject.Find("topRight").transform;  
    66.         bottomLeftCube = GameObject.Find("bottomLeft").transform;  
    67.         topLeftCube = GameObject.Find("topLeft").transform;
    68.         bottomRightCube = GameObject.Find("bottomRight").transform;
    69.     }
    70.    
    71. }
    72.  
    73. function Update () {
    74.  
    75.     if (Input.GetButtonDown ("Fire1"))
    76.     {
    77.         //if left button is down, save the mouse position, set the leftButtonIsDown to true and save the world position of the rectangle's "top left" corner
    78.         mouseButton1UpPoint=Input.mousePosition;
    79.         leftButtonIsDown = true;
    80.         Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition),  hit, 1000);
    81.         topLeft = hit.point;       
    82.     }
    83.    
    84.     if (Input.GetButtonUp ("Fire1"))
    85.     {
    86.         //if left button is up set the leftButtonIsDown to false
    87.         leftButtonIsDown = false;
    88.        
    89.         //if the range is not big enough, it's a simple clic, not a dragg-select operation
    90.         if (IsInRange(mouseButton1DownPoint, mouseButton1UpPoint))
    91.         {      
    92.             // user just did a click, no dragging. mouse 1 down and up pos are equal.
    93.             // if units are selected, move them. If not, select that unit.
    94.             if (GetSelectedUnitsCount() == 0)
    95.             {
    96.                 // no units selected, select the one we clicked - if any.
    97.                
    98.                 if ( Physics.Raycast (Camera.main.ScreenPointToRay (mouseButton1DownPoint), hit, 1000, selectableLayerMask) )
    99.                 {
    100.                     // Ray hit something. Try to select that hit target.
    101.                     //print ("Hit something: " + hit.collider.name);
    102.                     AddSelectedUnit(hit.collider.gameObject);
    103.                 }
    104.                                
    105.             }
    106.         }
    107.        
    108.     }
    109.    
    110.     if (Input.GetButtonUp ("Fire2"))
    111.     {
    112.         //right click, move the pointer to the position
    113.         if(Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition),  hit, 1000,layerMask))
    114.         {      
    115.             target.position=hit.point;
    116.             target.position.y=0;
    117.             //todo : move the selected units to the position of the pointer.
    118.         }
    119.        
    120.    
    121.     }
    122.    
    123.     //if the left button is down and the mouse is moving, start dragging
    124.    
    125.     if(leftButtonIsDown)
    126.     {
    127.         //actual position of the mouse
    128.         mouseButton1DownPoint=Input.mousePosition;
    129.        
    130.         //set the 3 other corner of the polygon in the world space
    131.         Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition),  hit, 1000);
    132.         bottomRight = hit.point;
    133.                
    134.         Physics.Raycast(Camera.main.ScreenPointToRay(Vector2(Input.mousePosition.x+width,Input.mousePosition.y)),  hit, 1000);
    135.         bottomLeft= hit.point;
    136.                
    137.         Physics.Raycast(Camera.main.ScreenPointToRay(Vector2(Input.mousePosition.x,Input.mousePosition.y-height)),  hit, 1000);
    138.         topRight= hit.point;
    139.        
    140.         ClearSelectedUnitsList();      
    141.         SelectUnitsInArea();
    142.        
    143.         if(debugMode)
    144.         {
    145.             bottomRightCube.position = bottomRight;
    146.             topRightCube.position = topRight;
    147.             bottomLeftCube.position = bottomLeft;
    148.             topLeftCube.position = topLeft;    
    149.         }
    150.        
    151.     }
    152.        
    153.        
    154.        
    155.  
    156. }
    157.  
    158.  
    159.  
    160. function AddSelectedUnit(unitToAdd : GameObject) {
    161.     listSelected.Push(unitToAdd);
    162.     unitToAdd.GetComponent(pathTest).setSelectCircleVisible(true); 
    163. }
    164.  
    165. function ClearSelectedUnitsList() {
    166.    
    167.     for (var unitToClear : GameObject in listSelected) {
    168.         unitToClear.GetComponent(pathTest).setSelectCircleVisible(false);  
    169.     }
    170.     listSelected.Clear();
    171. }
    172.  
    173. function fillAllUnits(unitToAdd : GameObject)
    174. {
    175.     listAllUnits.Add(unitToAdd);
    176. }
    177.  
    178. function SelectUnitsInArea() {
    179.     var poly = new Array();
    180.    
    181.     //set the array with the 4 points of the polygon
    182.     poly[0] =  topLeft;
    183.     poly[1] = topRight;
    184.     poly[2] = bottomRight;
    185.     poly[3] = bottomLeft;
    186.    
    187.     //iterate trough the all unit's array
    188.     for (var go : GameObject in listAllUnits) {
    189.         var goPos : Vector3 = go.transform.position;
    190.         //if the unit is in the polygon, select it.
    191.         if (isPointInPoly(poly, goPos))
    192.         {
    193.             AddSelectedUnit(go);
    194.         }
    195.     }
    196. }  
    197.  
    198.  
    199. //math formula to know if a given point is inside a polygon
    200. function isPointInPoly(poly, pt){
    201.     var c = false;
    202.      l = poly.length;
    203.      j = l - 1;
    204.      
    205.     for(i = -1 ; ++i < l; j = i){      
    206.         if(((poly[i].z <= pt.z  pt.z < poly[j].z) || (poly[j].z <= pt.z  pt.z < poly[i].z))
    207.          (pt.x < (poly[j].x - poly[i].x) * (pt.z - poly[i].z) / (poly[j].z - poly[i].z) + poly[i].x))
    208.         c = !c;
    209.         }
    210.     return c;
    211. }
    212.  
    213. function GetSelectedUnitsCount() {
    214.     return listSelected.length;
    215. }
    216.  
    217. function IsInRange(v1 : Vector2, v2 : Vector2) : boolean {
    218.     var dist = Vector2.Distance(v1, v2);
    219.    
    220.     if (Vector2.Distance(v1, v2) < mouseButtonReleaseBlurRange) {
    221.         return true;
    222.     }
    223.     return false;
    224. }
    So this script needs to be putted on a gameobject in the scene (most probably an empty one ;) ), I named mine "FrameListener"

    And on each selectable unit you have to put in a start function somewhere this part of code :

    Code (csharp):
    1. var frameListener = GameObject.Find("FrameListener");
    2.            
    3.         frameListener.GetComponent (FrameListenerScript).fillAllUnits(this.gameObject);
    Hope it can help someone
     
  4. pakfront

    pakfront

    Joined:
    Oct 6, 2010
    Posts:
    551
    Thanks for posting that.

    My think was that yes, it would return some objects outside the selection rectangle, but you would iignore those by testing all points to see if they are inside the rectangle. Did this not work?
     
  5. tet2brick

    tet2brick

    Joined:
    Jun 24, 2009
    Posts:
    77
    No prob, this script is very basic, it can be optimized ;)

    Not like I wanted, some objects visibly within the rectangle return a point outside the rectangle, so that was the same problem as before :)
     
  6. jpeele

    jpeele

    Joined:
    Apr 5, 2012
    Posts:
    7
    I know this thread is dead, but this script works really well. I'm using it for one of my own projects, so I brought the script over to C#, and added some features. Hope someone will find this useful

    Code (csharp):
    1. //C# conversion from tet2bricks original code, by Jonah Peele
    2.  
    3.  
    4. //All selectable units need need to have the script below attached to them or they won't be checked
    5. /*    ---Selectable.CS---
    6. using UnityEngine;
    7. using System.Collections;
    8. public class Selectable : MonoBehaviour
    9. {
    10.     public void Start()
    11.     {
    12.         StartCoroutine("braodcstSelectablility");
    13.     }
    14.     public IEnumerator braodcstSelectablility( )
    15.     {
    16.         yield return new WaitForSeconds(0.1F);
    17.        
    18.         foreach ( Object o in GameObject.FindObjectsOfType(typeof(GameObject)) ){
    19.             GameObject go = (GameObject) o;
    20.             go.SendMessage("fillAllUnits", this.gameObject, SendMessageOptions.DontRequireReceiver);
    21.         }
    22.     }
    23. }
    24. *///end--Selectable.CS---
    25. //note: if we dont make selectable yield, there is a chance selectable gameObjects will try to register themselves,
    26. //      before the _allUnits List has been intialized.
    27.  
    28. //TODO: make the debug code instatiate new cubes on runtime rather than trying to find them in scene
    29. //TODO: clean up the sendMeassage calls with faster methods once we have locked down our unit manager code
    30.  
    31. using UnityEngine;
    32. using System.Collections;
    33. using System.Collections.Generic;
    34.  
    35. public enum MouseButton { Left, Right } //there is a more elgant way to handle enums attached thier members
    36. public enum MouseFunction { MarqueeSelection, Click, ClickDrag }
    37. public enum MarqueeType { Texture2d, EmptyBox, None }
    38.  
    39. public class MouseButtonObserver : MonoBehaviour
    40. {
    41.    
    42.     public MouseButton WhichButton = MouseButton.Left;
    43.     public string ButtonName {
    44.         get {
    45.             switch ( WhichButton ) {
    46.             case MouseButton.Left:
    47.                 return "Fire1";
    48.                 break;
    49.             case MouseButton.Right:
    50.                 return "Fire2";
    51.                 break;
    52.             default:
    53.                 return "Fire1";
    54.             }
    55.         }
    56.     }
    57.     //private bool IsUnitSelector = true;// anitquated
    58.     public MouseFunction MouseFunctionType = MouseFunction.Click;
    59.     public MarqueeType Marquee;
    60.     private Vector2 downLocation;
    61.     private Vector2 startDragLocation;
    62.     private Vector2 upLocation;
    63.    
    64.     //these are for the position of the selection coreners
    65.     private Vector3 _topLeft;
    66.     private Vector3 _topRight;
    67.     private Vector3 _bottomLeft;
    68.     private Vector3 _bottomRight;
    69.    
    70.     private bool _isDragging = false;
    71.     public bool isDragging {
    72.         get { return _isDragging; }
    73.         set {
    74.             if ( _isDragging != value ){
    75.                 _isDragging = value;
    76.                 //DebugStreamer.message = ButtonName + " isDragging = " + _isDragging.ToString() ;
    77.             }
    78.         }
    79.     }
    80.     private bool _isDown = false;
    81.     //public GameObject debugStreamer;
    82.     public bool isDown {
    83.         get { return _isDown; }
    84.         set {
    85.             if (_isDown != value) {
    86.                 _isDown = value;
    87.                 //DebugStreamer.message = ButtonName + " isDown = " + _isDown.ToString() ;
    88.             }
    89.         }      
    90.     }
    91.    
    92.     //for debug
    93.     private Transform topLeftCube;
    94.     private Transform bottomRightCube;
    95.     private Transform topRightCube;
    96.     private Transform bottomLeftCube;
    97.    
    98.     public int DragDither = 20;
    99.     public Color OutlineColor;
    100.     public Texture2D MarqueeTexture;
    101.     public GameObject MouseButtonListener;
    102.    
    103.     private float width() { return startDragLocation.x - upLocation.x; }
    104.     private float height() { return (Screen.height - startDragLocation.y) - (Screen.height - upLocation.y); }
    105.    
    106.     public List<GameObject> _selectedUnits;// = new List<GameObject>();
    107.     public int GetSelectedUnitsCount() { return _selectedUnits.Count; }
    108.     public List<GameObject> GetSelectedUnits() { return _selectedUnits; }
    109.    
    110.     private List<GameObject> _allUnits;//this bugs out when its set to private because it initializes too late
    111.     public void fillAllUnits( GameObject unitToAdd ) {
    112.         _allUnits.Add(unitToAdd);
    113.         NumberOfSelectableUnitsInScene = _allUnits.Count;
    114.         //DebugStreamer.message = "unit added:" + unitToAdd.ToString();
    115.     }
    116.     public int NumberOfSelectableUnitsInScene;
    117.     public bool DebugMode = false;
    118.    
    119.     private RaycastHit hit = new RaycastHit();
    120.     private Texture2D whiteTex ;
    121.    
    122.     private Vector3 ClickDragStart;
    123.     private Vector3 ClickDragEnd;
    124.     private Ray _clickDragRay;
    125.     public Ray ClickDragray { get { return _clickDragRay; } }
    126.    
    127.     public void Awake()
    128.     {
    129.         _allUnits = new List<GameObject>();
    130.     }
    131.     public void Start()
    132.     {
    133.         _allUnits = new List<GameObject>();
    134.         _selectedUnits = new List<GameObject>();
    135.         if( !MouseButtonListener ){ Debug.LogWarning("No Listener assigned to " + this );}  
    136.        
    137.         whiteTex = new Texture2D(1,1);
    138.         whiteTex.SetPixel(0,0, new Color(1,1,1,1));
    139.         whiteTex.Apply();
    140.        
    141.         if (DebugMode)
    142.         {
    143.             topRightCube = GameObject.Find("topRight").transform;  
    144.             bottomLeftCube = GameObject.Find("bottomLeft").transform;  
    145.             topLeftCube = GameObject.Find("topLeft").transform;
    146.             bottomRightCube = GameObject.Find("bottomRight").transform;
    147.         }
    148.     }
    149.    
    150.    
    151.    
    152.     public MouseButtonObserver( MouseButton newButton, /*string buttonName,*/ Texture2D marquee )
    153.     {
    154.         WhichButton = newButton;
    155.         //ButtonName = buttonName;
    156.         MarqueeTexture = marquee;
    157.     }
    158.    
    159.     public void Update()
    160.     {
    161.         switch (MouseFunctionType)
    162.         {
    163.         case MouseFunction.Click:
    164.             if ( MouseButtonListener ) {
    165.                 if ( Input.GetButtonUp(ButtonName) ){
    166.                     MouseButtonListener.SendMessage( "Click", ButtonName );
    167.                 }
    168.             }
    169.             break;
    170.         case MouseFunction.ClickDrag:
    171.             if ( Input.GetButton( ButtonName ) ) {
    172.                
    173.                 downLocation = Input.mousePosition;
    174.                
    175.                 if ( !_isDown ) {
    176.                     isDown = true;
    177.                     startDragLocation = downLocation;
    178.                 }
    179.                
    180.                 if (_isDragging == false) {
    181.                     _isDragging = hasStartedDragging( startDragLocation, downLocation );
    182.                 } else {
    183.                     ClickDragStart = getScreenRaycastPoint( startDragLocation );
    184.                     ClickDragEnd = getScreenRaycastPoint( downLocation );
    185.                     _clickDragRay = new Ray( ClickDragStart, (ClickDragEnd - ClickDragStart).normalized );
    186.                     Debug.DrawRay( ClickDragStart, (ClickDragEnd - ClickDragStart).normalized*10, Color.yellow );
    187.                 }
    188.                
    189.             }
    190.            
    191.             if ( Input.GetButtonUp( ButtonName ) ) {
    192.                
    193.                 //did the player drag the mous or just click?
    194.                 if ( isDragging == false ) {
    195.                     MouseButtonListener.SendMessage( "Click", ButtonName );
    196.                     DebugStreamer.message = ButtonName + " was clicked";
    197.                 } else {
    198.                     upLocation = Input.mousePosition;
    199.                    
    200.                     if ( MouseButtonListener ) {
    201.                         DebugStreamer.message = "New Direction" + _clickDragRay.origin.ToString() + _clickDragRay.direction.ToString();
    202.                         MouseButtonListener.SendMessage( "ClickDragInput", _clickDragRay, SendMessageOptions.DontRequireReceiver);
    203.                     }
    204.                 }
    205.                
    206.                 isDragging = false;
    207.                 isDown = false;
    208.             }
    209.             break;
    210.         case MouseFunction.MarqueeSelection:
    211.             if ( Input.GetButton( ButtonName ) )
    212.             {
    213.                 downLocation = Input.mousePosition;
    214.                
    215.                 if ( !_isDown ) {
    216.                     isDown = true;
    217.                     startDragLocation = downLocation;
    218.                 }
    219.                
    220.                 if (_isDragging == false) {
    221.                     isDragging = hasStartedDragging( startDragLocation, downLocation );
    222.                 } else {
    223.                     _topLeft = getScreenRaycastPoint( startDragLocation );
    224.                     _selectedUnits.Clear();
    225.                 }
    226.                
    227.             }
    228.             if ( Input.GetButtonUp( ButtonName ) ) {
    229.                
    230.                 isDragging = false;
    231.                 isDown = false;
    232.                 upLocation = Input.mousePosition;
    233.                
    234.  
    235.                 getOtherCorners();
    236.                 if (DebugMode) { showCorners(); }
    237.                
    238.                 SelectUnitsInArea();
    239.  
    240.                 if ( MouseButtonListener ) {
    241.                     MouseButtonListener.SendMessage( "SetSelection", _selectedUnits, SendMessageOptions.DontRequireReceiver);
    242.                 }
    243.  
    244.             }
    245.             break;
    246.         }
    247.     }
    248.     public void getOtherCorners()
    249.     {
    250.         _bottomRight = getScreenRaycastPoint( upLocation );
    251.         _bottomLeft  = getScreenRaycastPoint( new Vector2( upLocation.x+width(), upLocation.y ) );
    252.         _topRight    = getScreenRaycastPoint( new Vector2( upLocation.x, upLocation.y-height() ) );
    253.     }
    254.     public void showCorners()  
    255.     {
    256.         topLeftCube.position     = _topLeft;
    257.         topRightCube.position    = _topRight;
    258.         bottomLeftCube.position  = _bottomLeft;
    259.         bottomRightCube.position = _bottomRight;
    260.     }
    261.     private void SelectUnitsInArea()
    262.     {
    263.         //DebugStreamer.message = "allUnit count:" + _allUnits.Count ;
    264.         //DebugStreamer.message = "allUnit 1:" + _allUnits[0].ToString() ;
    265.         //var poly = new Array();
    266.         Vector3[] poly = new Vector3[4];
    267.        
    268.         //set the array with the 4 points of the polygon
    269.         poly[0] = _topLeft;
    270.         poly[1] = _topRight;
    271.         poly[2] = _bottomRight;
    272.         poly[3] = _bottomLeft;
    273.        
    274.         //iterate trough the all unit's array
    275.         foreach ( GameObject go in _allUnits) {
    276.             //if the unit is in the polygon, select it.
    277.             if (isPointInPoly(poly, go.transform.position)) {
    278.                 _selectedUnits.Add(go);
    279.                 //print ( "unit added" + go.ToString() );
    280.             }
    281.         }
    282.     }
    283.     //this is a fancy F***ing algorithm , I have no idea how it works
    284.     private bool isPointInPoly( Vector3[] poly, Vector3 pt )
    285.     {
    286.         bool c = false;
    287.          int  l = 4;//poly.length;
    288.          int j = l - 1;
    289.          
    290.         for( int i = -1 ; ++i < l; j = i){      
    291.             if(((poly[i].z <= pt.z  pt.z < poly[j].z) || (poly[j].z <= pt.z  pt.z < poly[i].z))
    292.              (pt.x < (poly[j].x - poly[i].x) * (pt.z - poly[i].z) / (poly[j].z - poly[i].z) + poly[i].x))
    293.             c = !c;
    294.             }
    295.         return c;
    296.     }
    297.    
    298.    
    299.    
    300.     public void OnGUI() {
    301.        
    302.         if ( _isDragging  (MouseFunctionType==MouseFunction.MarqueeSelection) )
    303.         {
    304.             float width = startDragLocation.x - downLocation.x;
    305.             float height = ( Screen.height - startDragLocation.y) - ( Screen.height - downLocation.y ) ;
    306.             Rect rect = new Rect( downLocation.x, Screen.height - downLocation.y, width, height);
    307.            
    308.             if ( Marquee == MarqueeType.Texture2d ){
    309.                 GUI.DrawTexture (rect, MarqueeTexture, ScaleMode.StretchToFill, true);
    310.             } else if ( Marquee == MarqueeType.EmptyBox ){
    311.                 drawHollowRect(rect, 1.0f, OutlineColor);
    312.             }
    313.         }
    314.     }
    315.     //converted to C# from dr. blitzkrieg's original method
    316.     public void drawHollowRect ( Rect r, float thickness, Color col)
    317.     {
    318.         if(thickness<=0)return;
    319.         Color origColor = GUI.color;
    320.         GUI.color=col;//Set color
    321.         GUI.DrawTexture( new Rect(r.x,r.y,thickness,r.height),whiteTex);//left side
    322.         GUI.DrawTexture( new Rect(r.x,r.y,r.width,thickness),whiteTex);//top
    323.         GUI.DrawTexture( new Rect(r.x+r.width-(thickness-0),r.y,thickness,r.height),whiteTex);//right
    324.         GUI.DrawTexture( new Rect(r.x,r.y+r.height-(thickness-0),r.width,thickness),whiteTex);//bottom
    325.         GUI.color=origColor;//Reset color to white
    326.     }
    327.    
    328.     private bool hasStartedDragging ( Vector2 v1, Vector2 v2)
    329.     {
    330.         //var dist = Vector2.Distance(v1, v2);
    331.        
    332.         if (Vector2.Distance(v1, v2) > DragDither) {
    333.             return true;
    334.         } else {
    335.             return false;
    336.         }
    337.     }
    338.    
    339.     private Vector3 getScreenRaycastPoint ( Vector2 screenPosition )
    340.     {
    341.         Physics.Raycast(Camera.main.ScreenPointToRay(screenPosition), out hit, 1000);  
    342.         return hit.point;
    343.     }
    344.    
    345. }
    346.  
     
  7. hellcaller

    hellcaller

    Joined:
    May 19, 2010
    Posts:
    381
    Good job thnx!
     
  8. Velo222

    Velo222

    Joined:
    Apr 29, 2012
    Posts:
    1,437
    Just wanted to say thanks especially to tet2brick, but to others also. The javascript code worked awesome. I was having the same exact problem trying to do a spherecastall etc and was having units on the edges of the screen being selected even though the GUI box was not over them at all. I knew it had to do with angles and converting a 2d box to a 3d environment, but I had no clue how to fix it.

    I used this code, plugged in some of my own variables and game objects and after a little tweaking it works like a charm!

    Thank you for this code :)
     
  9. tet2brick

    tet2brick

    Joined:
    Jun 24, 2009
    Posts:
    77
    Happy. :p
     
  10. Velo222

    Velo222

    Joined:
    Apr 29, 2012
    Posts:
    1,437
    Ok so after testing this algorithm/function with a lot of units to select (say 12+ units), the function actually doesn't work so well for me now :x

    The problem is that for some reason it's too intensive on the processor I think, and so every time I do a multiple unit selection in my game that involves more than about 10 units, my game lags. For small numbers of selections it doesn't lag at all, but it's just too cpu intensive when there are a lot of points to calculate at once.

    The function works great, but it causes a slight lag stutter when I do my multiple unit selections. Anyone have any ideas how to resolve this?
     
  11. Bladesfist

    Bladesfist

    Joined:
    Jan 3, 2012
    Posts:
    107
    Well Im not sure what the whole point of having 5 GUI calls instead of 1 and checking the point with a vector3 array instead of using the Rect you already have and doing Rect.Contains()

    Edit: Just tested my Selection script with 337 units and not even a stutter. Finally got a stutter with 1345 objects being selected.
     
    Last edited: Jul 8, 2012
  12. Velo222

    Velo222

    Joined:
    Apr 29, 2012
    Posts:
    1,437
    Well I havn't looked at workarounds for my stutter problem yet, but I hope you're right. I havn't posted any of my code yet (as far as I know lol), so we'll see. I'll take a look at it sometime this week probably.

    I really hope I am doing something wrong actually, because this point in poly function does work really well. :cool:

    In my script I feed the function the rectangle points (4 of them) and each transform position of every game object in my selected units array.
     
  13. Velo222

    Velo222

    Joined:
    Apr 29, 2012
    Posts:
    1,437
    Yep it was my mistake! I had the function running twice basically, although it wasn't super obvious. :roll: This is one of those times I'm glad I'm wrong.

    Thanks for letting me know it works well with selecting lots of units Bladesfist. And I retract my former statement. This is really a cool function.
     
  14. Bladesfist

    Bladesfist

    Joined:
    Jan 3, 2012
    Posts:
    107
    I am not using this script, I wrote my own which is a bit more optimized than this.
     
  15. chanfort

    chanfort

    Joined:
    Dec 15, 2013
    Posts:
    641
    tet2brick, this code even do not compile:
    Assets/scripts/FrameListenerScript.js(323,28): BCE0005: Unknown identifier: 'pathTest'.
    Assets/scripts/FrameListenerScript.js(335,34): BCE0005: Unknown identifier: 'pathTest'.