I’d like to transform the masked area without transforming the content being masked, like moving a window over a static object. AFAIK masked content must be on a child GameObject of the mask GameObject right now, so transforms propagate down the hierarchy. It seems I’d prefer it to be set up so a mask takes an explicit reference to a content GameObject, rather than inferring the mask / content relationship through hierarchy. This would allow more flexibility, as you could still have the parent-child relationship if you so wish.
This isn’t far off, I just modified a drag script I already had to maintain the child position.
Put this script on the Mask panel and drag the parent canvas onto the ParentRT slot, the Mask panel onto MyRect and the child Image onto the MyChild slot:
private bool mouseDown = false;
private Vector3 startMousePos;
private Vector3 startPos;
private bool restrictX;
private bool restrictY;
private float fakeX;
private float fakeY;
private float myWidth;
private float myHeight;
private bool snapHome = true;
public RectTransform ParentRT;
public RectTransform MyRect;
public RectTransform MyChild;
private Vector3 ChildPos;
void Start()
{
myWidth = (MyRect.rect.width + 5) / 2;
myHeight = (MyRect.rect.height + 5) / 2;
ChildPos = MyChild.transform.position;
}
public void OnPointerDown(PointerEventData ped)
{
mouseDown = true;
startPos = transform.position;
startMousePos = Input.mousePosition;
}
public void OnPointerUp(PointerEventData ped)
{
mouseDown = false;
if(snapHome)
transform.position = startPos;
}
void Update ()
{
if (mouseDown) {
Vector3 currentPos = Input.mousePosition;
Vector3 diff = currentPos - startMousePos;
Vector3 pos = startPos + diff;
transform.position = pos;
MyChild.transform.position = ChildPos;
if(transform.localPosition.x < 0 - ((ParentRT.rect.width / 2) - myWidth) || transform.localPosition.x > ((ParentRT.rect.width / 2) - myWidth))
restrictX = true;
else
restrictX = false;
if(transform.localPosition.y < 0 - ((ParentRT.rect.height / 2) - myHeight) || transform.localPosition.y > ((ParentRT.rect.height / 2) - myHeight))
restrictY = true;
else
restrictY = false;
if(restrictX)
{
if(transform.localPosition.x < 0)
fakeX = 0 - (ParentRT.rect.width / 2) + myWidth;
else
fakeX = (ParentRT.rect.width / 2) - myWidth;
Vector3 xpos = new Vector3 (fakeX, transform.localPosition.y, 0.0f);
transform.localPosition = xpos;
}
if(restrictY)
{
if(transform.localPosition.y < 0)
fakeY = 0 - (ParentRT.rect.height / 2) + myHeight;
else
fakeY = (ParentRT.rect.height / 2) - myHeight;
Vector3 ypos = new Vector3 (transform.localPosition.x, fakeY, 0.0f);
transform.localPosition = ypos;
}
}
}
}
EDIT
Just a heads up I’m not getting mail notifications so very limitied to how I can use Answers ATM, if you post a comment I won’t be notified. I’m not ignoring you, just not getting notification!
There is a very simple way tested in Unity 2018.2.
Be aware that this solution changes UI hierarchy which may be less efficient than the first solution proposed. In my case I needed it on a desktop project and it was totally fine. Better you profile it (especially mobile users).
Before to change the position of the mask, simply
- Set the parent of the masked child to null.
- Move the mask.
- Assign back the child.
Here an example code inside a tween :
DOTween.To(() => MaskPosition, value => MaskPosition = value,
destination, duration);
private Vector2 MaskPosition
{
get { return _mask.rectTransform.anchoredPosition; }
set
{
_child.parent = null;
_mask.rectTransform.anchoredPosition = value;
_child.parent = _mask.rectTransform;
}
}
Is there a way to do this without using scripts? I"m working in UI and animating on the timeline. I’ve tried using components but any mask I attach to the parent moves the children.
I"ve been searching for this answer for months now and I’m beginning to think that its not possible without using scripts. Which if that’s the case, I"m lost.
You can actually do masking without using direct ancestors. Setup your hierarchy like so:
- left mask (Image)
- right mask (Image)
- mask parent (Image + Mask + this object should be 0 size because you dont actually want its mask to be applied)
- child object that gets masked
- child object that gets masked
- child object that gets masked
Once you set it up like that, you have to go into 1 of your child objects and toggle the rendering component on and off to refresh the masking setup.
Tested in Unity 5.2.2p4