Compare commits

..

3 Commits

Author SHA1 Message Date
8989341714 feat: add delta time 2025-10-18 22:06:19 +02:00
dde690818b feat: add simple track generator 2025-10-18 21:56:14 +02:00
f1ae12d0ec feat: add speedometer 2025-10-18 21:51:33 +02:00
6 changed files with 324 additions and 50 deletions

View File

@@ -2,12 +2,12 @@
"name": "Simple Track",
"start": {
"pos": [
0,
-3
30,
0
],
"direction": [
1,
0
0,
1
]
}
}

View File

@@ -3,59 +3,255 @@
"type": "road",
"pts": [
[
0,
-3,
0,
-1,
30.0,
0.0,
1.0,
0.0,
1
],
[
2,
-2,
1,
-1,
29.544,
5.209,
0.985,
0.174,
1
],
[
3,
0,
1,
0,
28.191,
10.261,
0.94,
0.342,
1
],
[
2,
2,
1,
1,
25.981,
15.0,
0.866,
0.5,
1
],
[
0,
3,
0,
1,
22.981,
19.284,
0.766,
0.643,
1
],
[
-2,
2,
-1,
1,
19.284,
22.981,
0.643,
0.766,
1
],
[
-3,
0,
-1,
0,
15.0,
25.981,
0.5,
0.866,
1
],
[
-2,
-2,
-1,
-1,
10.261,
28.191,
0.342,
0.94,
1
],
[
5.209,
29.544,
0.174,
0.985,
1
],
[
0.0,
30.0,
0.0,
1.0,
1
],
[
-5.209,
29.544,
-0.174,
0.985,
1
],
[
-10.261,
28.191,
-0.342,
0.94,
1
],
[
-15.0,
25.981,
-0.5,
0.866,
1
],
[
-19.284,
22.981,
-0.643,
0.766,
1
],
[
-22.981,
19.284,
-0.766,
0.643,
1
],
[
-25.981,
15.0,
-0.866,
0.5,
1
],
[
-28.191,
10.261,
-0.94,
0.342,
1
],
[
-29.544,
5.209,
-0.985,
0.174,
1
],
[
-30.0,
0.0,
-1.0,
0.0,
1
],
[
-29.544,
-5.209,
-0.985,
-0.174,
1
],
[
-28.191,
-10.261,
-0.94,
-0.342,
1
],
[
-25.981,
-15.0,
-0.866,
-0.5,
1
],
[
-22.981,
-19.284,
-0.766,
-0.643,
1
],
[
-19.284,
-22.981,
-0.643,
-0.766,
1
],
[
-15.0,
-25.981,
-0.5,
-0.866,
1
],
[
-10.261,
-28.191,
-0.342,
-0.94,
1
],
[
-5.209,
-29.544,
-0.174,
-0.985,
1
],
[
-0.0,
-30.0,
-0.0,
-1.0,
1
],
[
5.209,
-29.544,
0.174,
-0.985,
1
],
[
10.261,
-28.191,
0.342,
-0.94,
1
],
[
15.0,
-25.981,
0.5,
-0.866,
1
],
[
19.284,
-22.981,
0.643,
-0.766,
1
],
[
22.981,
-19.284,
0.766,
-0.643,
1
],
[
25.981,
-15.0,
0.866,
-0.5,
1
],
[
28.191,
-10.261,
0.94,
-0.342,
1
],
[
29.544,
-5.209,
0.985,
-0.174,
1
]
]

40
scripts/track_gen.py Normal file
View File

@@ -0,0 +1,40 @@
import json
from math import radians
from pathlib import Path
from src.utils import ROOT
from src.vec import Vec
def gen_circle(
folder: Path, center: Vec, radius: float, n_sides: int, width: float = 1
):
with open(folder / "track.json", "w") as f:
pts: list[tuple[float, ...]] = []
for i in range(n_sides):
angle: float = radians(i / n_sides * 360)
v: Vec = Vec(1, 0).rotate(angle)
pos: Vec = center + v * radius
normal: Vec = v
pts.append((pos.x, pos.y, normal.x, normal.y, width))
for i, pt in enumerate(pts):
pts[i] = tuple(round(v, 3) for v in pt)
json.dump([{"type": "road", "pts": pts}], f, indent=4)
with open(folder / "meta.json", "r") as f:
meta: dict = json.load(f)
meta["start"] = {"pos": [radius, 0], "direction": [0, 1]}
with open(folder / "meta.json", "w") as f:
json.dump(meta, f, indent=4)
def main():
folder: Path = ROOT / "assets" / "tracks" / "simple"
gen_circle(folder, Vec(0, 0), 30, 36)
if __name__ == "__main__":
main()

