diff --git a/Car simulation/Car simulation.csproj b/Car simulation/Car simulation.csproj
index 027dfcc..92d9b96 100644
--- a/Car simulation/Car simulation.csproj
+++ b/Car simulation/Car simulation.csproj
@@ -1,7 +1,7 @@
- Exe
+ WinExe
net10.0
Car_simulation
enable
@@ -12,4 +12,10 @@
+
+
+ PreserveNewest
+
+
+
diff --git a/Car simulation/Car.cs b/Car simulation/Car.cs
index 3f9ae6f..fd8a0a6 100644
--- a/Car simulation/Car.cs
+++ b/Car simulation/Car.cs
@@ -48,6 +48,33 @@ namespace Car_simulation
InitializeAudio();
}
+ public List GetDisplayData()
+ {
+ return new List
+ {
+ $"Engine Energy: {Engine.FlywheelEnergy,7:F0} J",
+ $"Engine Torque: {Engine.GetTorqueOutput(),7:F0} Nm",
+ $"Engine RPM: {Engine.RPM,7:F0}",
+ $"Total Energy: {WheelSystem.TotalEnergy,7:F0} J",
+ $" (Wheel Rot: {WheelSystem.GetRotationalEnergy(),7:F0} J)",
+ $" (Car Trans: {WheelSystem.GetTranslationalEnergy(),7:F0} J)",
+ $"Wheel RPM: {WheelSystem.RPM,7:F0}",
+ $"Vehicle: {Speed * 3.6f,7:F1} km/h",
+ $"Throttle: {Engine.GetActualThrottle() * 100,6:F1}%",
+ $"Power: {Engine.CurrentPower / 1000,6:F1} kW",
+ $"Transmitted: {Drivetrain.TransmittedPower / 1000,6:F1} kW",
+ $"Brake: {BrakeInput * 100,6:F1}%",
+ $"Speed Diff: {Drivetrain.GetSpeedDifferenceRPM(),6:F0} RPM",
+ $"Clutch: {ClutchInput * 100,6:F1}% disengaged",
+ $"Clutch T: {Drivetrain.ClutchTorque,6:F0} Nm",
+ $"Clutch Slip: {Drivetrain.GetClutchSlipPercent(),6:F1}%",
+ $"Resistance: {CalculateTotalResistanceForce(),6:F1} N",
+ $"Drag: {CalculateDragForce(),6:F1} N",
+ $"Rolling: {CalculateRollingResistanceForce(),6:F1} N",
+ $"Gear: {Drivetrain.GetCurrentGearName(),3} (Ratio: {Drivetrain.GearRatio:F2}:1)"
+ };
+ }
+
private void InitializeAudio()
{
try
@@ -120,40 +147,15 @@ namespace Car_simulation
return dragForce + rollingForce;
}
- private float CalculateDragForce()
+ public float CalculateDragForce()
{
float speed = Speed;
return 0.5f * AirDensity * DragCoefficient * FrontalArea * speed * speed;
}
- private float CalculateRollingResistanceForce()
+ public float CalculateRollingResistanceForce()
{
return RollingResistanceCoefficient * Mass * 9.81f;
}
-
- public void DisplayUpdate()
- {
- Console.SetCursorPosition(0, 0);
- Console.WriteLine($"Engine Energy: {Engine.FlywheelEnergy,7:F0} J");
- Console.WriteLine($"Engine Torque: {Engine.GetTorqueOutput(),7:F0} Nm");
- Console.WriteLine($"Engine RPM: {Engine.RPM,7:F0}");
- Console.WriteLine($"Total Energy: {WheelSystem.TotalEnergy,7:F0} J");
- Console.WriteLine($" (Wheel Rot: {WheelSystem.GetRotationalEnergy(),7:F0} J)");
- Console.WriteLine($" (Car Trans: {WheelSystem.GetTranslationalEnergy(),7:F0} J)");
- Console.WriteLine($"Wheel RPM: {WheelSystem.RPM,7:F0}");
- Console.WriteLine($"Vehicle: {Speed * 3.6f,7:F1} km/h");
- Console.WriteLine($"Throttle: {Engine.GetActualThrottle() * 100,6:F1}%");
- Console.WriteLine($"Power: {Engine.CurrentPower / 1000,6:F1} kW");
- Console.WriteLine($"Transmitted: {Drivetrain.TransmittedPower / 1000,6:F1} kW");
- Console.WriteLine($"Brake: {BrakeInput * 100,6:F1}%");
- Console.WriteLine($"Speed Diff: {Drivetrain.GetSpeedDifferenceRPM(),6:F0} RPM");
- Console.WriteLine($"Clutch: {ClutchInput * 100,6:F1}% disengaged");
- Console.WriteLine($"Clutch T: {Drivetrain.ClutchTorque,6:F0} Nm");
- Console.WriteLine($"Clutch Slip: {Drivetrain.GetClutchSlipPercent(),6:F1}%");
- Console.WriteLine($"Resistance: {CalculateTotalResistanceForce(),6:F1} N");
- Console.WriteLine($"Drag: {CalculateDragForce(),6:F1} N");
- Console.WriteLine($"Rolling: {CalculateRollingResistanceForce(),6:F1} N");
- Console.WriteLine($"Gear: {Drivetrain.GetCurrentGearName(),3} (Ratio: {Drivetrain.GearRatio:F2}:1)");
- }
}
}
\ No newline at end of file
diff --git a/Car simulation/EngineSound.cs b/Car simulation/EngineSound.cs
index bd8a66b..eace81c 100644
--- a/Car simulation/EngineSound.cs
+++ b/Car simulation/EngineSound.cs
@@ -9,7 +9,7 @@ namespace Car_simulation
// Audio properties - smaller buffer for less latency
private const uint SAMPLE_RATE = 44100;
private const ushort CHANNEL_COUNT = 2; // Stereo
- private const float BUFFER_DURATION = 0.01f; // 10ms instead of 50ms!
+ private const float BUFFER_DURATION = 0.05f; // 10ms instead of 50ms!
// Engine sound properties - NO SMOOTHING for instant response
private volatile float _currentRPM = 800f; // volatile for thread safety
@@ -44,8 +44,6 @@ namespace Car_simulation
{
_harmonicPhases[i] = (float)(_random.NextDouble() * 2 * Math.PI);
}
-
- Console.WriteLine($"EngineSound initialized: {BUFFER_DURATION * 1000:F0}ms buffer, {CylinderCount} cylinders");
}
// CALL THIS FROM YOUR PHYSICS THREAD - INSTANT UPDATE
diff --git a/Car simulation/Program.cs b/Car simulation/Program.cs
index 733ee76..51aaa54 100644
--- a/Car simulation/Program.cs
+++ b/Car simulation/Program.cs
@@ -2,7 +2,8 @@
using SFML.Window;
using SFML.Graphics;
using SFML.System;
-using System.Diagnostics;
+using System.Collections.Generic;
+using System;
internal class Program
{
@@ -10,6 +11,18 @@ internal class Program
private bool _isRunning = true;
private RenderWindow _window;
+ private Font _font;
+ private List _displayTexts = new List();
+ private RectangleShape _tachometerBackground;
+ private RectangleShape _tachometerNeedle;
+ private RectangleShape _speedometerBackground;
+ private RectangleShape _speedometerNeedle;
+
+ // Colors
+ private Color _backgroundColor = new Color(20, 20, 30);
+ private Color _textColor = new Color(220, 220, 220);
+ private Color _highlightColor = new Color(0, 150, 255);
+ private Color _warningColor = new Color(255, 100, 100);
// Timing for physics
private Clock _clock = new Clock();
@@ -28,7 +41,7 @@ internal class Program
private void Run()
{
- _window = new RenderWindow(new VideoMode(800, 600), "Car Simulation", Styles.Default);
+ _window = new RenderWindow(new VideoMode(1000, 800), "Car Simulation", Styles.Default);
_window.SetVisible(true);
_window.SetFramerateLimit(60);
_window.SetKeyRepeatEnabled(false);
@@ -37,6 +50,17 @@ internal class Program
_window.KeyPressed += OnKeyPressed;
_window.KeyReleased += OnKeyReleased;
+ // Load font
+ try
+ {
+ _font = new Font("arial.ttf");
+ }
+ catch
+ {
+ _font = new Font("C:/Windows/Fonts/arial.ttf");
+ }
+
+ InitializeDisplay();
InitializeTrackedKeys();
_clock.Restart();
@@ -54,14 +78,10 @@ internal class Program
car.Update(_timePerUpdate.AsSeconds());
_accumulatedTime -= _timePerUpdate;
_updateCount++;
-
- if (_accumulatedTime >= Time.FromSeconds(0.2f))
- {
- _accumulatedTime = _timePerUpdate;
- }
}
UpdateDisplay();
+ _window.Display();
UpdatePreviousKeyStates();
}
@@ -69,111 +89,238 @@ internal class Program
Console.WriteLine($"\nSimulation stopped after {_updateCount} updates");
}
+ private void InitializeDisplay()
+ {
+ // Initialize display texts
+ for (int i = 0; i < 30; i++)
+ {
+ Text text = new Text("", _font, 16);
+ text.FillColor = _textColor;
+ text.Position = new Vector2f(20, 20 + i * 24);
+ _displayTexts.Add(text);
+ }
+
+ // Tachometer
+ _tachometerBackground = new RectangleShape(new Vector2f(200, 200));
+ _tachometerBackground.Position = new Vector2f(700, 50);
+ _tachometerBackground.FillColor = new Color(40, 40, 50);
+ _tachometerBackground.OutlineThickness = 2;
+ _tachometerBackground.OutlineColor = Color.White;
+
+ _tachometerNeedle = new RectangleShape(new Vector2f(80, 4));
+ _tachometerNeedle.Position = new Vector2f(800, 150);
+ _tachometerNeedle.FillColor = Color.Red;
+ _tachometerNeedle.Origin = new Vector2f(70, 2);
+
+ // Speedometer
+ _speedometerBackground = new RectangleShape(new Vector2f(200, 200));
+ _speedometerBackground.Position = new Vector2f(700, 300);
+ _speedometerBackground.FillColor = new Color(40, 40, 50);
+ _speedometerBackground.OutlineThickness = 2;
+ _speedometerBackground.OutlineColor = Color.White;
+
+ _speedometerNeedle = new RectangleShape(new Vector2f(80, 4));
+ _speedometerNeedle.Position = new Vector2f(800, 400);
+ _speedometerNeedle.FillColor = Color.Green;
+ _speedometerNeedle.Origin = new Vector2f(70, 2);
+ }
+
+ private void UpdateDisplay()
+ {
+ _window.Clear(_backgroundColor);
+
+ UpdateDisplayTexts();
+
+ foreach (var text in _displayTexts)
+ {
+ if (!string.IsNullOrEmpty(text.DisplayedString))
+ _window.Draw(text);
+ }
+
+ DrawGauges();
+ DrawKeyBindings();
+ }
+
+ private void UpdateDisplayTexts()
+ {
+ // Clear all text
+ for (int i = 0; i < _displayTexts.Count; i++)
+ {
+ _displayTexts[i].DisplayedString = "";
+ _displayTexts[i].FillColor = _textColor;
+ }
+
+ // Update text - using safe indexing
+ int line = 0;
+
+ if (line < _displayTexts.Count) _displayTexts[line++].DisplayedString = "ENGINE";
+ if (line < _displayTexts.Count) _displayTexts[line++].DisplayedString = $" RPM: {car.Engine.RPM,7:F0}";
+ if (line < _displayTexts.Count) _displayTexts[line++].DisplayedString = $" Torque: {car.Engine.GetTorqueOutput(),7:F0} Nm";
+ if (line < _displayTexts.Count) _displayTexts[line++].DisplayedString = $" Throttle: {car.Engine.GetActualThrottle() * 100,6:F1}%";
+ if (line < _displayTexts.Count) _displayTexts[line++].DisplayedString = $" Power: {car.Engine.CurrentPower / 1000,6:F1} kW";
+
+ if (line < _displayTexts.Count)
+ {
+ _displayTexts[line].DisplayedString = $" Status: {(car.Engine.IsRunning ? "RUNNING" : "STALLED")}";
+ _displayTexts[line].FillColor = car.Engine.IsRunning ? _textColor : _warningColor;
+ line++;
+ }
+
+ line++; // Blank line
+
+ if (line < _displayTexts.Count) _displayTexts[line++].DisplayedString = "DRIVETRAIN";
+ if (line < _displayTexts.Count) _displayTexts[line++].DisplayedString = $" Gear: {car.Drivetrain.GetCurrentGearName(),3} (Ratio: {car.Drivetrain.GearRatio:F2}:1)";
+ if (line < _displayTexts.Count) _displayTexts[line++].DisplayedString = $" Clutch: {car.ClutchInput * 100,6:F1}% disengaged";
+ if (line < _displayTexts.Count) _displayTexts[line++].DisplayedString = $" Clutch Torque: {car.Drivetrain.ClutchTorque,6:F0} Nm";
+
+ if (line < _displayTexts.Count)
+ {
+ _displayTexts[line].DisplayedString = $" Clutch Slip: {car.Drivetrain.GetClutchSlipPercent(),6:F1}%";
+ _displayTexts[line].FillColor = car.Drivetrain.GetClutchSlipPercent() > 50 ? _warningColor : _textColor;
+ line++;
+ }
+
+ if (line < _displayTexts.Count) _displayTexts[line++].DisplayedString = $" Transmitted: {car.Drivetrain.TransmittedPower / 1000,6:F1} kW";
+ if (line < _displayTexts.Count) _displayTexts[line++].DisplayedString = $" Speed Diff: {car.Drivetrain.GetSpeedDifferenceRPM(),6:F0} RPM";
+
+ line++; // Blank line
+
+ if (line < _displayTexts.Count) _displayTexts[line++].DisplayedString = "VEHICLE";
+ if (line < _displayTexts.Count) _displayTexts[line++].DisplayedString = $" Speed: {car.Speed * 3.6f,7:F1} km/h";
+ if (line < _displayTexts.Count) _displayTexts[line++].DisplayedString = $" Wheel RPM: {car.WheelSystem.RPM,7:F0}";
+ if (line < _displayTexts.Count) _displayTexts[line++].DisplayedString = $" Brake: {car.BrakeInput * 100,6:F1}%";
+
+ line++; // Blank line
+
+ if (line < _displayTexts.Count) _displayTexts[line++].DisplayedString = "FORCES";
+ if (line < _displayTexts.Count) _displayTexts[line++].DisplayedString = $" Total Resistance: {car.CalculateTotalResistanceForce(),6:F1} N";
+ if (line < _displayTexts.Count) _displayTexts[line++].DisplayedString = $" Drag: {car.CalculateDragForce(),6:F1} N";
+ if (line < _displayTexts.Count) _displayTexts[line++].DisplayedString = $" Rolling: {car.CalculateRollingResistanceForce(),6:F1} N";
+
+ line++; // Blank line
+
+ if (line < _displayTexts.Count) _displayTexts[line++].DisplayedString = "ENERGY";
+ if (line < _displayTexts.Count) _displayTexts[line++].DisplayedString = $" Engine: {car.Engine.FlywheelEnergy,7:F0} J";
+ if (line < _displayTexts.Count) _displayTexts[line++].DisplayedString = $" Total: {car.WheelSystem.TotalEnergy,7:F0} J";
+ if (line < _displayTexts.Count) _displayTexts[line++].DisplayedString = $" Wheel Rotation: {car.WheelSystem.GetRotationalEnergy(),7:F0} J";
+ if (line < _displayTexts.Count) _displayTexts[line++].DisplayedString = $" Car Translation: {car.WheelSystem.GetTranslationalEnergy(),7:F0} J";
+ }
+
+ private void DrawGauges()
+ {
+ _window.Draw(_tachometerBackground);
+
+ float rpmRatio = Math.Clamp(car.Engine.RPM / 8000f, 0f, 1f);
+ float tachometerAngle = -90 + (270 * rpmRatio);
+ _tachometerNeedle.Rotation = tachometerAngle;
+ _window.Draw(_tachometerNeedle);
+
+ Text tachLabel = new Text("RPM", _font, 20);
+ tachLabel.FillColor = Color.White;
+ tachLabel.Position = new Vector2f(770, 70);
+ _window.Draw(tachLabel);
+
+ Text rpmText = new Text($"{car.Engine.RPM:F0}", _font, 24);
+ rpmText.FillColor = car.Engine.RPM > 7000 ? _warningColor : Color.White;
+ rpmText.Position = new Vector2f(765, 100);
+ _window.Draw(rpmText);
+
+ _window.Draw(_speedometerBackground);
+
+ float speedRatio = Math.Clamp(car.Speed * 3.6f / 200f, 0f, 1f);
+ float speedometerAngle = -90 + (270 * speedRatio);
+ _speedometerNeedle.Rotation = speedometerAngle;
+ _window.Draw(_speedometerNeedle);
+
+ Text speedLabel = new Text("SPEED", _font, 20);
+ speedLabel.FillColor = Color.White;
+ speedLabel.Position = new Vector2f(770, 320);
+ _window.Draw(speedLabel);
+
+ Text speedText = new Text($"{car.Speed * 3.6f:F1} km/h", _font, 24);
+ speedText.FillColor = Color.White;
+ speedText.Position = new Vector2f(750, 350);
+ _window.Draw(speedText);
+
+ Text gearText = new Text($"GEAR {car.Drivetrain.GetCurrentGearName()}", _font, 28);
+ gearText.FillColor = _highlightColor;
+ gearText.Position = new Vector2f(750, 520);
+ _window.Draw(gearText);
+ }
+
+ private void DrawKeyBindings()
+ {
+ Text controls = new Text("CONTROLS\n\nW/S: Throttle/Brake\nUp/Down: Clutch\nLeft/Right: Gear Up/Down\nSpace: Toggle Force Clutch\nESC: Quit", _font, 14);
+ controls.FillColor = new Color(180, 180, 180);
+ controls.Position = new Vector2f(250, 625);
+ _window.Draw(controls);
+ }
+
private void InitializeTrackedKeys()
{
- // Initialize all keys we care about
- var keysToTrack = new Keyboard.Key[]
- {
- Keyboard.Key.W,
- Keyboard.Key.Up,
- Keyboard.Key.Down,
- Keyboard.Key.B,
- Keyboard.Key.Space,
- Keyboard.Key.Left,
- Keyboard.Key.Right,
- Keyboard.Key.Escape
+ var keys = new[] {
+ Keyboard.Key.W, Keyboard.Key.S,
+ Keyboard.Key.Down, Keyboard.Key.Up, Keyboard.Key.Space,
+ Keyboard.Key.Escape,
+ Keyboard.Key.Right, Keyboard.Key.Left
};
- foreach (var key in keysToTrack)
+ foreach (var key in keys)
{
- _currentKeyStates[key] = false;
_previousKeyStates[key] = false;
+ _currentKeyStates[key] = false;
}
}
private void OnKeyPressed(object sender, KeyEventArgs e)
{
- var key = e.Code;
-
- // Update current state
- if (_currentKeyStates.ContainsKey(key))
- {
- _currentKeyStates[key] = true;
- }
+ if (_currentKeyStates.ContainsKey(e.Code))
+ _currentKeyStates[e.Code] = true;
}
private void OnKeyReleased(object sender, KeyEventArgs e)
{
- var key = e.Code;
-
- // Update current state
- if (_currentKeyStates.ContainsKey(key))
- {
- _currentKeyStates[key] = false;
- }
+ if (_currentKeyStates.ContainsKey(e.Code))
+ _currentKeyStates[e.Code] = false;
}
private void ProcessInput(float deltaTime)
{
- // quit
- if (IsKeyDown(Keyboard.Key.Escape))
- {
- _isRunning = false;
- return;
- }
-
- // force clutch
- car.ForceClutch = (IsKeyDown(Keyboard.Key.Space));
-
- // throttle
- if (IsKeyDown(Keyboard.Key.W))
- {
- car.ThrottleInput = Math.Min(car.ThrottleInput + 2f * deltaTime, 1.0f);
- }
+ // Throttle/Brake
+ if (_currentKeyStates[Keyboard.Key.W])
+ car.ThrottleInput += deltaTime * 4f;
else
- {
- car.ThrottleInput = Math.Max(car.ThrottleInput - 10f * deltaTime, 0f);
- }
+ car.ThrottleInput -= deltaTime * 8f;
- // brake
- if (IsKeyDown(Keyboard.Key.B))
- {
- car.BrakeInput = Math.Min(car.BrakeInput + 1f * deltaTime, 1.0f);
- }
+ if (_currentKeyStates[Keyboard.Key.S])
+ car.BrakeInput += deltaTime * 4f;
else
- {
- car.BrakeInput = Math.Max(car.BrakeInput - 4f * deltaTime, 0f);
- }
+ car.BrakeInput -= deltaTime * 8f;
- // clutch
- if (IsKeyDown(Keyboard.Key.Up))
- {
- car.ClutchInput = Math.Min(car.ClutchInput + 0.1f * deltaTime, 1.0f);
- }
- else if (IsKeyDown(Keyboard.Key.Down))
- {
- car.ClutchInput = Math.Max(car.ClutchInput - 0.1f * deltaTime, 0f);
- }
+ car.ThrottleInput = Math.Clamp(car.ThrottleInput, 0f, 1f);
+ car.BrakeInput = Math.Clamp(car.BrakeInput, 0f, 1f);
- // clutch
- if (IsKeyDown(Keyboard.Key.Up))
- {
- car.ClutchInput = Math.Min(car.ClutchInput + 1f * deltaTime, 1.0f);
- }
- else if (IsKeyDown(Keyboard.Key.Down))
- {
- car.ClutchInput = Math.Max(car.ClutchInput - 1f * deltaTime, 0f);
- }
+ // Clutch
+ if (_currentKeyStates[Keyboard.Key.Up])
+ car.ClutchInput += deltaTime * 0.5f;
+ if(_currentKeyStates[Keyboard.Key.Down])
+ car.ClutchInput -= deltaTime * 0.5f;
- // gear
- if (WasKeyPressed(Keyboard.Key.Left))
- {
- car.Drivetrain.GearDown();
- }
- else if (WasKeyPressed(Keyboard.Key.Right))
- {
+ car.ClutchInput = Math.Clamp(car.ClutchInput, 0f, 1f);
+
+ // Toggle force clutch
+ if (_currentKeyStates[Keyboard.Key.Space] && !_previousKeyStates[Keyboard.Key.Space])
+ car.ForceClutch = !car.ForceClutch;
+
+ // Gear changes
+ if (_currentKeyStates[Keyboard.Key.Right] && !_previousKeyStates[Keyboard.Key.Right])
car.Drivetrain.GearUp();
- }
+ if (_currentKeyStates[Keyboard.Key.Left] && !_previousKeyStates[Keyboard.Key.Left])
+ car.Drivetrain.GearDown();
+
+ // Quit
+ if (_currentKeyStates[Keyboard.Key.Escape])
+ _isRunning = false;
}
private void UpdatePreviousKeyStates()
@@ -181,31 +328,8 @@ internal class Program
var keys = new List(_currentKeyStates.Keys);
foreach (var key in keys)
{
- _previousKeyStates[key] = _currentKeyStates[key];
+ if (_previousKeyStates.ContainsKey(key))
+ _previousKeyStates[key] = _currentKeyStates[key];
}
}
-
- private bool IsKeyDown(Keyboard.Key key)
- {
- return _currentKeyStates.ContainsKey(key) && _currentKeyStates[key];
- }
-
- private bool WasKeyPressed(Keyboard.Key key)
- {
- return IsKeyDown(key) &&
- (!_previousKeyStates.ContainsKey(key) || !_previousKeyStates[key]);
- }
-
- private void UpdateDisplay()
- {
- _window.Clear(Color.Black);
-
- // Render car or simulation visualization here
- // For example, if car has Draw() method:
- // car.Draw(_window);
-
- car.DisplayUpdate(); // If this updates console display
-
- _window.Display();
- }
}
\ No newline at end of file
diff --git a/Car simulation/arial.ttf b/Car simulation/arial.ttf
new file mode 100644
index 0000000..7ff88f2
Binary files /dev/null and b/Car simulation/arial.ttf differ