refactor: improve rendering process
This commit is contained in:
		
							
								
								
									
										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