Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Car speedometer dial

Discussion in 'Scripting' started by andeeeee, Oct 15, 2010.

  1. andeeeee

    andeeeee

    Joined:
    Jul 19, 2005
    Posts:
    8,768
    Not every man can make speedos work. I'm just one of the lucky few, I guess ;-)

    Attached is an example of how to make a gauge with a rotating needle on a dial. I've designed it around the idea of a car speedometer but the basic technique can be applied to any similar kind of dial.

    A little tip for getting the start and end angles right for your dial. Set the speed to 0mph and set the game running. Then, change the stopAngle value until it matches the the 0mph point on your dial. Note the number and then set the speed to the top speed. Now, change the topSpeedAngle value until it matches the upper limit of the dial and note this number down. When you stop the game, you just need to put the noted numbers back in the variables. And the job's a good 'un.
     

    Attached Files:

    EdwinChua and Deleted User like this.
  2. Thomas Bayley

    Thomas Bayley

    Joined:
    Oct 7, 2010
    Posts:
    4
    Hi Andeeee,

    Thanks so much for going above and beyond on my account. This is an awesome gift and you are very very kind. Your helpful tip to define the topSpeedAngle is inspired too. You are awesome!

    Best regards,
    Tom
     
  3. n0mad

    n0mad

    Joined:
    Jan 27, 2009
    Posts:
    3,732
    Cool, thanks :)
     
  4. QuantumCalzone

    QuantumCalzone

    Joined:
    Jan 9, 2010
    Posts:
    262
  5. ColossalDuck

    ColossalDuck

    Joined:
    Jun 6, 2009
    Posts:
    3,246
    I love thee. Bookmarked.
     
  6. Thomas Bayley

    Thomas Bayley

    Joined:
    Oct 7, 2010
    Posts:
    4
    Does this dial need anymore script to read a rigidbody for example? My box collider I have assigned to the car is reading the 'Player' tag and my score updates, but the needle on this dial still does not move. I don't want to be looking at a gift horse power in the mouth and know that there is a trick here I am missing. I am presently combining the Car tutorial with the Lerpz tutorial adopting all the game assets to create a test drive that knocks a point off every road cone you hit. It is very entertaining and would like to share it with you when its finished.

    Please provide another clue.
     
  7. andeeeee

    andeeeee

    Joined:
    Jul 19, 2005
    Posts:
    8,768
    The position of the needle is determined by the value of the speed variable, so you need to set the speed yourself from another script. (If you're wondering, I deliberately didn't tie the script to using a rigidbody, since the game doesn't necessarily use physics). A simple way to get the rigidbody's speed is to get the magnitude of the velocity vector. However, it is more realistic (and also more efficient, surprisingly) to get the speed the car is moving in its forward direction. You can do that easily using a dot product as follows:-
    Code (csharp):
    1. function ForwardSpeed() {
    2.   return Vector3.Dot(rigidbody.velocity, transform.forward);
    3. }
    You can then assign this value to the speed variable of the speedometer script to get the needle to move.
     
  8. etomp10291

    etomp10291

    Joined:
    Jan 11, 2010
    Posts:
    108
    how could i modify this as an altimeter? been trying to create an altimeter for my flight sim game but not having much luck.

    thanks for any help you can offer.
     
  9. andeeeee

    andeeeee

    Joined:
    Jul 19, 2005
    Posts:
    8,768
    Getting the height value should be no problem (in most cases it would just be the Y coordinate, but if you've got a spherical planet, for example, then it would be the distance from the centre of the sphere). Other than that, it's just a matter of remembering that where the script says "speed", it really means height from your point of view. Naturally, you can do a find-and-replace on the script to make things clearer if necessary.
     
  10. fdfragoso

    fdfragoso

    Joined:
    Nov 15, 2010
    Posts:
    35
    The follow code:

    function ForwardSpeed() {
    return Vector3.Dot(rigidbody.velocity, transform.forward);
    }

    returns speeds in miles? RPM? KM/h?

    Thanks.
     
  11. Quietus2

    Quietus2

    Joined:
    Mar 28, 2008
    Posts:
    2,058
    Can't really answer that question as it's a function of your world's scale. A value returned of 100 obviously doesn't mean the same thing if your model is 100 unity units large vs .01.

    If the model is built/imported into Unity at 1 unit = 1 meter, then the value will obviously be in meters per second.
     
  12. TheWetFloorSign

    TheWetFloorSign

    Joined:
    Nov 13, 2010
    Posts:
    5
    I don't mean to sound really stupid, but I'm new with trying to code with Unity, or anything really. How would I get the speed on the speedometer to link with the rigidbody speed exactly? I understand the math and the coding in the script itself, but not how I can target the rigidbody.
     
  13. andeeeee

    andeeeee

    Joined:
    Jul 19, 2005
    Posts:
    8,768
    The code in the ForwardSpeed function posted above is all you need to get the speed. You can then use that to set the speedometer reading. The easiest way to go is to add an Update function to the speedometer script which contains the active code from the function:-
    Code (csharp):
    1. function Update() {
    2.   speed = Vector3.Dot(rigidbody.velocity, transform.forward);
    3. }
    It would have been sensible for me to add that to the file commented out, really </livesAndLearns>
     
  14. TheWetFloorSign

    TheWetFloorSign

    Joined:
    Nov 13, 2010
    Posts:
    5
    Putting the update function in the speedo code still doesn't cause the needle to move for me. The position is still being determined by the speed input in the inspector. Am I just missing something obvious?
     
  15. TheWetFloorSign

    TheWetFloorSign

    Joined:
    Nov 13, 2010
    Posts:
    5
    Actually, is the script attached to the car, a GUI texture, or a new empty? I know, I'm dumb.
     
  16. Holynub

    Holynub

    Joined:
    Nov 9, 2010
    Posts:
    60
    This is unpossibly awesome. How does you do this!? HOW DOES?!
     
  17. Holynub

    Holynub

    Joined:
    Nov 9, 2010
    Posts:
    60
    Quick question. How difficult do you think this would be to implement as a tachometer(Thing that measures RPM... That's a tachometer right?)? I got it basically setup. But it jumps back to the zero position when gears change. I'm guessing I'd need to implement some kind of reset pause that brings the needle back down.
     
  18. konzon

    konzon

    Joined:
    Mar 2, 2010
    Posts:
    51
    Anybody find some nice speedometer / rpm gauge art out there?
     
  19. konzon

    konzon

    Joined:
    Mar 2, 2010
    Posts:
    51
    @ WetFloor - With this piece of update code all you have done is updated the speed variable. You still have to set the speed attribute of the game object component to which your speedo script is attached.
     
    Last edited: Nov 25, 2010
  20. Yusuf-AKDAG

    Yusuf-AKDAG

    Joined:
    May 13, 2009
    Posts:
    280
    c# Version :
    Code (csharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class SpeedometerUI : MonoBehaviour {
    5. public Texture2D dialTex;
    6. public Texture2D needleTex;
    7. public Vector2 dialPos;
    8. public float topSpeed=0;
    9. public float stopAngle=0;
    10. public float topSpeedAngle=0;
    11. public float speed=0;
    12.  
    13.  
    14. void  OnGUI (){
    15.     GUI.DrawTexture( new Rect(dialPos.x, dialPos.y, dialTex.width, dialTex.height), dialTex);
    16.     Vector2 centre= new Vector2((dialPos.x + dialTex.width) / 2, (dialPos.y + dialTex.height) / 2);
    17.     Matrix4x4 savedMatrix= GUI.matrix;
    18.     float speedFraction= speed / topSpeed;
    19.     float needleAngle= Mathf.Lerp(stopAngle, topSpeedAngle, speedFraction);
    20.     GUIUtility.RotateAroundPivot(needleAngle, centre);
    21.     GUI.DrawTexture( new Rect(centre.x, centre.y - needleTex.height / 2, needleTex.width, needleTex.height), needleTex);
    22.     GUI.matrix = savedMatrix;
    23. }
    24. }
     
    szczygly likes this.
  21. PaulHarisson

    PaulHarisson

    Joined:
    Jan 31, 2011
    Posts:
    13
    Thank u Andeee, it works great
     
  22. Spookytooth

    Spookytooth

    Joined:
    Jun 27, 2009
    Posts:
    57
  23. zappapa

    zappapa

    Joined:
    Dec 12, 2010
    Posts:
    57
    I just can't figure this out. Allthough the speedometer background and the needle scales fine with this script, I just cannot get the right pivotpoint for the needle. It rotates but it doesn't rotate around the centre of the needle. My needle has the same size (512x512) as the speedometer background. I used Spookytooth's artwork for testing purposes. So the centre of the needle is exactly in the centre of the needle image. Does anybody know what's wrong here? Here's my code:

    Code (csharp):
    1. var dialTex: Texture2D;
    2. var needleTex: Texture2D;
    3. var dialPos: Vector2;
    4. var topSpeed: float;
    5. var stopAngle: float;
    6. var topSpeedAngle: float;
    7. static var speed: float;
    8. var nativeVerticalResolution = 1200.0;
    9.  
    10.  
    11.  
    12. function OnGUI() {
    13.    
    14.     GUI.matrix = Matrix4x4.TRS (Vector3(0, 0, 0), Quaternion.identity, Vector3 (Screen.height / nativeVerticalResolution, Screen.height / nativeVerticalResolution, 1));
    15.     DrawImageBottomRightAligned( dialPos, dialTex);
    16.     DrawNeedleBottomRightAligned( dialPos, needleTex);
    17.  
    18. }
    19.  
    20. function DrawImageBottomRightAligned (pos : Vector2, image : Texture2D)
    21. {
    22.     var scaledResolutionWidth = nativeVerticalResolution / Screen.height * Screen.width;
    23.     GUI.Label(Rect (scaledResolutionWidth - pos.x - image.width, nativeVerticalResolution - image.height - pos.y, image.width, image.height), image);
    24. }
    25.  
    26.  
    27. function DrawNeedleBottomRightAligned (pos : Vector2, image : Texture2D)
    28. {
    29.     var scaledResolutionWidth = nativeVerticalResolution / Screen.height * Screen.width;
    30.  
    31.     ///the centre of the NeedleTex, this is wrong - forum PLEASE HELP me!
    32.  
    33.     var centre = Vector2(scaledResolutionWidth - image.width, nativeVerticalResolution - image.height);
    34.     var speedFraction = speed / topSpeed;
    35.     var needleAngle = Mathf.Lerp(stopAngle, topSpeedAngle, speedFraction);
    36.     GUIUtility.RotateAroundPivot(needleAngle, centre);
    37.    
    38.     GUI.Label(Rect (scaledResolutionWidth - pos.x - image.width, nativeVerticalResolution - image.height - pos.y, image.width, image.height), image);
    39.  
    40. }
     
    Last edited: Mar 26, 2011
  24. OttoFish

    OttoFish

    Joined:
    Jun 15, 2011
    Posts:
    1
    Hey, thanks for your generosity!! I modified it to work as a nice looking variometer.
     
  25. carking1996

    carking1996

    Joined:
    Jun 15, 2010
    Posts:
    2,608
    Same here. I wanted to use GUI.Matrix. But, it doesnt rotate right.

    EDIT. I got it. Just delete the save GUI.Matrix's. ;)
     
    Last edited: Jun 23, 2011
  26. carking1996

    carking1996

    Joined:
    Jun 15, 2010
    Posts:
    2,608
    Are there any ways to make it stay on the position on the screen? It moves depending on the res. :confused:
     
  27. andeeeee

    andeeeee

    Joined:
    Jul 19, 2005
    Posts:
    8,768
    If you need to make it work with multiple resolutions then you will need to calculate the dialPos X and Y values rather than relying on stored values. How you do the calculation will depend on exactly where on the screen you want the dial to appear. The position will usually be relative to the screen's centre, a corner or some other defined marker point. For example, if you want the dial to appear in the bottom left corner then you should use code like the following to position it:-
    Code (csharp):
    1. dialPos.x = 0;
    2. dialPos.y = Screen.height - dialTex.height
     
  28. carking1996

    carking1996

    Joined:
    Jun 15, 2010
    Posts:
    2,608
    Thankyou for the answer, but...

    I am confused on how I would implement those. Any ideas?
     
  29. JamesArndt

    JamesArndt

    Joined:
    Dec 1, 2009
    Posts:
    2,932
    Yeah Im wondering how to set this up as well?
     
  30. MikePalmer

    MikePalmer

    Joined:
    Dec 10, 2011
    Posts:
    20
    Hey,

    What setup do I need? Because for some reason in game when moving it doesn't show an speed update.. Thanks
     
  31. agenda.

    agenda.

    Joined:
    May 8, 2010
    Posts:
    21
    very good! thx:)


    JamesArndt
    MikePalmer

    place the script on your vehicle.


    use update function as specified earlier in the thread.:


    function Update(){
    speed = Vector3.Dot(rigidbody.velocity, transform.forward);
    }




    worked for me!
     
    Last edited: Dec 11, 2011
  32. carking1996

    carking1996

    Joined:
    Jun 15, 2010
    Posts:
    2,608
    I have it so it stays at a portion of the screen, but it doesn't resize. any ideas?
     
  33. gotanidea

    gotanidea

    Joined:
    Jun 30, 2012
    Posts:
    1
    Hi Andeeee,

    Thanks a lot for the speedometer. It works great.

    But I have the same problem as zappapa and carking. How to scale the speedometer if the screen size changes?

    Right now the speedometer doesn't resize if the screen size changes....
     
  34. diepnh2

    diepnh2

    Joined:
    Nov 6, 2012
    Posts:
    1

    Thanks Andeeee !
    I have a question. I have done like this way: http://answers.unity3d.com/questions/15414/how-can-i-make-an-on-screen-speedometer.html , and change his prefab to your prefab you have attached, but i don't know how does it work, it doesn't draw anything on my GUI. I will very happy if you can help. I am waiting for your answer.

    Best regards.
     
  35. Orloffyeah

    Orloffyeah

    Joined:
    Dec 9, 2012
    Posts:
    4
    The speedometer just detects up to speed 2 and when im moving to the right, not forward.
     
  36. DarkJoney

    DarkJoney

    Joined:
    Jan 31, 2013
    Posts:
    24
    Didn't work :(
    I setup it using a tutorial at this topic, but needle woun't rotate.
     
  37. Deleted User

    Deleted User

    Guest

  38. noldy

    noldy

    Joined:
    May 20, 2013
    Posts:
    3
    help me arrow can't rotate :-|
     
  39. rameshkumar

    rameshkumar

    Joined:
    Aug 5, 2013
    Posts:
    50
    Its working fine but when we adjust the position of the GUI then its making the problem..but its working "cool"...::D
     
  40. superrbryan

    superrbryan

    Joined:
    Dec 16, 2013
    Posts:
    1
    Hi. I've already downloaded the zip file, extract it and then here's the outcome. How can I attach this speedometer on my car game? can somebody help me? I'm a newbie here in Unity mehehehe. Thanks :) http://tinypic.com/r/fpcz60/5
     
  41. jho_2212

    jho_2212

    Joined:
    Jan 23, 2014
    Posts:
    1
    Hi guys please help me .. i want add speed indicator to my game .. and i have one error ..

    this is the error.

    UnassignedReferenceException: The variable myWC of 'Car' has not been assigned.
    You probably need to assign the myWC variable of the Car script in the inspector.

    and this is the line with error


    currentSpeed = (Mathf.PI*2*myWC.radius)*myWC.rpm*0/1000;

    hope to help me guys .. i really need ur help guys thanks ..
     
  42. smurfgenio

    smurfgenio

    Joined:
    Apr 19, 2015
    Posts:
    1
    In Unity5, already using CANVAS. Add the speedometer needle to Canvas and write that:

    kph = GetComponent<Rigidbody>().velocity.magnitude * 3.6f; //for MPH replace 3.6f by 2.27f
    needleSprite.localRotation = Quaternion.Euler(0, 0, initialAngle-kph); //initialAngle is the ZERO mark on your dial.
     
    Crysis6161 likes this.
  43. Nirav-Madhani

    Nirav-Madhani

    Joined:
    Jan 8, 2014
    Posts:
    27
    NEEDLE POSITION NEEDED TO IMPROVED



    Code (CSharp):
    1.     void  OnGUI (){
    2.  
    3.         GUI.DrawTexture( new Rect(dialPos.x, dialPos.y, dialTex.width, dialTex.height), dialTex);
    4. //UPDATED HERE      
    5.   Vector2 centre= new Vector2((dialPos.x )+ dialTex.width / 2, (dialPos.y )+ dialTex.height / 2);
    6.         Matrix4x4 savedMatrix= GUI.matrix;
    7.         float speedFraction= speed / topSpeed;
    8.         float needleAngle= Mathf.Lerp(stopAngle, topSpeedAngle, speedFraction);
    9.         GUIUtility.RotateAroundPivot(needleAngle, centre);
    10.         GUI.DrawTexture( new Rect(centre.x, centre.y - needleTex.height / 2, needleTex.width, needleTex.height), needleTex);
    11.         GUI.matrix = savedMatrix;
    12.     }
     
  44. Idris-Fuquan

    Idris-Fuquan

    Joined:
    Aug 6, 2016
    Posts:
    5
    I am not sure if this post is still active but I do hope it is: Anyway, I have added the script supplied by "Andeeee" above on my vehicle but unfortunately I have two main complications. 1) The "pivot" issue as mentioned by someone above, as I have followed the threads and have been unable to find a practical solution that really works (even tried the "RotatableGuiItem" solution but that creates and works on another instance of the needle which is not what I require here. And 2) The "needle position" I am unable to figure out how to align it accurately with the dial Meter. (see image attached).

    One of the above proposed fixes for problem 2 above mentioned removing the "saved matrix" lines but that does not really solve the problem either as it only serves to angle it but not in the desired location.

    If someone with a working solution is able to help that would be very much appreciated:

    Thanks
    Fuquan


    The code used has not been altered as you can see below:
    =============================================
    public class SpeedometerUI : MonoBehaviour
    {
    public Texture2D dialTex;
    public Texture2D needleTex;
    public Vector2 dialPos;
    public float topSpeed=0;
    public float stopAngle=0;
    public float topSpeedAngle=0;
    public float speed=0;

    void Update()
    {
    speed = Vector3.Dot(GetComponent<Rigidbody>().velocity, transform.forward);
    }

    void OnGUI (){
    GUI.DrawTexture( new Rect(dialPos.x, dialPos.y, dialTex.width, dialTex.height), dialTex);
    dialPos.x = Screen.width - 500;
    dialPos.y = Screen.height - dialTex.height;


    Vector2 centre= new Vector2((dialPos.x )+ dialTex.width / 2, (dialPos.y )+ dialTex.height / 2);
    //Vector2 centre= new Vector2((dialPos.x + dialTex.width) / 2, (dialPos.y + dialTex.height) / 2);
    Matrix4x4 savedMatrix= GUI.matrix;
    float speedFraction= speed / topSpeed;
    float needleAngle= Mathf.Lerp(stopAngle, topSpeedAngle, speedFraction);
    GUIUtility.RotateAroundPivot(needleAngle, centre);
    GUI.DrawTexture( new Rect(centre.x, centre.y - needleTex.height / 2, needleTex.width, needleTex.height), needleTex);

    GUI.matrix = savedMatrix;
    }
    }
     

    Attached Files:

  45. HunterNacho338

    HunterNacho338

    Joined:
    Aug 30, 2015
    Posts:
    17
    This works really well, thanks man! :)
     
  46. TheTrollPlays

    TheTrollPlays

    Joined:
    Feb 26, 2017
    Posts:
    2
    How do I resize it? halp