feat: add rollback button
This commit is contained in:
22
src/car.py
22
src/car.py
@@ -8,7 +8,8 @@ from src.remote_controller import RemoteController
|
||||
from src.utils import get_segments_intersection, segments_intersect
|
||||
from src.vec import Vec
|
||||
|
||||
sign = lambda x: 0 if x == 0 else (-1 if x < 0 else 1)
|
||||
|
||||
def sign(x): return 0 if x == 0 else (-1 if x < 0 else 1)
|
||||
|
||||
|
||||
class Car:
|
||||
@@ -27,6 +28,8 @@ class Car:
|
||||
RAYS_MAX_DIST = 100
|
||||
|
||||
def __init__(self, pos: Vec, direction: Vec) -> None:
|
||||
self.initial_pos: Vec = pos.copy()
|
||||
self.initial_dir: Vec = direction.copy()
|
||||
self.pos: Vec = pos
|
||||
self.direction: Vec = direction
|
||||
self.speed: float = 0
|
||||
@@ -77,7 +80,8 @@ class Car:
|
||||
if show_raycasts:
|
||||
pos: Vec = camera.world2screen(self.pos)
|
||||
for p in self.rays_end:
|
||||
pygame.draw.line(surf, (255, 0, 0), pos, camera.world2screen(p), 2)
|
||||
pygame.draw.line(surf, (255, 0, 0), pos,
|
||||
camera.world2screen(p), 2)
|
||||
|
||||
pts: list[Vec] = self.get_corners()
|
||||
pts = [camera.world2screen(p) for p in pts]
|
||||
@@ -127,14 +131,17 @@ class Car:
|
||||
n *= -1
|
||||
dist = -dist
|
||||
self.speed = 0
|
||||
self.pos = self.pos + n * (self.COLLISION_MARGIN - dist)
|
||||
self.pos = self.pos + n * \
|
||||
(self.COLLISION_MARGIN - dist)
|
||||
return
|
||||
|
||||
def cast_rays(self, polygons: list[list[Vec]]):
|
||||
for i in range(self.N_RAYS):
|
||||
angle: float = radians((i / (self.N_RAYS - 1) - 0.5) * self.RAYS_FOV)
|
||||
angle: float = radians(
|
||||
(i / (self.N_RAYS - 1) - 0.5) * self.RAYS_FOV)
|
||||
p: Optional[Vec] = self.cast_ray(angle, polygons)
|
||||
self.rays[i] = self.RAYS_MAX_DIST if p is None else (p - self.pos).mag()
|
||||
self.rays[i] = self.RAYS_MAX_DIST if p is None else (
|
||||
p - self.pos).mag()
|
||||
self.rays_end[i] = self.pos if p is None else p
|
||||
|
||||
def cast_ray(self, angle: float, polygons: list[list[Vec]]) -> Optional[Vec]:
|
||||
@@ -161,3 +168,8 @@ class Car:
|
||||
dist = d
|
||||
closest = p
|
||||
return closest
|
||||
|
||||
def reset(self):
|
||||
self.pos = self.initial_pos.copy()
|
||||
self.direction = self.initial_dir.copy()
|
||||
self.speed = 0
|
||||
|
||||
@@ -5,10 +5,14 @@ from enum import IntEnum
|
||||
import struct
|
||||
from typing import Type
|
||||
|
||||
from src.snapshot import Snapshot
|
||||
|
||||
|
||||
class CommandType(IntEnum):
|
||||
CAR_CONTROL = 0
|
||||
RECORDING = 1
|
||||
APPLY_SNAPSHOT = 2
|
||||
RESET = 3
|
||||
|
||||
|
||||
class CarControl(IntEnum):
|
||||
@@ -30,8 +34,8 @@ class Command(abc.ABC):
|
||||
)
|
||||
Command.REGISTRY[cls.TYPE] = cls
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_payload(self) -> bytes: ...
|
||||
def get_payload(self) -> bytes:
|
||||
return b""
|
||||
|
||||
def pack(self) -> bytes:
|
||||
payload: bytes = self.get_payload()
|
||||
@@ -43,8 +47,8 @@ class Command(abc.ABC):
|
||||
return Command.REGISTRY[type].from_payload(data[1:])
|
||||
|
||||
@classmethod
|
||||
@abc.abstractmethod
|
||||
def from_payload(cls, payload: bytes) -> Command: ...
|
||||
def from_payload(cls, payload: bytes) -> Command:
|
||||
return cls()
|
||||
|
||||
|
||||
class ControlCommand(Command):
|
||||
@@ -82,3 +86,24 @@ class RecordingCommand(Command):
|
||||
def from_payload(cls, payload: bytes) -> Command:
|
||||
state: bool = struct.unpack(">B", payload)[0]
|
||||
return RecordingCommand(state)
|
||||
|
||||
|
||||
class ApplySnapshotCommand(Command):
|
||||
TYPE = CommandType.APPLY_SNAPSHOT
|
||||
__match_args__ = ("snapshot",)
|
||||
|
||||
def __init__(self, snapshot: Snapshot) -> None:
|
||||
super().__init__()
|
||||
self.snapshot: Snapshot = snapshot
|
||||
|
||||
def get_payload(self) -> bytes:
|
||||
return self.snapshot.pack()
|
||||
|
||||
@classmethod
|
||||
def from_payload(cls, payload: bytes) -> Command:
|
||||
snapshot: Snapshot = Snapshot.unpack(payload)
|
||||
return ApplySnapshotCommand(snapshot)
|
||||
|
||||
|
||||
class ResetCommand(Command):
|
||||
TYPE = CommandType.RESET
|
||||
|
||||
@@ -9,7 +9,7 @@ from PyQt6.QtCore import QObject, QThread, QTimer, pyqtSignal, pyqtSlot
|
||||
from PyQt6.QtGui import QKeyEvent
|
||||
from PyQt6.QtWidgets import QMainWindow
|
||||
|
||||
from src.command import CarControl, Command, ControlCommand, RecordingCommand
|
||||
from src.command import ApplySnapshotCommand, CarControl, Command, ControlCommand, RecordingCommand, ResetCommand
|
||||
from src.record_file import RecordFile
|
||||
from src.recorder_ui import Ui_Recorder
|
||||
from src.snapshot import Snapshot
|
||||
@@ -203,7 +203,19 @@ class RecorderWindow(Ui_Recorder, QMainWindow):
|
||||
self.send_command(RecordingCommand(self.recording))
|
||||
|
||||
def rollback(self):
|
||||
pass
|
||||
rollback_by: int = self.forgetSnapshotNumber.value()
|
||||
rollback_by = max(0, min(rollback_by, len(self.snapshots) - 1))
|
||||
|
||||
self.snapshots = self.snapshots[:-rollback_by]
|
||||
self.nbrSnapshotSaved.setText(str(len(self.snapshots)))
|
||||
|
||||
if len(self.snapshots) == 0:
|
||||
self.send_command(ResetCommand())
|
||||
else:
|
||||
self.send_command(ApplySnapshotCommand(self.snapshots[-1]))
|
||||
|
||||
if self.recording:
|
||||
self.toggle_record()
|
||||
|
||||
def toggle_autopilot(self):
|
||||
self.autopiloting = not self.autopiloting
|
||||
|
||||
@@ -6,7 +6,7 @@ import struct
|
||||
import threading
|
||||
from typing import TYPE_CHECKING, Optional
|
||||
|
||||
from src.command import CarControl, Command, ControlCommand, RecordingCommand
|
||||
from src.command import ApplySnapshotCommand, CarControl, Command, ControlCommand, RecordingCommand, ResetCommand
|
||||
from src.snapshot import Snapshot
|
||||
from src.utils import RepeatTimer
|
||||
|
||||
@@ -119,6 +119,10 @@ class RemoteController:
|
||||
self.set_control(control, active)
|
||||
case RecordingCommand(state):
|
||||
self.recording = state
|
||||
case ApplySnapshotCommand(snapshot):
|
||||
snapshot.apply(self.car)
|
||||
case ResetCommand():
|
||||
self.car.reset()
|
||||
|
||||
def set_control(self, control: CarControl, active: bool):
|
||||
setattr(self.car, self.CONTROL_ATTRIBUTES[control], active)
|
||||
|
||||
@@ -94,3 +94,8 @@ class Snapshot:
|
||||
raycast_distances=car.rays.copy(),
|
||||
image=None
|
||||
)
|
||||
|
||||
def apply(self, car: Car):
|
||||
car.pos = self.position.copy()
|
||||
car.direction = self.direction.copy()
|
||||
car.speed = 0
|
||||
|
||||
Reference in New Issue
Block a user