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!

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.