engine-sim/main.py

179 lines
6.1 KiB
Python

# Example file showing a circle moving on screen
import pygame
import math
from engine import Engine
from transmission import Transmission
# pygame setup
pygame.init()
pygame.display.set_caption('Engine Sim')
screen = pygame.display.set_mode((1280, 720))
clock = pygame.time.Clock()
running = True
dt = 0
# Text Setup
pygame.font.init()
font = pygame.font.SysFont(None, 64)
gauge_font = pygame.font.SysFont(None, 24)
# Gauge Setup
rpm_pos = pygame.Vector2(screen.get_width() * 0.30, screen.get_height() / 2)
spd_pos = pygame.Vector2(screen.get_width() * 0.70, screen.get_height() / 2)
gauge_radius = screen.get_height() / 5
# Angle for gauge
angle_rad = math.radians(145)
needle_color = "white"
needle_width = 4
tip_radius = needle_width
offset_vector = pygame.Vector2(
math.cos(angle_rad) * gauge_radius,
math.sin(angle_rad) * gauge_radius
)
e = Engine()
t = Transmission(e)
throttle = 0
def map_value_to_angle(value, min_val, max_val):
clamped = max(min_val, value)
return math.radians(150 + 270 * (clamped - min_val) / (max_val - min_val))
while running:
screen.fill("white")
sX, sY = screen.get_width(), screen.get_height()
mX, mY = pygame.mouse.get_pos()
# Gauge Cluster
cluster_padding = (sX / sY) * (sX / 64)
cluster_padding_x = (sX / sY) * (sX / 64)
cluster_y = min(rpm_pos.y, spd_pos.y) - gauge_radius - cluster_padding
cluster_bottom = max(rpm_pos.y, spd_pos.y) + gauge_radius + cluster_padding
cluster_x = rpm_pos.x - gauge_radius - cluster_padding - cluster_padding_x
cluster_right = spd_pos.x + gauge_radius + cluster_padding + cluster_padding_x
cluster_width = cluster_right - cluster_x
cluster_height = cluster_bottom - cluster_y
cluster_rect = pygame.Rect(cluster_x, cluster_y, cluster_width, cluster_height)
pygame.draw.rect(screen, (50, 50, 50), cluster_rect, border_radius=30) # dark gray with rounded corners
# poll for events
# pygame.QUIT event means the user clicked X to close your window
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if (pygame.key.name(event.key) == 'v'):
if e.ignition:
e.ignition = False
else:
e.start(dt)
if (pygame.key.name(event.key) == 'x'):
t.upshift()
if (pygame.key.name(event.key) == 'z'):
t.downshift()
if (pygame.key.name(event.key) == 'left shift'):
t.clutch_pressure = 1
if event.type == pygame.KEYUP:
if (pygame.key.name(event.key) == 'left shift'):
t.clutch_pressure = 0
if event.type == pygame.QUIT:
running = False
rpm_text = font.render(f"RPM: {int(e.rpm)}", True, (0, 0, 0))
rpm_rect = rpm_text.get_rect(center=(screen.get_width() // 2, screen.get_height() // 4))
screen.blit(rpm_text, rpm_rect)
rpm_text = font.render(f"Torque: {int(e.instant_torque)}", True, (255, 0, 0))
rpm_rect = rpm_text.get_rect(center=(screen.get_width() // 2, screen.get_height() // 4 +100))
screen.blit(rpm_text, rpm_rect)
rpm_angle = map_value_to_angle(e.rpm, 0, 8000)
# RPM Gauge
rpm_vector = pygame.Vector2(math.cos(rpm_angle), math.sin(rpm_angle)) * gauge_radius
pygame.draw.circle(screen, "black", rpm_pos, gauge_radius)
pygame.draw.line(screen, needle_color, rpm_pos, rpm_pos + rpm_vector, needle_width)
for rpm_tick in range(0, 9000, 1000): # 1000 to 8000
angle = map_value_to_angle(rpm_tick, 0, 8000)
direction = pygame.Vector2(math.cos(angle), math.sin(angle))
label_pos = rpm_pos + direction * (gauge_radius - 20) # slight inward offset
label_text = gauge_font.render(str(rpm_tick // 1000), True, (255, 255, 255))
text_rect = label_text.get_rect(center=(label_pos.x, label_pos.y))
screen.blit(label_text, text_rect)
# Speed Gauge
speed_angle = map_value_to_angle(t.get_velocity(), 0, 160)
speed_vector = pygame.Vector2(math.cos(speed_angle), math.sin(speed_angle)) * gauge_radius
pygame.draw.circle(screen, "black", spd_pos, gauge_radius)
pygame.draw.line(screen, needle_color, spd_pos, spd_pos + speed_vector, needle_width)
for speed_tick in range(0, 180, 20): # 1000 to 8000
angle = map_value_to_angle(speed_tick, 0, 160)
direction = pygame.Vector2(math.cos(angle), math.sin(angle))
label_pos = spd_pos + direction * (gauge_radius - 20) # slight inward offset
label_text = gauge_font.render(str(speed_tick), True, (255, 255, 255))
text_rect = label_text.get_rect(center=(label_pos.x, label_pos.y))
screen.blit(label_text, text_rect)
# Fuel Gauge - 10 Steps
fuel_steps = math.ceil((e.fuel_capacity / e.max_fuel_capacity) * 10)
fuel_x = cluster_x + (cluster_padding / 1.5)
fuel_y = cluster_bottom - cluster_padding * 2
fuel_width = cluster_padding / 1.5
fuel_height = cluster_height / 20
fuel_step = cluster_height / 16
#fuel_rect = pygame.rect() Make this a rect as a backdrop for fuel
for i in range(fuel_steps):
fuel_rect = pygame.Rect(fuel_x, fuel_y, fuel_width, fuel_height)
pygame.draw.rect(screen, "white", fuel_rect, border_radius=2)
fuel_y -= fuel_step
# Temp Gauge - 10 Steps
# Throttle
throttle_text = font.render(f"Throttle", True, (0, 0, 0))
throttle_text_rect = throttle_text.get_rect(center=((sX - sX // 16), screen.get_height() // 4.5))
screen.blit(throttle_text, throttle_text_rect)
throttle_rect = pygame.Rect((sX - sX / 16), sY / 4, sX / 16, sY / 2)
pygame.draw.rect(screen, "red", throttle_rect)
keys = pygame.key.get_pressed()
if keys[pygame.K_w]:
e.rpm += 600 * dt
if keys[pygame.K_s]:
e.rpm -= 600 * dt
if keys[pygame.K_r]:
e.rpm = e.idle_rpm
# Throttle (Using mouse pos)
throttle = pow(max(0, min(1 - (((mY - (sY / 4)) / 2) / (sY / 4)), 1)),2) # Clamp value between 0 and 1
# print(mX, mY)
pygame.display.flip()
# limits FPS to 60
# dt is delta time in seconds since last frame, used for framerate-
# independent physics.
dt = clock.tick(60) / 1000
e.update(throttle, 0, dt)
pygame.quit()