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.camera import Camera
|
||||||
from src.car import Car
|
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
|
from src.vec import Vec
|
||||||
|
|
||||||
|
|
||||||
@@ -10,6 +11,7 @@ class Game:
|
|||||||
DEFAULT_SIZE = (1280, 720)
|
DEFAULT_SIZE = (1280, 720)
|
||||||
BACKGROUND_COLOR = (80, 80, 80)
|
BACKGROUND_COLOR = (80, 80, 80)
|
||||||
MAX_FPS = 60
|
MAX_FPS = 60
|
||||||
|
FPS_COLOR = (255, 0, 0)
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
pygame.init()
|
pygame.init()
|
||||||
@@ -23,6 +25,10 @@ class Game:
|
|||||||
self.camera: Camera = Camera()
|
self.camera: Camera = Camera()
|
||||||
|
|
||||||
self.clock: pygame.time.Clock = pygame.time.Clock()
|
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):
|
def mainloop(self):
|
||||||
while self.running:
|
while self.running:
|
||||||
@@ -53,29 +59,13 @@ class Game:
|
|||||||
|
|
||||||
def render(self):
|
def render(self):
|
||||||
self.win.fill(self.BACKGROUND_COLOR)
|
self.win.fill(self.BACKGROUND_COLOR)
|
||||||
self.render_track()
|
self.track.render(self.win, self.camera)
|
||||||
self.render_car()
|
self.render_car()
|
||||||
|
if self.show_fps:
|
||||||
|
self.render_fps()
|
||||||
|
|
||||||
pygame.display.flip()
|
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):
|
def render_car(self):
|
||||||
u: Vec = self.car.direction * 0.3
|
u: Vec = self.car.direction * 0.3
|
||||||
v: Vec = self.car.direction.perp * 0.2
|
v: Vec = self.car.direction.perp * 0.2
|
||||||
@@ -107,3 +97,9 @@ class Game:
|
|||||||
self.car.left = False
|
self.car.left = False
|
||||||
elif event.key == pygame.K_d:
|
elif event.key == pygame.K_d:
|
||||||
self.car.right = False
|
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
|
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.utils import ROOT
|
||||||
from src.vec import Vec
|
from src.vec import Vec
|
||||||
|
|
||||||
|
TrackObject.init()
|
||||||
|
|
||||||
|
|
||||||
class Track:
|
class Track:
|
||||||
TRACKS_DIRECTORY = ROOT / "assets" / "tracks"
|
TRACKS_DIRECTORY = ROOT / "assets" / "tracks"
|
||||||
@@ -36,26 +41,8 @@ class Track:
|
|||||||
|
|
||||||
self.objects = []
|
self.objects = []
|
||||||
for obj_data in data:
|
for obj_data in data:
|
||||||
if obj_data["type"] == "road":
|
self.objects.append(TrackObject.load(obj_data))
|
||||||
self.objects.append(Road.load(obj_data))
|
|
||||||
|
|
||||||
|
def render(self, surf: pygame.Surface, camera: Camera):
|
||||||
class RoadPoint:
|
for object in self.objects:
|
||||||
def __init__(self, pos: Vec, normal: Vec, width: float) -> None:
|
object.render(surf, camera)
|
||||||
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"]])
|
|
||||||
|
|||||||
@@ -1,13 +1,42 @@
|
|||||||
|
import importlib
|
||||||
|
import pkgutil
|
||||||
from enum import StrEnum
|
from enum import StrEnum
|
||||||
|
from typing import Optional, Self
|
||||||
|
|
||||||
|
import pygame
|
||||||
|
|
||||||
|
import src.objects
|
||||||
|
from src.camera import Camera
|
||||||
|
|
||||||
|
|
||||||
class TrackObjectType(StrEnum):
|
class TrackObjectType(StrEnum):
|
||||||
Road = "road"
|
Road = "road"
|
||||||
|
|
||||||
|
Unknown = "unknown"
|
||||||
|
|
||||||
|
|
||||||
class TrackObject:
|
class TrackObject:
|
||||||
def __init__(
|
REGISTRY = {}
|
||||||
self,
|
type: TrackObjectType = TrackObjectType.Unknown
|
||||||
type: TrackObjectType,
|
|
||||||
) -> None:
|
@staticmethod
|
||||||
self.type: TrackObjectType = type
|
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