Search Unity

Make an arrow to point at a direction from UI

Discussion in 'Scripting' started by blablaalb, Sep 7, 2019.

  1. blablaalb

    blablaalb

    Joined:
    Oct 28, 2015
    Posts:
    53
    I want to have a guiding arrow on the left side of UI. The arrow is child of the player's camera and it's rendered from another camera into render texture. The render texture is displayed on the screen. The arrow is rotated via
    transform.LookAt(targetPosition)
    The problem I'm having is that although it does point in the right direction, form player's point of view it looks like the arrow is pointing somewhere else.
    I want that arrow to point from the point where it's placed on the UI. It should look something like this:

    I tried to do this:
    Code (CSharp):
    1.         Vector3 direction = targetPosition - _arrowRawImage.rectTransform.position;
    2.         _transform.LookAt(direction);
    , but it didn't work.
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,752
    There's a few ways to do this. What I did for my Jetpack Kurt directional arrow is the following:

    Like you, I have a small "offstage" area at (0,-1000,0) where the arrow is being "filmed" by the arrow camera.

    The camera filming this arrow does NOT move around it. It is offset from the arrow to regard it while looking +Z, the normal "forward." It is also offset just right so that it goes as a full-screen camera with only a tiny little arrow rendered in the corner. I don't use render textures, just the "arrow Camera" with clear flags to Depth Only and depth above the main camera.

    The actual update pointing function does this:

    - takes the heading of the player, but only rotated around the Y axis:

    Code (csharp):
    1. float PlayerHeading = 0; // compass heading of the player, 0 to 360 around Y
    2. var heading = Quaternion.Euler( 0, PlayerHeading, 0);
    Then it gets the Quaternion.LookRotation of the vector from the Player's world location to the Goal/Target location.

    Code (csharp):
    1. var towards = Quaternion.LookRotation( TargetPosition - PlayerPosition);
    Finally it adjust the arrow graphic, which points +Z towards its goal, like so:

    Code (csharp):
    1. Arrow.transform.rotation = heading * towards;
    The actual code in my game is one big blobby line, I'm ashamed to say:

    Code (csharp):
    1.     void UpdateAdjustPointing()
    2.     {
    3.         Arrow.transform.rotation = Quaternion.Euler( 0, GetFacing(), 0) * Quaternion.LookRotation (
    4.             GetWorldTarget () - GetPlayerTarget ());
    5.     }
    Also, to get the arrow position right in the camera frustum I do this blurblet:

    Code (csharp):
    1.     void UpdateAdjustArrowPosition()
    2.     {
    3.         if (!Arrow)
    4.         {
    5.             return;
    6.         }
    7.  
    8.         float yFrustum = Mathf.Sin (CameraFieldOfView * Mathf.Deg2Rad) * PullbackForScale / 2;
    9.         float xFrustum = (yFrustum * Screen.width) / Screen.height;
    10.  
    11.         Arrow.transform.localPosition = new Vector3 (
    12.             xFrustum * FrustumPosition.x,
    13.             yFrustum * FrustumPosition.y);
    14.     }
    The above works because the Arrow is a child of the Camera stage. If you change the aspect ratio of your screen, calling that will reset the local position of the arrow to preserve where it should be.
     
    blablaalb likes this.
  3. blablaalb

    blablaalb

    Joined:
    Oct 28, 2015
    Posts:
    53
    Thank you for the elaborate answer. I'm not sure what the
    PlayerHeading
    variable should be and where does it come from. so I marked it serializable, tweaked it in the Inspector and find out that number 30 works fine for me.