- Home /
Locking Rotation of UI Elements Relative to Canvas (VR)
I'm having trouble creating directional target indicators on the player's UI. I'm developing for HTC Vive so the UI Canvas is defined in world space as a child to the main VR camera so that it is always in view when the player moves his/her head.
Essentially, the code spawns arrows at the edges of the screen pointing to off-screen targets. The code rotates these arrows based on the angle between the centre of the screen and each target's screen-space coordinates.
// Get screen centre
Vector3 centre = new Vector3(Screen.width, Screen.height, 0) / 2;
// Offset screen pos by centre to put (0, 0) at the centre of screen rather than bottom left
screenPos -= centre;
// Find angle for indicator rotation
float angle = Mathf.Atan2(screenPos.y, screenPos.x) + 90.0f;
angle *= Mathf.Rad2Deg;
// Calculate gradient using screen position
float m = screenPos.y / screenPos.x;
// Bring screen bounds in by a tenth
Vector3 screenBounds = centre * 0.9f;
// Which side of the screen is it off?
... calculate screen position for arrow
// We now have the position in screen space to instantiate our indicator
GameObject newIndicator = GetIndicator(); // instantiates new arrow as child of canvas
newIndicator.transform.localPosition = screenPos;
newIndicator.GetComponent<RectTransform> ().rotation = Quaternion.Euler (0, 0, angle);
My problem is that despite attempting to lock the rotation of the arrows on the x and y axes (always want them to be directly facing the player and just spin based on direction) the arrows will rotate in the x and y at runtime. Since they are spawned as children of the canvas I need them to stay at zero rotation relative to it, but something is changing it at runtime.
public class IndicatorScript : MonoBehaviour {
float lockRot;
RectTransform transf;
// Use this for initialization
void Start ()
{
transf = GetComponent<RectTransform> ();
lockRot = 0.0f;
}
// Update is called once per frame
void Update ()
{
// Lock rotation on x and y axes to 0
transf.rotation = Quaternion.Euler (lockRot, lockRot, transform.rotation.eulerAngles.z);
}
}
Any help would be appreciated!
Hey did you ever figure this one out? I've run into a similar problem.
Answer by cammymcp · Jun 10, 2017 at 10:19 AM
Thanks @pfreema1 for the comment reminding me of this question. I did figure this out and it was due to the fact that I was editing the transform.rotation property of the arrow. This value is its global rotation, which messes up when its parent rotates.
What you want to edit is its localRotation property, this is its rotation relative to its parent. I simply didn't know that this one existed until it was pointed out to me!
Hope this helps others with this problem.