major rework

This commit is contained in:
max
2026-02-16 18:32:48 +01:00
parent bbd82da07e
commit 932734e5b4
24 changed files with 1706 additions and 893 deletions

View File

@@ -0,0 +1,164 @@
using SFML.Graphics;
using SFML.System;
namespace Car_simulation.UI.Instruments
{
public class Gauge
{
private RectangleShape _background;
private RectangleShape _needle;
private Font _font;
private Text _label;
private Text _valueText;
private Color _normalColor = Color.White;
private Color _warningColor = new Color(255, 100, 100);
public Vector2f Position { get; set; }
public float Size { get; set; } = 200f;
private float _value = 0f;
private float _minValue;
private float _maxValue;
private float _valuePerMark;
private float _linesPerMark;
private string _displayText;
public Gauge(Font font, Vector2f position, float size, float minValue, float maxValue, float valuePerMark, string _displayText, float linesPerMark)
{
_minValue = minValue;
_maxValue = maxValue;
_linesPerMark = linesPerMark
_valuePerMark = valuePerMark;
_font = font;
Position = position;
Size = size;
Initialize();
}
private void Initialize()
{
_background = new RectangleShape(new Vector2f(Size, Size));
_background.Position = Position;
_background.FillColor = new Color(40, 40, 50);
_background.OutlineThickness = 2;
_background.OutlineColor = Color.White;
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.Red;
_needle.Origin = new Vector2f(needleLength * 0.875f, 2);
_label = new Text(_displayText, _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.80f
);
_valueText = new Text("0", _font, (uint)(Size * 0.12f));
_valueText.FillColor = _normalColor;
_valueText.Position = new Vector2f(
Position.X + Size / 2 - 20,
Position.Y + Size
);
}
public void Update(float value)
{
_value = value;
_minValue
float ratio = Math.Clamp(_value / _maxValue, 0f, 1f);
float needleAngle = -45 + (270 * ratio);
_needle.Rotation = needleAngle;
_valueText.DisplayedString = $"{_value:F0}";
FloatRect bounds = _valueText.GetLocalBounds();
_valueText.Origin = new Vector2f(bounds.Width / 2, bounds.Height / 2);
_valueText.Position = new Vector2f(
Position.X + Size / 2,
Position.Y + Size * 0.35f
);
}
public void Draw(RenderWindow window)
{
window.Draw(_background);
DrawTickMarks(window);
window.Draw(_needle);
window.Draw(_label);
window.Draw(_valueText);
}
private void DrawTickMarks(RenderWindow window)
{
float targetAngle = 270;
int marks = (int)MathF.Ceiling(_maxValue / 1000) * 2;
for (int i = marks; i >= 0; i--)
{
float angle = 135 + (i * (targetAngle / marks)); // 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;
float rpmValue = (i * 1000);
Text label = new Text($"{rpmValue / 2000: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
}
}
}

View File

@@ -0,0 +1,73 @@
using Car_simulation.Core.Models;
using SFML.Graphics;
using SFML.System;
namespace Car_simulation.UI.Instruments
{
public class InstrumentPanel
{
private List<Text> _displayTexts = new List<Text>();
private Tachometer _tachometer;
private Speedometer _speedometer;
private Font _font;
private Color _textColor = Color.White;
public InstrumentPanel(Font font, Vector2f tachometerPosition, Vector2f speedometerPosition)
{
_font = font;
_tachometer = new Tachometer(font, tachometerPosition, 200, 7000);
_speedometer = new Speedometer(font, speedometerPosition, 200);
InitializeDisplayTexts();
}
private void InitializeDisplayTexts()
{
for (int i = 0; i < 30; i++)
{
Text text = new Text("", _font, 16);
text.FillColor = Color.White;
text.Position = new Vector2f(20, 20 + i * 24);
_displayTexts.Add(text);
}
}
public void Update(Car_simulation.Core.Models.Car car)
{
UpdateTextDisplay(car);
_tachometer.Update(car.Engine.RPM);
_speedometer.Update(car.Speed);
}
private void UpdateTextDisplay(Car car)
{
var displayData = car.GetDisplayData();
// Just put each line in a text element
for (int i = 0; i < _displayTexts.Count; i++)
{
if (i < displayData.Count)
{
_displayTexts[i].DisplayedString = displayData[i];
_displayTexts[i].FillColor = _textColor;
}
else
{
_displayTexts[i].DisplayedString = "";
}
}
}
public void Draw(RenderWindow window)
{
foreach (var text in _displayTexts)
{
if (!string.IsNullOrEmpty(text.DisplayedString))
window.Draw(text);
}
_tachometer.Draw(window);
_speedometer.Draw(window);
}
}
}

View File

@@ -0,0 +1,201 @@
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;
}
}
}

View File

@@ -0,0 +1,161 @@
using SFML.Graphics;
using SFML.System;
namespace Car_simulation.UI.Instruments
{
public class Tachometer
{
private RectangleShape _background;
private RectangleShape _needle;
private Font _font;
private Text _label;
private Text _rpmText;
private Color _normalColor = Color.White;
private Color _warningColor = new Color(255, 100, 100);
public Vector2f Position { get; set; }
public float Size { get; set; } = 200f;
private float _currentRPM = 0f;
private float _maxRpm = 7000f;
public Tachometer(Font font, Vector2f position, float size, float maxRpm)
{
_maxRpm = maxRpm;
_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.Red;
_needle.Origin = new Vector2f(needleLength * 0.875f, 2); // Offset origin to create pivot point
// Labels
_label = new Text("RPM", _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.80f
);
_rpmText = new Text("0", _font, (uint)(Size * 0.12f));
_rpmText.FillColor = _normalColor;
_rpmText.Position = new Vector2f(
Position.X + Size / 2 - 20,
Position.Y + Size
);
}
public void Update(float rpm)
{
_currentRPM = rpm;
float rpmRatio = Math.Clamp(rpm / _maxRpm, 0f, 1f);
float needleAngle = -45 + (270 * rpmRatio);
_needle.Rotation = needleAngle;
// Update RPM text
_rpmText.DisplayedString = $"{rpm:F0}";
// Center RPM text
FloatRect bounds = _rpmText.GetLocalBounds();
_rpmText.Origin = new Vector2f(bounds.Width / 2, bounds.Height / 2);
_rpmText.Position = new Vector2f(
Position.X + Size / 2,
Position.Y + Size * 0.35f
);
}
public void Draw(RenderWindow window)
{
window.Draw(_background);
DrawTickMarks(window);
window.Draw(_needle);
window.Draw(_label);
window.Draw(_rpmText);
}
private void DrawTickMarks(RenderWindow window)
{
float targetAngle = 270;
int marks = (int)MathF.Ceiling(_maxRpm / 1000) * 2;
for (int i = marks; i >= 0; i--)
{
float angle = 135 + (i * (targetAngle / marks)); // 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;
float rpmValue = (i * 1000);
Text label = new Text($"{rpmValue / 2000: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
}
}
}