View File

@@ -7,14 +7,19 @@ from src.utils import segments_intersect
from src.vec import Vec
sign = lambda x: 0 if x == 0 else (-1 if x < 0 else 1)
class Car:
MAX_SPEED = 0.05
MAX_BACK_SPEED = -0.025
ROTATE_SPEED = radians(1)
MAX_SPEED = 5
MAX_BACK_SPEED = -2
ROTATE_SPEED = 1
COLOR = (230, 150, 80)
WIDTH = 0.4
LENGTH = 0.6
COLLISION_MARGIN = 0.4
ACCELERATION = 2
FRICTION = 3
def __init__(self, pos: Vec, direction: Vec) -> None:
self.pos: Vec = pos
@@ -26,20 +31,20 @@ class Car:
self.right: bool = False
self.colliding: bool = False
def update(self):
def update(self, dt: float):
if self.forward:
self.speed += 0.001
self.speed += self.ACCELERATION * dt
self.speed = min(self.MAX_SPEED, self.speed)
if self.backward:
self.speed -= 0.002
self.speed -= self.ACCELERATION * 2 * dt
self.speed = max(self.MAX_BACK_SPEED, self.speed)
rotate_angle: float = 0
if self.left:
rotate_angle -= self.ROTATE_SPEED
rotate_angle -= self.ROTATE_SPEED * dt
if self.right:
rotate_angle += self.ROTATE_SPEED
rotate_angle += self.ROTATE_SPEED * dt
# if self.backward:
# rotate_angle *= -1
@@ -47,11 +52,13 @@ class Car:
if rotate_angle != 0:
self.direction = self.direction.rotate(rotate_angle)
self.speed *= 0.98
if abs(self.speed) < 1e-8:
if not self.forward and not self.backward:
self.speed -= sign(self.speed) * self.FRICTION * dt
if abs(self.speed) < 1e-4:
self.speed = 0
self.pos += self.direction * self.speed
self.pos += self.direction * self.speed * dt
def render(self, surf: pygame.Surface, camera: Camera):
pts: list[Vec] = self.get_corners()

View File

@@ -1,3 +1,4 @@
from math import cos, radians, sin
import pygame
from src.camera import Camera
@@ -29,11 +30,13 @@ class Game:
str(ROOT / "assets" / "fonts" / "Ubuntu-M.ttf"), 20
)
self.show_fps: bool = True
self.show_speed: bool = True
def mainloop(self):
while self.running:
dt: float = self.clock.get_time() / 1000
self.process_pygame_events()
self.car.update()
self.car.update(dt)
self.car.check_collisions(self.track.get_collision_polygons())
self.render()
self.clock.tick(60)
@@ -64,6 +67,8 @@ class Game:
self.car.render(self.win, self.camera)
if self.show_fps:
self.render_fps()
if self.show_speed:
self.render_speedometer()
pygame.display.flip()
@@ -76,6 +81,10 @@ class Game:
self.car.left = True
elif event.key == pygame.K_d:
self.car.right = True
elif event.key == pygame.K_f:
self.show_fps = not self.show_fps
elif event.key == pygame.K_v:
self.show_speed = not self.show_speed
def on_key_up(self, event: pygame.event.Event):
if event.key == pygame.K_w:
@@ -92,3 +101,27 @@ class Game:
f"{self.clock.get_fps():.1f}", True, self.FPS_COLOR
)
self.win.blit(txt, (self.win.get_width() - txt.get_width(), 0))
def render_speedometer(self):
if self.car.speed == 0:
return
angle: float = self.car.speed / self.car.MAX_SPEED * 180
pts1: list[tuple[float, float]] = []
pts2: list[tuple[float, float]] = []
n: int = 30
r: float = 50
ox: float = r + 10
oy: float = r + 10
thickness: float = 5
r2: float = r - thickness
for i in range(n):
a: float = radians(angle * i / (n - 1))
dx: float = -cos(a)
dy: float = -sin(a)
pts1.append((ox + r * dx, oy + r * dy))
pts2.append((ox + r2 * dx, oy + r2 * dy))
pygame.draw.polygon(self.win, (200, 200, 200), pts1 + pts2[::-1])

View File

@@ -28,8 +28,6 @@ class Road(TrackObject):
p3: Vec = p1 - pt.normal * pt.width
side1.append(camera.world2screen(p2))
side2.append(camera.world2screen(p3))
col: tuple[float, float, float] = (i * 10 + 150, 100, 100)
pygame.draw.circle(surf, col, camera.world2screen(p1), 5)
n: int = len(self.pts)
for i in range(n):