29using System.Collections.Generic;
34 [RequireComponent(typeof(Canvas))]
35 [AddComponentMenu(
"UI/Extensions/Selection Box")]
48 private Vector2 origin;
54 private RectTransform boxRect;
60 private MonoBehaviour[] selectableGroup;
73 void ValidateCanvas(){
74 var canvas = gameObject.GetComponent<Canvas>();
76 if (canvas.renderMode != RenderMode.ScreenSpaceOverlay) {
77 throw new System.Exception(
"SelectionBox component must be placed on a canvas in Screen Space Overlay mode.");
80 var canvasScaler = gameObject.GetComponent<CanvasScaler>();
82 if (canvasScaler && canvasScaler.enabled && (!Mathf.Approximately(canvasScaler.scaleFactor, 1f) || canvasScaler.uiScaleMode != CanvasScaler.ScaleMode.ConstantPixelSize)) {
83 Destroy(canvasScaler);
84 Debug.LogWarning(
"SelectionBox component is on a gameObject with a Canvas Scaler component. As of now, Canvas Scalers without the default settings throw off the coordinates of the selection box. Canvas Scaler has been removed.");
95 void SetSelectableGroup(IEnumerable<MonoBehaviour> behaviourCollection) {
98 if (behaviourCollection ==
null) {
99 selectableGroup =
null;
105 var behaviourList =
new List<MonoBehaviour>();
107 foreach(var behaviour
in behaviourCollection) {
108 if (behaviour as IBoxSelectable !=
null) {
109 behaviourList.Add (behaviour);
113 selectableGroup = behaviourList.ToArray();
116 void CreateBoxRect(){
117 var selectionBoxGO =
new GameObject();
119 selectionBoxGO.name =
"Selection Box";
120 selectionBoxGO.transform.parent = transform;
121 selectionBoxGO.AddComponent<
Image>();
123 boxRect = selectionBoxGO.transform as RectTransform;
139 boxRect.anchoredPosition =
Vector2.zero;
140 boxRect.sizeDelta =
Vector2.zero;
141 boxRect.anchorMax =
Vector2.zero;
142 boxRect.anchorMin =
Vector2.zero;
144 boxRect.gameObject.SetActive(
false);
148 void BeginSelection(){
150 if (!Input.GetMouseButtonDown(0))
154 boxRect.gameObject.SetActive(
true);
157 origin =
new Vector2(Input.mousePosition.x, Input.mousePosition.y);
160 if (!PointIsValidAgainstSelectionMask(origin)) {
166 boxRect.anchoredPosition = origin;
168 MonoBehaviour[] behavioursToGetSelectionsFrom;
171 if (selectableGroup ==
null) {
172 behavioursToGetSelectionsFrom = GameObject.FindObjectsOfType<MonoBehaviour>();
174 behavioursToGetSelectionsFrom = selectableGroup;
178 List<IBoxSelectable> selectableList =
new List<IBoxSelectable>();
180 foreach (MonoBehaviour behaviour
in behavioursToGetSelectionsFrom) {
183 IBoxSelectable selectable = behaviour as IBoxSelectable;
184 if (selectable !=
null) {
185 selectableList.Add (selectable);
188 if (!Input.GetKey (KeyCode.LeftShift)) {
189 selectable.selected =
false;
194 selectables = selectableList.ToArray();
197 clickedBeforeDrag = GetSelectableAtMousePosition();
201 bool PointIsValidAgainstSelectionMask(Vector2 screenPoint){
207 Camera screenPointCamera = GetScreenPointCamera(
selectionMask);
209 return RectTransformUtility.RectangleContainsScreenPoint(
selectionMask, screenPoint, screenPointCamera);
212 IBoxSelectable GetSelectableAtMousePosition() {
214 if (!PointIsValidAgainstSelectionMask(Input.mousePosition)) {
219 foreach (var selectable
in selectables) {
222 var rectTransform = (selectable.transform as RectTransform);
226 var screenCamera = GetScreenPointCamera(rectTransform);
230 if (RectTransformUtility.RectangleContainsScreenPoint(rectTransform, Input.mousePosition, screenCamera)) {
238 var radius = selectable.transform.GetComponent<
UnityEngine.Renderer>().bounds.extents.magnitude;
240 var selectableScreenPoint = GetScreenPointOfSelectable(selectable);
243 if (
Vector2.Distance(selectableScreenPoint, Input.mousePosition) <= radius) {
256 void DragSelection(){
258 if (!Input.GetMouseButton(0) || !boxRect.gameObject.activeSelf)
262 Vector2 currentMousePosition =
new Vector2(Input.mousePosition.x, Input.mousePosition.y);
265 Vector2 difference = currentMousePosition - origin;
273 if (difference.x < 0)
275 startPoint.x = currentMousePosition.x;
276 difference.x = -difference.x;
278 if (difference.y < 0)
280 startPoint.y = currentMousePosition.y;
281 difference.y = -difference.y;
285 boxRect.anchoredPosition = startPoint;
286 boxRect.sizeDelta = difference;
289 foreach(var selectable
in selectables) {
291 Vector3 screenPoint = GetScreenPointOfSelectable(selectable);
294 selectable.preSelected = RectTransformUtility.RectangleContainsScreenPoint(boxRect, screenPoint,
null) && PointIsValidAgainstSelectionMask(screenPoint);
300 if (clickedBeforeDrag !=
null) {
305 void ApplySingleClickDeselection(){
308 if (clickedBeforeDrag ==
null)
320 void ApplyPreSelections(){
322 foreach(var selectable
in selectables) {
325 if (selectable.preSelected) {
326 selectable.selected =
true;
327 selectable.preSelected =
false;
333 Vector2 GetScreenPointOfSelectable(IBoxSelectable selectable) {
337 var rectTransform = selectable.transform as RectTransform;
343 Camera renderingCamera = GetScreenPointCamera(rectTransform);
345 return RectTransformUtility.WorldToScreenPoint(renderingCamera, selectable.transform.position);
349 return Camera.main.WorldToScreenPoint(selectable.transform.position);
361 Camera GetScreenPointCamera(RectTransform rectTransform) {
363 Canvas rootCanvas =
null;
364 RectTransform rectCheck = rectTransform;
368 rootCanvas = rectCheck.GetComponent<Canvas>();
371 if (rootCanvas && !rootCanvas.isRootCanvas) {
376 rectCheck = (RectTransform)rectCheck.parent;
378 }
while (rootCanvas ==
null);
381 switch (rootCanvas.renderMode) {
382 case RenderMode.ScreenSpaceOverlay:
386 case RenderMode.ScreenSpaceCamera:
389 return (rootCanvas.worldCamera) ? rootCanvas.worldCamera : Camera.main;
392 case RenderMode.WorldSpace:
400 if (selectables ==
null) {
404 var selectedList =
new List<IBoxSelectable>();
406 foreach(var selectable
in selectables) {
407 if (selectable.selected) {
408 selectedList.Add (selectable);
412 return selectedList.ToArray();
417 if (!Input.GetMouseButtonUp(0) || !boxRect.gameObject.activeSelf)
420 clickedAfterDrag = GetSelectableAtMousePosition();
422 ApplySingleClickDeselection();
423 ApplyPreSelections();
System.Drawing.Image Image
SelectionEvent onSelectionChange
RectTransform selectionMask
IBoxSelectable[] GetAllSelected()
Credit Erdener Gonenc - @PixelEnvision.