using SFML.Graphics; using SFML.System; namespace Car_simulation.UI.Instruments { public class Speedometer { private RectangleShape _background; private RectangleShape _needle; private Font _font; private Text _label; private Text _speedText; private Text _gearText; private Color _normalColor = Color.White; private Color _highlightColor = new Color(0, 150, 255); public Vector2f Position { get; set; } public float Size { get; set; } = 200f; private float _currentSpeed = 0f; private string _currentGear = "N"; private const float MAX_SPEED = 200f; // km/h public Speedometer(Font font) { _font = font; Initialize(); } public Speedometer(Font font, Vector2f position, float size) { _font = font; Position = position; Size = size; Initialize(); } private void Initialize() { // Background _background = new RectangleShape(new Vector2f(Size, Size)); _background.Position = Position; _background.FillColor = new Color(40, 40, 50); _background.OutlineThickness = 2; _background.OutlineColor = Color.White; // Needle float needleLength = Size * 0.4f; _needle = new RectangleShape(new Vector2f(needleLength, 4)); _needle.Position = new Vector2f( Position.X + Size / 2, Position.Y + Size / 2 ); _needle.FillColor = Color.Green; _needle.Origin = new Vector2f(needleLength * 0.875f, 2); // Labels _label = new Text("SPEED", _font, (uint)(Size * 0.1f)); _label.FillColor = Color.White; _label.Position = new Vector2f( Position.X + Size / 2 - _label.GetLocalBounds().Width / 2, Position.Y + Size * 0.05f ); _speedText = new Text("0 km/h", _font, (uint)(Size * 0.1f)); _speedText.FillColor = _normalColor; _speedText.Position = new Vector2f( Position.X + Size / 2 - 40, Position.Y + Size * 0.25f ); _gearText = new Text($"GEAR {_currentGear}", _font, (uint)(Size * 0.14f)); _gearText.FillColor = _highlightColor; _gearText.Position = new Vector2f( Position.X + Size * 0.5f, Position.Y + Size * 1.1f ); } public void Update(float speed) { _currentSpeed = speed; float speedKmh = speed * 3.6f; // Update needle angle (-90° to +180° rotation) float speedRatio = Math.Clamp(speedKmh / MAX_SPEED, 0f, 1f); float needleAngle = -90 + (270 * speedRatio); _needle.Rotation = needleAngle; // Update speed text _speedText.DisplayedString = $"{speedKmh:F1} km/h"; // Center speed text FloatRect bounds = _speedText.GetLocalBounds(); _speedText.Origin = new Vector2f(bounds.Width / 2, bounds.Height / 2); _speedText.Position = new Vector2f( Position.X + Size / 2, Position.Y + Size * 0.35f ); } public void UpdateGear(string gear) { _currentGear = gear; _gearText.DisplayedString = $"GEAR {gear}"; // Center gear text FloatRect bounds = _gearText.GetLocalBounds(); _gearText.Origin = new Vector2f(bounds.Width / 2, bounds.Height / 2); _gearText.Position = new Vector2f( Position.X + Size / 2, Position.Y + Size * 1.1f ); } public void Draw(RenderWindow window) { window.Draw(_background); // Draw tick marks DrawTickMarks(window); window.Draw(_needle); window.Draw(_label); window.Draw(_speedText); window.Draw(_gearText); } private void DrawTickMarks(RenderWindow window) { for (int i = 0; i <= 10; i++) { float angle = -90 + (i * 27); // 270° divided into 10 segments float startRadius = Size * 0.45f; float endRadius = Size * 0.42f; if (i % 2 == 0) // Major tick { endRadius = Size * 0.38f; // Add number label for major ticks float speedValue = (i * MAX_SPEED / 10f); Text label = new Text($"{speedValue:F0}", _font, 12); label.FillColor = Color.White; float labelRadius = Size * 0.32f; float _radAngle = angle * (float)Math.PI / 180f; Vector2f labelPos = new Vector2f( Position.X + Size / 2 + labelRadius * (float)Math.Cos(_radAngle), Position.Y + Size / 2 + labelRadius * (float)Math.Sin(_radAngle) ); FloatRect bounds = label.GetLocalBounds(); label.Origin = new Vector2f(bounds.Width / 2, bounds.Height / 2); label.Position = labelPos; window.Draw(label); } float radAngle = angle * (float)Math.PI / 180f; Vector2f startPos = new Vector2f( Position.X + Size / 2 + startRadius * (float)Math.Cos(radAngle), Position.Y + Size / 2 + startRadius * (float)Math.Sin(radAngle) ); Vector2f endPos = new Vector2f( Position.X + Size / 2 + endRadius * (float)Math.Cos(radAngle), Position.Y + Size / 2 + endRadius * (float)Math.Sin(radAngle) ); Vertex[] line = new Vertex[2] { new Vertex(startPos, Color.White), new Vertex(endPos, Color.White) }; window.Draw(line, PrimitiveType.Lines); } } public void SetPosition(Vector2f position) { Position = position; Initialize(); // Re-initialize with new position } public void SetSize(float size) { Size = size; Initialize(); // Re-initialize with new size } public void SetGearColor(Color color) { _gearText.FillColor = color; } public void SetNeedleColor(Color color) { _needle.FillColor = color; } } }