Search Unity

Horizontal Compass HUD?

Discussion in 'Scripting' started by Kovenant, Jan 21, 2016.

  1. Kovenant

    Kovenant

    Joined:
    Sep 18, 2013
    Posts:
    254
  2. LeftyRighty

    LeftyRighty

    Joined:
    Nov 2, 2012
    Posts:
    5,148
    code is attached to the Image that is the compass in the UI.
    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using UnityEngine.UI;
    4.  
    5. using System.Collections;
    6.  
    7. public class CompassHandler : MonoBehaviour
    8. {
    9.     public float numberOfPixelsNorthToNorth;
    10.     public GameObject target;
    11.     Vector3 startPosition;
    12.     float rationAngleToPixel;
    13.  
    14.     void Start()
    15.     {
    16.         startPosition = transform.position;
    17.         rationAngleToPixel = numberOfPixelsNorthToNorth / 360f;
    18.     }
    19.  
    20.     void Update ()
    21.     {
    22.         Vector3 perp = Vector3.Cross(Vector3.forward, target.transform.forward);
    23.         float dir = Vector3.Dot(perp, Vector3.up);
    24.         transform.position = startPosition + (new Vector3(Vector3.Angle(target.transform.forward, Vector3.forward) * Mathf.Sign(dir) * rationAngleToPixel, 0, 0));
    25.     }
    26. }
    27.  
    28.  

    the compass image is double just to make sure it doesn't "run out" and end before the imagemask does. Due to the virtue of angles "wrapping around" naturally you don't have to worry about clamping the position etc.



    oh, in the code "Vector3.forward" is "north" if you want to change that to be something different. Needs to be done in line 18 and 20
     
    Last edited: Jan 21, 2016
  3. Kovenant

    Kovenant

    Joined:
    Sep 18, 2013
    Posts:
    254
    Thank you mister! Didn't expect a code to copy & paste, just guidelines.. But this is awesome! Thank you! :)
     
  4. LeftyRighty

    LeftyRighty

    Joined:
    Nov 2, 2012
    Posts:
    5,148
    It's been on my list of "it'd be kinda cool to have an example of... " so I put it together :)
     
    Appleguysnake and Kurt-Dekker like this.
  5. LeftyRighty

    LeftyRighty

    Joined:
    Nov 2, 2012
    Posts:
    5,148
    hmm, actually I missed something. When i made the compass image I made it 90 pixels between each tick, so 1deg = 1 pixel. If your image isn't at that resolution you'll need to factor in a ratio. I've updated the above code.
     
    Kovenant likes this.
  6. Kovenant

    Kovenant

    Joined:
    Sep 18, 2013
    Posts:
    254
    @LeftyRighty

    I have finally put it to the test... My compass consists of numbers instead of the traditional "N S W E"..
    My compass doesn't seem to loop seamlessly like yours do.
    What am I doing wrong? (I haven't altered your code...)

    compass_unityforum.jpg
     
  7. Kovenant

    Kovenant

    Joined:
    Sep 18, 2013
    Posts:
    254
    numbers.png
    There's (slightly visible) my image of the numbers are.... :)
     
  8. LeftyRighty

    LeftyRighty

    Joined:
    Nov 2, 2012
    Posts:
    5,148
    first thing that comes to mind is that 360 and 0 are the same thing, on your compass they are separated... can you post the entire image of your compass image (like i did underneath the code above, the entire image with all the numbers etc. )
     
  9. Kovenant

    Kovenant

    Joined:
    Sep 18, 2013
    Posts:
    254
    I've posted the image with the numbers.. look at the post I did just before your last reply... "There's (slightly visible)......".... :) The image is there.. :D
     
  10. Kovenant

    Kovenant

    Joined:
    Sep 18, 2013
    Posts:
    254
    compass.jpg
    I re-designed it.. and it works now.. Don't know what I was thinking when I started... :p
     
  11. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    OK, I'm feeling dumb. @LeftyRighty, can you explain how this works? In the animated GIF and in the OP's original request, it looks like an image whose texture shifts according to which way you're facing. So I would expect to see code that mucks with the material's texture offset. But this code just updates transform.position. How does moving the image around result in the texture appearing to shift?!?
     
  12. LeftyRighty

    LeftyRighty

    Joined:
    Nov 2, 2012
    Posts:
    5,148
    @JoeStrout
    in 3d/2d you'd probably need to do something like offset the material, but this is UI...

    canvas > image mask > compass image

    the Red area is the image mask (offsetted up, coloured and mask component removed), the compass is below it. As the object rotates the offset and mask perform something similar to a texture offset.
     
    Last edited: Jan 25, 2016
  13. LeftyRighty

    LeftyRighty

    Joined:
    Nov 2, 2012
    Posts:
    5,148
    having tried to make the example for joe I've found you really should include some sort of reference to the gameobject's horizontal scale in the pixel ratio... haven't got time to update the code yet, but as an example, scale of 0.5 means 180 pixels from north to north when the image is actually 360 pixels north to north etc. :)
     
  14. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    Yep, I see now — sticking it inside an ImageMask makes perfect sense. Very clever solution (and yep, I feel sheepish for not thinking of it right away!).
     
  15. exrnge

    exrnge

    Joined:
    Jun 9, 2016
    Posts:
    6
    i'm trying to add this compass to my plane's hud . Because the plane is moving too , ui canvas including hud is going to somwhere else . I need help @LeftyRighty @Kovenant
     
  16. LeftyRighty

    LeftyRighty

    Joined:
    Nov 2, 2012
    Posts:
    5,148
    plane hud as in a world space Canvas inside the cockpit?
     
  17. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    Then you haven't set up your UI canvas correctly. Either set it up to use screen space, or if you're going to put it in world space, then put it inside your plane so it moves with the plane.
     
  18. exrnge

    exrnge

    Joined:
    Jun 9, 2016
    Posts:
    6
    yes . there is a world space canvas that is attached to cockpit and there is another canvas which holds a panel with mask and compass image . that's my hierarchy . i have another question for you , what is the target in your code i don't understand exactly . Thanks for reply

    Note : gif with cube and compass above in your post , think it like cube is also moving . this is what i need , cube is moving , compass ui image is sliding (world space mode) and staying in screen
     
    Last edited: Jun 10, 2016
  19. exrnge

    exrnge

    Joined:
    Jun 9, 2016
    Posts:
    6
    i think it's not the problem cause other hud objects are moving with the plane (but these ones are not moving like the compass , they are static ui images , texts and scroll bars ) . Thanks for reply .
     
    Last edited: Jun 10, 2016
  20. LeftyRighty

    LeftyRighty

    Joined:
    Nov 2, 2012
    Posts:
    5,148
    target is the cube (or whatever you want to take the baring of), the code above goes on the Image for the compass UI.
     
  21. exrnge

    exrnge

    Joined:
    Jun 9, 2016
    Posts:
    6
    ı can't figure out the problem , i create a compass with scrollbar . Thanks for help :)
     
  22. reocwolf

    reocwolf

    Joined:
    Aug 1, 2013
    Posts:
    182
    Hi guys. how would I go about creating a world space compass that is 360* around the player. Would it be the same? Something like this:
    I've got the UI elements but I'm just an artist that is just not too good at coding but can manage.
     
  23. LeftyRighty

    LeftyRighty

    Joined:
    Nov 2, 2012
    Posts:
    5,148
    @reocwolf er, not really. For something like that I think you're looking at a separate gameobject which has it's position updated to the be the same as the player (don't want to parent it as it'll mess with the rotation), so it's more akin to a follow camera than the ui compass. If you're looking specifically for the "cylinder" style you might even be better off with a cylinder billboard style mesh with the compass texture applied to it than canvasUI based, there are ways of "curving" the canvas but they get really complicated fast.
     
  24. andgus

    andgus

    Joined:
    Oct 6, 2016
    Posts:
    10
    Hi LeftyRight, Very nice compass. Thanks for sharing but I really need your help. I put the compass bar image onto the canvas and put my player as the target. It works just fine but when the player faces north (0) or south (180) the compass image moves left and right when I look up and down using mouselook. I just want the compass to move when I moving the player to the left and right. I really don´t get the mathematics behind the script and would appreciate some help.

    Here is a webdemo to show you what I mean http://angu.ddns.net/CompBar/compbar.html
     
  25. LeftyRighty

    LeftyRighty

    Joined:
    Nov 2, 2012
    Posts:
    5,148
    this line assumes it's a 2d plane
    Code (csharp):
    1.  
    2. Vector3.Angle(target.transform.forward, Vector3.forward)
    3.  
    if you want to get it to work with 3d rotations you'll need to "ignore" the y axis so something like
    Code (csharp):
    1.  
    2. // replace with
    3. Vector3.Angle(new Vector3(target.transform.forward.x, 0f, target.transform.forward.z), Vector3.forward)
    4.  
     
    KUFgoddess likes this.
  26. andgus

    andgus

    Joined:
    Oct 6, 2016
    Posts:
    10
    Thank you very much and for the fast reply!!
    It works perfectly now. :)

    Is this code for free? I mean. Can I use it in an asset at Asset Store?
     
  27. LeftyRighty

    LeftyRighty

    Joined:
    Nov 2, 2012
    Posts:
    5,148
  28. KUFgoddess

    KUFgoddess

    Joined:
    Apr 2, 2015
    Posts:
    27
    sorry for the necropost but is that a whole image im confused on how to set this up I have just a pointer (upside down triangle) could someone go through the whole steps?
     

    Attached Files:

  29. andgus

    andgus

    Joined:
    Oct 6, 2016
    Posts:
    10
  30. blakehmclaughlin

    blakehmclaughlin

    Joined:
    Jan 22, 2018
    Posts:
    2
    How can i get to do something like he did, would you be able to explain, i know this post was 2 years ago.
     
  31. LeftyRighty

    LeftyRighty

    Joined:
    Nov 2, 2012
    Posts:
    5,148
    explain which bit? similar how? :confused:
     
  32. blakehmclaughlin

    blakehmclaughlin

    Joined:
    Jan 22, 2018
    Posts:
    2
    Actly never mind, i figure it out my self. started to use my brain.
     
  33. Lethn

    Lethn

    Joined:
    May 18, 2015
    Posts:
    1,583
    @LeftRighty Bit random but just jumping in to post that was really interesting to learn about, thanks.
     
  34. Zymu

    Zymu

    Joined:
    Jan 29, 2017
    Posts:
    7
    Hi guys, wasn't sure if anyone was still wondering about this, but there is a solution that's a little bit easier.

    Code (csharp):
    1.  
    2.  
    3. using UnityEngine;
    4. using UnityEngine.UI;
    5.  
    6. public class Compass : MonoBehaviour {
    7.  
    8. public RawImage compass;
    9. public Transform player;
    10.  
    11. void Update() {
    12.  
    13. compass.uvRect = new Rect(player.localEulerAngles.y / 360f, 0, 1, 1);
    14.  
    15. }
    16.  
    17. }
    18.  
    19.  
    This is using a compass like this:

    compass1example.png

    Import it and set the wrap mode to "repeat".

    Assign it to a RawImage on your UI. (You'll probably want to make a new compass, I just made this one black because the white wouldn't show up on the background here.)

    Assign the RawImage to the public compass field in the inspector wherever you choose to put the above code, and assign the player's transform to the player field.

    I'm not sure if it's more or less efficient than the previously posted example, but I found it easier to understand, and it works the same.
     
  35. telecaster

    telecaster

    Joined:
    Jan 6, 2013
    Posts:
    29
    Thank you! this worked brilliantly - thank you Zymu - life saver!!! Works a charm. I am using it with a mask as a child to the image. Thank you.
     
  36. DBarlok

    DBarlok

    Joined:
    Apr 24, 2013
    Posts:
    268
    Thank you!!!!!! Enjoying this on a really hard prototype im doing, impossible to build without this!
     
  37. lulutube14

    lulutube14

    Joined:
    Sep 16, 2020
    Posts:
    12

    tysm! the other one didn't work for me but this worked perfectly! thank you!
     
    M0r5e80 likes this.
  38. novidd

    novidd

    Joined:
    Mar 27, 2019
    Posts:
    1
    This is exactly what I was looking for! Thank you!
     
  39. BADC00KIE

    BADC00KIE

    Joined:
    Mar 7, 2021
    Posts:
    1
    For anyone thats using this way because your compass isnt just one image and wants to have markers that loop around the south pole. The looping part took me 2 hours and I felt after taking from this post ill give something back
    Code (csharp):
    1.  
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5. using UnityEngine.UI;
    6.  
    7. public class Compass : MonoBehaviour
    8. {
    9.     [SerializeField] float rotationAngleToPixel;//-8.67
    10.     [SerializeField] RectTransform transformToMove, iconTransform;
    11.     [SerializeField] MarkerData[] markers;
    12.     [SerializeField] GameObject makerPrefab;
    13.     static MarkerData[] markersStatic;
    14.     static GameObject makerPrefabStatic;
    15.     static RectTransform iconTransformStatic;
    16.     static float rotationAngleToPixelStatic;
    17.  
    18.     static List<MarkerObject> compassMarkers = new List<MarkerObject>();
    19.  
    20.     static Transform cam;
    21.  
    22.     [System.Serializable]
    23.     struct MarkerData
    24.     {
    25.         public Sprite sprite;
    26.         public Color color;
    27.         public Vector3 size;
    28.     }
    29.  
    30.     struct MarkerObject
    31.     {
    32.         public RectTransform marker;
    33.         public RectTransform markerS;
    34.         public Transform follow;
    35.     }
    36.  
    37.     public enum MarkerType { Main, Side, Enemy, Player, Death, Base};
    38.  
    39.     void Start()
    40.     {
    41.         cam = Camera.main.transform;
    42.         markersStatic = markers;
    43.         rotationAngleToPixelStatic = rotationAngleToPixel;
    44.         makerPrefabStatic = makerPrefab;
    45.         iconTransformStatic = iconTransform;
    46.  
    47.         AddMarker(MarkerType.Main, testFollow);
    48.     }
    49.  
    50.     void FixedUpdate()
    51.     {
    52.         Vector3 facing = new Vector3(cam.forward.x, 0, cam.forward.z);
    53.  
    54.         Vector3 perp = Vector3.Cross(Vector3.forward, facing);
    55.         float dir = Vector3.Dot(perp, Vector3.up);
    56.         transformToMove.anchoredPosition = new Vector3(Vector3.Angle(facing, Vector3.forward) * Mathf.Sign(dir) * rotationAngleToPixel, 0, 0);
    57.  
    58.         if (compassMarkers.Count > 0) MoveMarkers();
    59.     }
    60.  
    61.     void MoveMarkers()
    62.     {
    63.         for (int i = 0; i < compassMarkers.Count; i++)
    64.         {
    65.             MoveMarker(compassMarkers[i]);
    66.         }
    67.     }
    68.  
    69.     static void MoveMarker(MarkerObject marker)
    70.     {
    71.         Vector3 direction = (marker.follow.position - cam.position).normalized;
    72.         Vector3 facing = new Vector3(direction.x, 0, direction.z);
    73.  
    74.         Vector3 perp = Vector3.Cross(Vector3.forward, facing);
    75.         float dir = Vector3.Dot(perp, Vector3.up);
    76.         float angle = Vector3.Angle(facing, Vector3.forward);
    77.         marker.marker.anchoredPosition = new Vector3(angle * Mathf.Sign(dir) * -rotationAngleToPixelStatic, 0, 0);//normal
    78.         marker.markerS.anchoredPosition = new Vector3(Map(angle, 0, 180, 360, 180) * Mathf.Sign(dir) * rotationAngleToPixelStatic, 0, 0);//looped
    79.     }
    80.  
    81.     static float Map(float value, float min1, float max1, float min2, float max2)
    82.     {
    83.         float perc = (value - min1) / (max1 - min1);
    84.         return perc * (max2 - min2) + min2;
    85.     }
    86.  
    87.     [SerializeField] Transform testFollow;
    88.     public static void AddMarker(MarkerType markerType, Transform follow)
    89.     {
    90.         MarkerData markerData = markersStatic[(int)markerType];
    91.  
    92.         GameObject newMarker = Instantiate(makerPrefabStatic, iconTransformStatic);
    93.         GameObject newMarkerS = Instantiate(makerPrefabStatic, iconTransformStatic);
    94.  
    95.         MarkerObject markerObject = new MarkerObject();
    96.         Image image = newMarker.GetComponent<Image>();
    97.         image.sprite = markerData.sprite;
    98.         image.color = markerData.color;
    99.  
    100.         image = newMarkerS.GetComponent<Image>();
    101.         image.sprite = markerData.sprite;
    102.         image.color = markerData.color;
    103.         markerObject.marker = newMarker.GetComponent<RectTransform>();
    104.         markerObject.markerS = newMarkerS.GetComponent<RectTransform>();
    105.         markerObject.follow = follow;
    106.  
    107.         MoveMarker(markerObject);
    108.  
    109.         compassMarkers.Add(markerObject);
    110.     }
    111.  
    112.     public static void RemoveMaker(Transform follow)
    113.     {
    114.         for (int i = 0; i < compassMarkers.Count; i++)
    115.         {
    116.             MarkerObject mark = compassMarkers[i];
    117.  
    118.             if (mark.follow == follow)
    119.             {
    120.                 Destroy(compassMarkers[i].marker.gameObject);
    121.  
    122.                 compassMarkers.RemoveAt(i);
    123.                 break;
    124.             }
    125.         }
    126.     }
    127. }
    128.  
    129.