How would I Consistantly 'Snap' a UI Element to the Edge of a Camera?
Hello everyone! I am making a 2D game, and want a UI Element to be like a Chat box you can "Hear" from a distance, Its size is 150 Width by 60 Height, and is just a regular texture element I can overlay text on, but I am having trouble automatically positioning it on the screen towards the position it wants to snap to. The code I currently have below "Should" do just that, but doesn't... Its a C# script inside the Main Camera itself. "chatBubble" is the Sprite object in Canvas. and "chatBubbleObject" is just a gameObject in real space I want it to lock to when its visible on screen etc:
Vector3 bubbleScreenPosition = gameObject.GetComponent<Camera>().WorldToScreenPoint(chatBubbleObject.transform.position);
chatBubble.transform.position = bubbleScreenPosition;
if (bubbleScreenPosition.y <= 0f + chatBubble.GetComponent<RectTransform> ().sizeDelta.y) {
chatBubble.transform.position = new Vector3 (chatBubble.transform.position.x, 0f + chatBubble.GetComponent<RectTransform> ().sizeDelta.y, chatBubble.transform.position.z);
} else if (bubbleScreenPosition.y >= gameObject.GetComponent<Camera>().pixelHeight - chatBubble.GetComponent<RectTransform> ().sizeDelta.y) {
chatBubble.transform.position = new Vector3 (chatBubble.transform.position.x, gameObject.GetComponent<Camera> ().pixelHeight - chatBubble.GetComponent<RectTransform> ().sizeDelta.y, chatBubble.transform.position.z);
}
if (bubbleScreenPosition.x <= 0f + chatBubble.GetComponent<RectTransform> ().sizeDelta.x) {
chatBubble.transform.position = new Vector3 (0f + chatBubble.GetComponent<RectTransform> ().sizeDelta.x, chatBubble.transform.position.y, chatBubble.transform.position.z);
} else if (bubbleScreenPosition.x >= gameObject.GetComponent<Camera>().pixelWidth - chatBubble.GetComponent<RectTransform> ().sizeDelta.x) {
chatBubble.transform.position = new Vector3 (gameObject.GetComponent<Camera> ().pixelWidth - chatBubble.GetComponent<RectTransform> ().sizeDelta.x, chatBubble.transform.position.y, chatBubble.transform.position.z);
}
(Visual Image of whats happening, I Don't want those gaps...): https://thumbs.gfycat.com/WeeklyHeartyBallpython-size_restricted.gif
The main issue I am having, Is I could have sworn I would have needed to Divide the Length of the UI object by Half, but to get the best results, I did not do this. Plus, It is still not completely accurate in snapping to the screen, and when the screens aspect ratio changes, it does throw off the UI's snap, making a big gap show, So basically it's not correct math.
I have a theory that the UI Size of the object 150 Width by 60 Height does not correctly translate to positions relative to the camera. I managed to see screen position relative to a game object, but I am confused if I need to do the same with the canvas to the camera, or how I would even go about doing that.
Thanks for reading!
Answer by ZaddBuzuki · Oct 30, 2016 at 02:34 AM
After much testing, I have found, that the scale on my image was actually 1.5f Which could have been throwing off the visual sizing of my UI. I had a friend look my code and item properties, and he concluded this is the code I should use to Reposition the UI accordingly. Just make sure the scale of your Image UI Object is 1 X 1 Y, and again, this is running under the 'Update' function, 'chatBubble' is the Image UI, 'chatBubbleObject' is the gameobject you want the UI to lock on in world space, and now 'MainCanvas' is the Canvas object itself. I hope this code helps others who want something similar to this in the future:
Vector3 bubbleScreenPosition = gameObject.GetComponent<Camera>().WorldToScreenPoint(chatBubbleObject.transform.position);
//bubbleScreenPosition += new Vector3 (0, 0, 0); //This offsets it from the object, If you want it above a character head for example.
chatBubble.transform.position = bubbleScreenPosition;
float bubbleX = chatBubble.GetComponent<RectTransform> ().rect.width * MainCanvas.scaleFactor;
float bubbleY = chatBubble.GetComponent<RectTransform> ().rect.height * MainCanvas.scaleFactor;
if (bubbleScreenPosition.y <= 0f + bubbleY/2) {
chatBubble.transform.position = new Vector3 (chatBubble.transform.position.x, 0f + bubbleY/2, chatBubble.transform.position.z);
} else if (bubbleScreenPosition.y >= gameObject.GetComponent<Camera>().pixelHeight - bubbleY/2) {
chatBubble.transform.position = new Vector3 (chatBubble.transform.position.x, gameObject.GetComponent<Camera> ().pixelHeight - bubbleY/2, chatBubble.transform.position.z);
}
if (bubbleScreenPosition.x <= 0f + bubbleX/2) {
chatBubble.transform.position = new Vector3 (0f + bubbleX/2, chatBubble.transform.position.y, chatBubble.transform.position.z);
} else if (bubbleScreenPosition.x >= gameObject.GetComponent<Camera>().pixelWidth - bubbleX/2) {
chatBubble.transform.position = new Vector3 (gameObject.GetComponent<Camera> ().pixelWidth - bubbleX/2, chatBubble.transform.position.y, chatBubble.transform.position.z);
}
Visual Representation of Final Result: https://gfycat.com/OrangeScalyGoat