This works exactly how I want it to when the GUI object is at its current size, but, In my game I’d like to give the player the option to change the size of the GUI object to his/her liking. So this brings me to my question; How do I stop a GUI object from going off screen based on its size?
@unin Got my own version working with any pivot after many hours of trying random stuff.
I can’t post the whole script because it’s for work but I here’s the gist of it.
Just replace the missing references and variables with your own. https://hastebin.com/bagosukiho.go
private void KeepOnScreen ()
{
var refRes = (canvas.transform as RectTransform).sizeDelta;
var goalX = rectTransform.anchoredPosition.x;
var goalY = rectTransform.anchoredPosition.y;
// This works if you change the pivot but don't change the anchors (or the scale).
if (IsTooHigh (refRes))
goalY = (refRes.y / 2f) - (rectTransform.sizeDelta.y * (1f - rectTransform.pivot.y));
if (IsTooLow (refRes))
goalY = -(refRes.y / 2f) + (rectTransform.sizeDelta.y * rectTransform.pivot.y);
if (IsTooFarRight (refRes))
goalX = (refRes.x / 2f) - (rectTransform.sizeDelta.x * (1f - rectTransform.pivot.x));
if (IsTooFarLeft (refRes))
goalX = -(refRes.x / 2f) + (rectTransform.sizeDelta.x * rectTransform.pivot.x);
rectTransform.anchoredPosition = new Vector2 (goalX, goalY);
}
private bool IsTooHigh (Vector2 refRes)
{
return (rectTransform.anchoredPosition.y + (rectTransform.sizeDelta.y * (1f - rectTransform.pivot.y)) > refRes.y / 2f);
}
private bool IsTooLow (Vector2 refRes)
{
return (rectTransform.anchoredPosition.y - (rectTransform.sizeDelta.y * rectTransform.pivot.y) < -refRes.y / 2f);
}
private bool IsTooFarRight (Vector2 refRes)
{
return (rectTransform.anchoredPosition.x + (rectTransform.sizeDelta.x * (1f - rectTransform.pivot.x)) > refRes.x / 2f);
}
private bool IsTooFarLeft (Vector2 refRes)
{
return (rectTransform.anchoredPosition.x - (rectTransform.sizeDelta.x * rectTransform.pivot.x) < -refRes.x / 2f);
}
I figured out how to do this but I’m sure there could be a better method than what I’m currently doing. The limitation of the code I see so far is that the guiObject’s anchors must be set to the center and I don’t think this code will work as intended if your target resolution changes(portrait to landscape). These limitations can be counteracted if you adjust the code to take those factors into account. In my case, it’s fine as is. Before using this code you must come up with a target resolution and set up your canvas scaler as such:
using UnityEngine;
using UnityEngine.EventSystems;
using System.Collections;
public class Example : MonoBehaviour, IDragHandler
{
private RectTransform myRectTransform;
private Vector2 guiSizeHalf;
public Vector2 screenSize;
private Vector2 targetRes;// Set this to whatever your target resolution is.
private Vector2 screenReciprocal;
void Start()
{
myRectTransform = (RectTransform)transform;
DefineScreenValues();
}
//Here we define values about the screen for use in some calculation later on.
void DefineScreenValues()
{
screenSize = new Vector2(Screen.width, Screen.height);
screenReciprocal = new Vector2(1 / screenSize.x, 1 / screenSize.y);
targetRes = new Vector2(720.0f, 1280.0f);
guiSizeHalf = new Vector2(myRectTransform.rect.width * 0.5f, myRectTransform.rect.height * 0.5f);
}
//Here we determine what happens when the mouse/finger starts moving while pressing down on the gameobject.
public void OnDrag(PointerEventData eventData)
{
Vector3 newPos = Vector3.zero;
int deltaX = (int)((eventData.position.x - screenSize.x * 0.5f) * targetRes.x * screenReciprocal.x);
deltaX = (int)(Mathf.Clamp(deltaX, (-targetRes.x * 0.5f + guiSizeHalf.x), (targetRes.x * 0.5f - guiSizeHalf.x)));
newPos.x = deltaX;// deltaX value is assigned to newPos.x
int deltaY = (int)((eventData.position.y - screenSize.y * 0.5f) * targetRes.y * screenReciprocal.y);
deltaY = (int)Mathf.Clamp(deltaY, (-targetRes.y * 0.5f + guiSizeHalf.y), (targetRes.y * 0.5f - guiSizeHalf.y));
newPos.y = deltaY;// deltaY value is assigned to newPos.y
//The position of the dragged object is defined.
myRectTransform.anchoredPosition = new Vector3(newPos.x, newPos.y, newPos.z);
}
}
As stated previously, I’m sure there is a better method so I would love to hear any input on how I can make this code more efficient. Thanks in advance.
I might be late but this is my version of the script(works with Scale with Screen Size scale mode).
Its probably not the fastest or most elegant but its easy-ish to understand:
Vector2 pos = Input.mousePosition;
Vector2 percScr;//position of the mouse's screen in percentage
percScr.x = pos.x / Screen.width;
percScr.y = pos.y / Screen.height;
var refRes = (canv.transform as RectTransform).sizeDelta;
pos = refRes * percScr;//translate from screen to canvas pixel position
//avoid going out of screen
if(pos.y > refRes.y - rectBody.sizeDelta.y) pos.y = refRes.y - rectBody.sizeDelta.y;//up
if(pos.y < 0) pos.y = 0;//down
if(pos.x < rectBody.sizeDelta.x) pos.x = rectBody.sizeDelta.x;//left
if(pos.x > refRes.x) pos.x = refRes.x;//right
rectBody.anchoredPosition = pos;