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.
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
public class DragHandler : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler, IPointerClickHandler
{
[SerializeField]
CanvasScaler canvasScaler;
[SerializeField]
Image selectionBoxImage;
[SerializeField]
Image selectionManager;
Vector2 startPosition;
Rect selectionRect;
PointerEventData mainEventData;
public void OnBeginDrag(PointerEventData eventData)
{
selectionBoxImage.gameObject.SetActive(true);
startPosition = eventData.position;
selectionRect = new Rect();
}
public void OnDrag(PointerEventData eventData)
{
if (eventData.position.x < startPosition.x)
{
selectionRect.xMin = eventData.position.x;
selectionRect.xMax = startPosition.x;
}
else
{
selectionRect.xMin = startPosition.x;
selectionRect.xMax = eventData.position.x;
}
if (eventData.position.y < startPosition.y)
{
selectionRect.yMin = eventData.position.y;
selectionRect.yMax = startPosition.y;
}
else
{
selectionRect.yMin = startPosition.y;
selectionRect.yMax = eventData.position.y;
}
if (eventData.position.x < 0)
{
selectionRect.x = 0;
selectionRect.width = startPosition.x;
}
if (eventData.position.x > selectionManager.rectTransform.rect.width)
{
selectionRect.width = selectionManager.rectTransform.rect.width - selectionRect.x;
}
if (eventData.position.y < 0)
{
selectionRect.y = 0;
selectionRect.height = startPosition.y;
}
if (eventData.position.y > selectionManager.rectTransform.rect.height)
{
selectionRect.height = selectionManager.rectTransform.rect.height - selectionRect.y;
}
selectionBoxImage.rectTransform.offsetMin = selectionRect.min;
selectionBoxImage.rectTransform.offsetMax = selectionRect.max;
}
public void OnEndDrag(PointerEventData eventData)
{
selectionBoxImage.gameObject.SetActive(false);
foreach(Selectable selectable in Selectable.allSelectables)
{
if (selectionRect.Contains(Camera.main.WorldToScreenPoint(selectable.transform.position)))
{
selectable.OnSelect(eventData);
}
}
}
public void OnPointerClick(PointerEventData eventData)
{
Selectable.DeselectAll(eventData);
List<RaycastResult> results = new List<RaycastResult>();
EventSystem.current.RaycastAll(eventData, results);
float distance = 0f;
foreach (RaycastResult result in results)
{
if (result.gameObject == gameObject)
{
distance = result.distance;
break;
}
}
GameObject nextObject = null;
float maxDistance = Mathf.Infinity;
foreach (RaycastResult result in results)
{
if (result.distance > distance && result.distance < maxDistance)
{
nextObject = result.gameObject;
maxDistance = result.distance;
}
}
if (nextObject)
{
ExecuteEvents.Execute<IPointerClickHandler>(nextObject, eventData, (x, y) => { x.OnPointerClick((PointerEventData)y); });
}
}
}

