From cd866cc5114a13e19aa8fb698e16c8184f2a77b1 Mon Sep 17 00:00:00 2001 From: LordBaryhobal Date: Sat, 25 Oct 2025 17:20:17 +0200 Subject: [PATCH] feat: initial implementation of image capture --- src/car.py | 12 +++++++++--- src/game.py | 11 +++++++---- src/recorder.py | 2 +- src/remote_controller.py | 7 +++++-- src/snapshot.py | 5 +++++ 5 files changed, 27 insertions(+), 10 deletions(-) diff --git a/src/car.py b/src/car.py index 4ed203c..6c9451c 100644 --- a/src/car.py +++ b/src/car.py @@ -1,5 +1,7 @@ +from __future__ import annotations + from math import radians -from typing import Optional +from typing import TYPE_CHECKING, Optional import pygame @@ -8,6 +10,9 @@ from src.remote_controller import RemoteController from src.utils import get_segments_intersection, segments_intersect from src.vec import Vec +if TYPE_CHECKING: + from src.game import Game + def sign(x): return 0 if x == 0 else (-1 if x < 0 else 1) @@ -27,7 +32,8 @@ class Car: RAYS_FOV = 180 RAYS_MAX_DIST = 100 - def __init__(self, pos: Vec, direction: Vec) -> None: + def __init__(self, game: Game, pos: Vec, direction: Vec) -> None: + self.game: Game = game self.initial_pos: Vec = pos.copy() self.initial_dir: Vec = direction.copy() self.pos: Vec = pos @@ -42,7 +48,7 @@ class Car: self.rays: list[float] = [0] * self.N_RAYS self.rays_end: list[Vec] = [Vec() for _ in range(self.N_RAYS)] - self.controller: RemoteController = RemoteController(self) + self.controller: RemoteController = RemoteController(self.game, self) self.controller.start_server() def update(self, dt: float): diff --git a/src/game.py b/src/game.py index 4a7d159..c08dace 100644 --- a/src/game.py +++ b/src/game.py @@ -19,10 +19,11 @@ class Game: self.win: pygame.Surface = pygame.display.set_mode( self.DEFAULT_SIZE, pygame.RESIZABLE ) + self.game_surf: pygame.Surface = pygame.Surface(self.DEFAULT_SIZE) pygame.display.set_caption("Rally Racer") self.running: bool = True self.track: Track = Track.load("simple") - self.car: Car = Car(self.track.start_pos, self.track.start_dir) + self.car: Car = Car(self, self.track.start_pos, self.track.start_dir) self.camera: Camera = Camera() self.clock: pygame.time.Clock = pygame.time.Clock() @@ -49,6 +50,7 @@ class Game: if event.type == pygame.QUIT: self.quit() elif event.type == pygame.VIDEORESIZE: + self.game_surf = pygame.Surface((event.w, event.h)) self.camera.set_size(Vec(event.w, event.h)) elif event.type == pygame.KEYDOWN: if event.key == pygame.K_ESCAPE: @@ -68,9 +70,10 @@ class Game: self.car.controller.close() def render(self): - self.win.fill(self.BACKGROUND_COLOR) - self.track.render(self.win, self.camera) - self.car.render(self.win, self.camera, self.show_raycasts) + self.game_surf.fill(self.BACKGROUND_COLOR) + self.track.render(self.game_surf, self.camera) + self.car.render(self.game_surf, self.camera, self.show_raycasts) + self.win.blit(self.game_surf, (0, 0)) if self.show_fps: self.render_fps() if self.show_speed: diff --git a/src/recorder.py b/src/recorder.py index 49a6187..4c9eb1d 100644 --- a/src/recorder.py +++ b/src/recorder.py @@ -17,7 +17,7 @@ from src.snapshot import Snapshot class RecorderClient(QObject): - DATA_CHUNK_SIZE = 4096 + DATA_CHUNK_SIZE = 65536 data_received: pyqtSignal = pyqtSignal(Snapshot) def __init__(self, host: str, port: int) -> None: diff --git a/src/remote_controller.py b/src/remote_controller.py index ad57698..9c7c111 100644 --- a/src/remote_controller.py +++ b/src/remote_controller.py @@ -12,11 +12,12 @@ from src.utils import RepeatTimer if TYPE_CHECKING: from src.car import Car + from src.game import Game class RemoteController: DEFAULT_PORT = 5000 - DATA_CHUNK_SIZE = 4096 + DATA_CHUNK_SIZE = 65536 CONTROL_ATTRIBUTES: dict[CarControl, str] = { CarControl.FORWARD: "forward", @@ -27,7 +28,8 @@ class RemoteController: SNAPSHOT_INTERVAL = 0.1 - def __init__(self, car: Car, port: int = DEFAULT_PORT) -> None: + def __init__(self, game: Game, car: Car, port: int = DEFAULT_PORT) -> None: + self.game: Game = game self.car: Car = car self.port: int = port self.server: socket.socket = socket.socket( @@ -134,5 +136,6 @@ class RemoteController: return snapshot: Snapshot = Snapshot.from_car(self.car) + snapshot.add_image(self.game) payload: bytes = snapshot.pack() self.client.sendall(struct.pack(">I", len(payload)) + payload) diff --git a/src/snapshot.py b/src/snapshot.py index 03ab165..10cf10e 100644 --- a/src/snapshot.py +++ b/src/snapshot.py @@ -5,11 +5,13 @@ from dataclasses import dataclass, field from typing import TYPE_CHECKING, Optional import numpy as np +import pygame from src.vec import Vec if TYPE_CHECKING: from src.car import Car + from src.game import Game def iter_unpack(format, data): @@ -99,3 +101,6 @@ class Snapshot: car.pos = self.position.copy() car.direction = self.direction.copy() car.speed = 0 + + def add_image(self, game: Game): + self.image = pygame.surfarray.array3d(game.game_surf)