refactor: improve rendering process
This commit is contained in:
BIN
assets/fonts/Ubuntu-M.ttf
Normal file
BIN
assets/fonts/Ubuntu-M.ttf
Normal file
Binary file not shown.
BIN
assets/fonts/Ubuntu-R.ttf
Normal file
BIN
assets/fonts/Ubuntu-R.ttf
Normal file
Binary file not shown.
36
src/game.py
36
src/game.py
@@ -2,7 +2,8 @@ import pygame
|
||||
|
||||
from src.camera import Camera
|
||||
from src.car import Car
|
||||
from src.track import Road, Track
|
||||
from src.track import Track
|
||||
from src.utils import ROOT
|
||||
from src.vec import Vec
|
||||
|
||||
|
||||
@@ -10,6 +11,7 @@ class Game:
|
||||
DEFAULT_SIZE = (1280, 720)
|
||||
BACKGROUND_COLOR = (80, 80, 80)
|
||||
MAX_FPS = 60
|
||||
FPS_COLOR = (255, 0, 0)
|
||||
|
||||
def __init__(self) -> None:
|
||||
pygame.init()
|
||||
@@ -23,6 +25,10 @@ class Game:
|
||||
self.camera: Camera = Camera()
|
||||
|
||||
self.clock: pygame.time.Clock = pygame.time.Clock()
|
||||
self.font: pygame.font.Font = pygame.font.Font(
|
||||
str(ROOT / "assets" / "fonts" / "Ubuntu-M.ttf"), 20
|
||||
)
|
||||
self.show_fps: bool = True
|
||||
|
||||
def mainloop(self):
|
||||
while self.running:
|
||||
@@ -53,29 +59,13 @@ class Game:
|
||||
|
||||
def render(self):
|
||||
self.win.fill(self.BACKGROUND_COLOR)
|
||||
self.render_track()
|
||||
self.track.render(self.win, self.camera)
|
||||
self.render_car()
|
||||
if self.show_fps:
|
||||
self.render_fps()
|
||||
|
||||
pygame.display.flip()
|
||||
|
||||
def render_track(self):
|
||||
road: Road = self.track.objects[0] # type: ignore
|
||||
|
||||
side1: list[Vec] = []
|
||||
side2: list[Vec] = []
|
||||
|
||||
for i, pt in enumerate(road.pts):
|
||||
p1: Vec = pt.pos
|
||||
p2: Vec = p1 + pt.normal * pt.width
|
||||
p3: Vec = p1 - pt.normal * pt.width
|
||||
side1.append(self.camera.world2screen(p2))
|
||||
side2.append(self.camera.world2screen(p3))
|
||||
col: tuple[float, float, float] = (i * 10 + 150, 100, 100)
|
||||
pygame.draw.circle(self.win, col, self.camera.world2screen(p1), 5)
|
||||
|
||||
pygame.draw.lines(self.win, (255, 255, 255), True, side1)
|
||||
pygame.draw.lines(self.win, (255, 255, 255), True, side2)
|
||||
|
||||
def render_car(self):
|
||||
u: Vec = self.car.direction * 0.3
|
||||
v: Vec = self.car.direction.perp * 0.2
|
||||
@@ -107,3 +97,9 @@ class Game:
|
||||
self.car.left = False
|
||||
elif event.key == pygame.K_d:
|
||||
self.car.right = False
|
||||
|
||||
def render_fps(self):
|
||||
txt: pygame.Surface = self.font.render(
|
||||
f"{self.clock.get_fps():.1f}", True, self.FPS_COLOR
|
||||
)
|
||||
self.win.blit(txt, (self.win.get_width() - txt.get_width(), 0))
|
||||
|
||||
0
src/objects/__init__.py
Normal file
0
src/objects/__init__.py
Normal file
54
src/objects/road.py
Normal file
54
src/objects/road.py
Normal file
@@ -0,0 +1,54 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import pygame
|
||||
|
||||
from src.camera import Camera
|
||||
from src.track_object import TrackObject, TrackObjectType
|
||||
from src.vec import Vec
|
||||
|
||||
|
||||
class Road(TrackObject):
|
||||
type = TrackObjectType.Road
|
||||
|
||||
def __init__(self, pts: list[RoadPoint]) -> None:
|
||||
super().__init__()
|
||||
self.pts: list[RoadPoint] = pts
|
||||
|
||||
@classmethod
|
||||
def load(cls, data: dict) -> Road:
|
||||
return Road([RoadPoint.load(pt) for pt in data["pts"]])
|
||||
|
||||
def render(self, surf: pygame.Surface, camera: Camera):
|
||||
side1: list[Vec] = []
|
||||
side2: list[Vec] = []
|
||||
|
||||
for i, pt in enumerate(self.pts):
|
||||
p1: Vec = pt.pos
|
||||
p2: Vec = p1 + pt.normal * pt.width
|
||||
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):
|
||||
pygame.draw.polygon(
|
||||
surf,
|
||||
(100, 100, 100),
|
||||
[side1[i], side1[(i + 1) % n], side2[(i + 1) % n], side2[i]],
|
||||
)
|
||||
|
||||
pygame.draw.lines(surf, (255, 255, 255), True, side1)
|
||||
pygame.draw.lines(surf, (255, 255, 255), True, side2)
|
||||
|
||||
|
||||
class RoadPoint:
|
||||
def __init__(self, pos: Vec, normal: Vec, width: float) -> None:
|
||||
self.pos: Vec = pos
|
||||
self.normal: Vec = normal.normalized
|
||||
self.width: float = width
|
||||
|
||||
@staticmethod
|
||||
def load(data: list[float]) -> RoadPoint:
|
||||
return RoadPoint(Vec(data[0], data[1]), Vec(data[2], data[3]), data[4])
|
||||
33
src/track.py
33
src/track.py
@@ -2,10 +2,15 @@ from __future__ import annotations
|
||||
|
||||
import json
|
||||
|
||||
from src.track_object import TrackObject, TrackObjectType
|
||||
import pygame
|
||||
|
||||
from src.camera import Camera
|
||||
from src.track_object import TrackObject
|
||||
from src.utils import ROOT
|
||||
from src.vec import Vec
|
||||
|
||||
TrackObject.init()
|
||||
|
||||
|
||||
class Track:
|
||||
TRACKS_DIRECTORY = ROOT / "assets" / "tracks"
|
||||
@@ -36,26 +41,8 @@ class Track:
|
||||
|
||||
self.objects = []
|
||||
for obj_data in data:
|
||||
if obj_data["type"] == "road":
|
||||
self.objects.append(Road.load(obj_data))
|
||||
self.objects.append(TrackObject.load(obj_data))
|
||||
|
||||
|
||||
class RoadPoint:
|
||||
def __init__(self, pos: Vec, normal: Vec, width: float) -> None:
|
||||
self.pos: Vec = pos
|
||||
self.normal: Vec = normal.normalized
|
||||
self.width: float = width
|
||||
|
||||
@staticmethod
|
||||
def load(data: list[float]) -> RoadPoint:
|
||||
return RoadPoint(Vec(data[0], data[1]), Vec(data[2], data[3]), data[4])
|
||||
|
||||
|
||||
class Road(TrackObject):
|
||||
def __init__(self, pts: list[RoadPoint]) -> None:
|
||||
super().__init__(TrackObjectType.Road)
|
||||
self.pts: list[RoadPoint] = pts
|
||||
|
||||
@staticmethod
|
||||
def load(data: dict) -> Road:
|
||||
return Road([RoadPoint.load(pt) for pt in data["pts"]])
|
||||
def render(self, surf: pygame.Surface, camera: Camera):
|
||||
for object in self.objects:
|
||||
object.render(surf, camera)
|
||||
|
||||
@@ -1,13 +1,42 @@
|
||||
import importlib
|
||||
import pkgutil
|
||||
from enum import StrEnum
|
||||
from typing import Optional, Self
|
||||
|
||||
import pygame
|
||||
|
||||
import src.objects
|
||||
from src.camera import Camera
|
||||
|
||||
|
||||
class TrackObjectType(StrEnum):
|
||||
Road = "road"
|
||||
|
||||
Unknown = "unknown"
|
||||
|
||||
|
||||
class TrackObject:
|
||||
def __init__(
|
||||
self,
|
||||
type: TrackObjectType,
|
||||
) -> None:
|
||||
self.type: TrackObjectType = type
|
||||
REGISTRY = {}
|
||||
type: TrackObjectType = TrackObjectType.Unknown
|
||||
|
||||
@staticmethod
|
||||
def init():
|
||||
package = src.objects
|
||||
for _, modname, _ in pkgutil.walk_packages(
|
||||
package.__path__, package.__name__ + "."
|
||||
):
|
||||
importlib.import_module(modname)
|
||||
|
||||
def __init_subclass__(cls, **kwargs) -> None:
|
||||
super().__init_subclass__(**kwargs)
|
||||
TrackObject.REGISTRY[cls.type] = cls
|
||||
|
||||
@classmethod
|
||||
def load(cls, data: dict) -> Self:
|
||||
obj_type: Optional[TrackObjectType] = data.get("type")
|
||||
if obj_type not in cls.REGISTRY:
|
||||
raise ValueError(f"Unknown object tyoe: {obj_type}")
|
||||
return cls.REGISTRY[obj_type].load(data)
|
||||
|
||||
def render(self, surf: pygame.Surface, camera: Camera):
|
||||
pass
|
||||
|
||||
Reference in New Issue
Block a user