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.
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
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.
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): function ForwardSpeed() { return Vector3.Dot(rigidbody.velocity, transform.forward); } You can then assign this value to the speed variable of the speedometer script to get the needle to move.
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.
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.
The follow code: function ForwardSpeed() { return Vector3.Dot(rigidbody.velocity, transform.forward); } returns speeds in miles? RPM? KM/h? Thanks.
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.
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.
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): function Update() { speed = Vector3.Dot(rigidbody.velocity, transform.forward); } It would have been sensible for me to add that to the file commented out, really </livesAndLearns>
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?
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.
@ 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.
c# Version : Code (csharp): using UnityEngine; using System.Collections; 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 OnGUI (){ GUI.DrawTexture( new Rect(dialPos.x, dialPos.y, dialTex.width, dialTex.height), dialTex); 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; } }
Here's a gauge...it is for KPH, but could easily be changed to MPH. http://www.blindsquirreldigital.com/downloads/unity3d/Speedometer_Gauge.psd.zip Cheers!
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): var dialTex: Texture2D; var needleTex: Texture2D; var dialPos: Vector2; var topSpeed: float; var stopAngle: float; var topSpeedAngle: float; static var speed: float; var nativeVerticalResolution = 1200.0; function OnGUI() { GUI.matrix = Matrix4x4.TRS (Vector3(0, 0, 0), Quaternion.identity, Vector3 (Screen.height / nativeVerticalResolution, Screen.height / nativeVerticalResolution, 1)); DrawImageBottomRightAligned( dialPos, dialTex); DrawNeedleBottomRightAligned( dialPos, needleTex); } function DrawImageBottomRightAligned (pos : Vector2, image : Texture2D) { var scaledResolutionWidth = nativeVerticalResolution / Screen.height * Screen.width; GUI.Label(Rect (scaledResolutionWidth - pos.x - image.width, nativeVerticalResolution - image.height - pos.y, image.width, image.height), image); } function DrawNeedleBottomRightAligned (pos : Vector2, image : Texture2D) { var scaledResolutionWidth = nativeVerticalResolution / Screen.height * Screen.width; ///the centre of the NeedleTex, this is wrong - forum PLEASE HELP me! var centre = Vector2(scaledResolutionWidth - image.width, nativeVerticalResolution - image.height); var speedFraction = speed / topSpeed; var needleAngle = Mathf.Lerp(stopAngle, topSpeedAngle, speedFraction); GUIUtility.RotateAroundPivot(needleAngle, centre); GUI.Label(Rect (scaledResolutionWidth - pos.x - image.width, nativeVerticalResolution - image.height - pos.y, image.width, image.height), image); }
Same here. I wanted to use GUI.Matrix. But, it doesnt rotate right. EDIT. I got it. Just delete the save GUI.Matrix's.
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): dialPos.x = 0; dialPos.y = Screen.height - dialTex.height
Hey, What setup do I need? Because for some reason in game when moving it doesn't show an speed update.. Thanks
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!
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....
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.
To make the speedometer stick to top right at any resolution. Just go to this below post.. http://answers.unity3d.com/questions/476447/get-android-screen-width.html
Its working fine but when we adjust the position of the GUI then its making the problem..but its working "cool"...:
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
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 ..
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.
NEEDLE POSITION NEEDED TO IMPROVED Code (CSharp): void OnGUI (){ GUI.DrawTexture( new Rect(dialPos.x, dialPos.y, dialTex.width, dialTex.height), dialTex); //UPDATED HERE 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; }
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; } }