Search Unity

Unity UI [SOLVED] EventSystem input, scale with screen size, and different resolutions

Discussion in 'UGUI & TextMesh Pro' started by Murgilod, Jul 29, 2017.

  1. Murgilod

    Murgilod

    Joined:
    Nov 12, 2013
    Posts:
    10,156
    I'm working on a unit selection system for an RTS based on Kiwasi's tutorial on the subject and I've run into an annoying problem. I'm using "Scale with screen size" and a screen space camera to keep my UI properly scaled on different resolutions with a default setting of 1920x1080. When the game is set in 1080p mode, everything works perfectly fine. If I change the resolution to, say, 720p however, the cursor position is completely offset in the wrong place.

    Working as intended:


    Super busted:


    Here's the modified code I'm using. I tried setting up a manual offset based on information from the canvas scaler and the camera resolution, but I couldn't get that to work at all.

    Code (CSharp):
    1. using System;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5. using UnityEngine.EventSystems;
    6. using UnityEngine.UI;
    7.  
    8. public class DragHandler : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler, IPointerClickHandler
    9. {
    10.     [SerializeField]
    11.     CanvasScaler canvasScaler;
    12.  
    13.     [SerializeField]
    14.     Image selectionBoxImage;
    15.     [SerializeField]
    16.     Image selectionManager;
    17.  
    18.     Vector2 startPosition;
    19.     Rect selectionRect;
    20.  
    21.     PointerEventData mainEventData;
    22.  
    23.     public void OnBeginDrag(PointerEventData eventData)
    24.     {
    25.         selectionBoxImage.gameObject.SetActive(true);
    26.         startPosition = eventData.position;
    27.         selectionRect = new Rect();
    28.     }
    29.  
    30.     public void OnDrag(PointerEventData eventData)
    31.     {
    32.         if (eventData.position.x < startPosition.x)
    33.         {
    34.             selectionRect.xMin = eventData.position.x;
    35.             selectionRect.xMax = startPosition.x;
    36.         }
    37.         else
    38.         {
    39.             selectionRect.xMin = startPosition.x;
    40.             selectionRect.xMax = eventData.position.x;
    41.         }
    42.  
    43.         if (eventData.position.y < startPosition.y)
    44.         {
    45.             selectionRect.yMin = eventData.position.y;
    46.             selectionRect.yMax = startPosition.y;
    47.         }
    48.         else
    49.         {
    50.             selectionRect.yMin = startPosition.y;
    51.             selectionRect.yMax = eventData.position.y;
    52.         }
    53.  
    54.         if (eventData.position.x < 0)
    55.         {
    56.             selectionRect.x = 0;
    57.             selectionRect.width = startPosition.x;
    58.         }
    59.  
    60.         if (eventData.position.x > selectionManager.rectTransform.rect.width)
    61.         {
    62.             selectionRect.width = selectionManager.rectTransform.rect.width - selectionRect.x;
    63.         }
    64.  
    65.         if (eventData.position.y < 0)
    66.         {
    67.             selectionRect.y = 0;
    68.             selectionRect.height = startPosition.y;
    69.         }
    70.  
    71.         if (eventData.position.y > selectionManager.rectTransform.rect.height)
    72.         {
    73.             selectionRect.height = selectionManager.rectTransform.rect.height - selectionRect.y;
    74.         }
    75.  
    76.         selectionBoxImage.rectTransform.offsetMin = selectionRect.min;
    77.         selectionBoxImage.rectTransform.offsetMax = selectionRect.max;
    78.     }
    79.  
    80.     public void OnEndDrag(PointerEventData eventData)
    81.     {
    82.         selectionBoxImage.gameObject.SetActive(false);
    83.         foreach(Selectable selectable in Selectable.allSelectables)
    84.         {
    85.             if (selectionRect.Contains(Camera.main.WorldToScreenPoint(selectable.transform.position)))
    86.             {
    87.                 selectable.OnSelect(eventData);
    88.             }
    89.         }
    90.     }
    91.  
    92.     public void OnPointerClick(PointerEventData eventData)
    93.     {
    94.         Selectable.DeselectAll(eventData);
    95.  
    96.         List<RaycastResult> results = new List<RaycastResult>();
    97.         EventSystem.current.RaycastAll(eventData, results);
    98.  
    99.         float distance = 0f;
    100.  
    101.         foreach (RaycastResult result in results)
    102.         {
    103.             if (result.gameObject == gameObject)
    104.             {
    105.                 distance = result.distance;
    106.                 break;
    107.             }
    108.         }
    109.  
    110.         GameObject nextObject = null;
    111.         float maxDistance = Mathf.Infinity;
    112.  
    113.         foreach (RaycastResult result in results)
    114.         {
    115.             if (result.distance > distance && result.distance < maxDistance)
    116.             {
    117.                 nextObject = result.gameObject;
    118.                 maxDistance = result.distance;
    119.             }
    120.         }
    121.  
    122.         if (nextObject)
    123.         {
    124.             ExecuteEvents.Execute<IPointerClickHandler>(nextObject, eventData, (x, y) => { x.OnPointerClick((PointerEventData)y); });
    125.         }
    126.     }
    127. }
    128.  
     
  2. Murgilod

    Murgilod

    Joined:
    Nov 12, 2013
    Posts:
    10,156
    After some amount of digging, I came across Canvas.scaleFactor, which seems to do exactly what I was trying to do, only correctly.
     
    laurG and PROE_ like this.