|
|
import pygame
|
|
|
import sys
|
|
|
import math
|
|
|
|
|
|
class MapSimulator:
|
|
|
def __init__(self, config):
|
|
|
pygame.init()
|
|
|
self.width = config.MAP_WIDTH
|
|
|
self.height = config.MAP_HEIGHT
|
|
|
self.screen = pygame.display.set_mode((self.width, self.height))
|
|
|
pygame.display.set_caption("Robot Map Simulator")
|
|
|
self.clock = pygame.time.Clock()
|
|
|
self.font = pygame.font.SysFont(None, 24)
|
|
|
|
|
|
self.obstacles = config.MAP_OBSTACLES
|
|
|
self.start = config.START_POS
|
|
|
self.finish = config.FINISH_POS
|
|
|
self.robot_radius = config.ROBOT_RADIUS
|
|
|
|
|
|
if config.ROBOT_IMAGE_PATH:
|
|
|
try:
|
|
|
self.robot_image = pygame.image.load(config.ROBOT_IMAGE_PATH)
|
|
|
self.robot_image = pygame.transform.scale(self.robot_image,
|
|
|
(self.robot_radius*2, self.robot_radius*2))
|
|
|
except:
|
|
|
self.robot_image = None
|
|
|
else:
|
|
|
self.robot_image = None
|
|
|
|
|
|
self.reset()
|
|
|
|
|
|
def reset(self):
|
|
|
self.x, self.y = self.start
|
|
|
self.angle = 0.0
|
|
|
self.linear_speed = 0.0
|
|
|
self.angular_speed = 0.0
|
|
|
self.game_over = False
|
|
|
self.won = False
|
|
|
|
|
|
def set_speeds(self, linear, angular):
|
|
|
self.linear_speed = linear
|
|
|
self.angular_speed = angular
|
|
|
|
|
|
def update(self):
|
|
|
if self.game_over or self.won:
|
|
|
return
|
|
|
|
|
|
dt = 1/30.0
|
|
|
self.angle += self.angular_speed * dt * 2
|
|
|
dx = self.linear_speed * math.cos(self.angle) * dt * 100
|
|
|
dy = self.linear_speed * math.sin(self.angle) * dt * 100
|
|
|
new_x = self.x + dx
|
|
|
new_y = self.y + dy
|
|
|
|
|
|
# Ограничение границами карты
|
|
|
new_x = max(self.robot_radius, min(self.width - self.robot_radius, new_x))
|
|
|
new_y = max(self.robot_radius, min(self.height - self.robot_radius, new_y))
|
|
|
|
|
|
# Проверка столкновений с препятствиями
|
|
|
if not self.check_collision(new_x, new_y):
|
|
|
self.x, self.y = new_x, new_y
|
|
|
else:
|
|
|
self.game_over = True
|
|
|
|
|
|
# Проверка финиша
|
|
|
dist = math.hypot(self.x - self.finish[0], self.y - self.finish[1])
|
|
|
if dist < self.robot_radius:
|
|
|
self.won = True
|
|
|
|
|
|
def check_collision(self, x, y):
|
|
|
for ox, oy, ow, oh in self.obstacles:
|
|
|
closest_x = max(ox, min(x, ox + ow))
|
|
|
closest_y = max(oy, min(y, oy + oh))
|
|
|
dist = math.hypot(x - closest_x, y - closest_y)
|
|
|
if dist < self.robot_radius:
|
|
|
return True
|
|
|
return False
|
|
|
|
|
|
def draw(self):
|
|
|
self.screen.fill((255,255,255))
|
|
|
|
|
|
for obs in self.obstacles:
|
|
|
pygame.draw.rect(self.screen, (100,100,100), obs)
|
|
|
|
|
|
pygame.draw.circle(self.screen, (0,255,0),
|
|
|
(int(self.finish[0]), int(self.finish[1])), self.robot_radius, 2)
|
|
|
|
|
|
if self.robot_image:
|
|
|
rotated = pygame.transform.rotate(self.robot_image, -math.degrees(self.angle))
|
|
|
rect = rotated.get_rect(center=(int(self.x), int(self.y)))
|
|
|
self.screen.blit(rotated, rect)
|
|
|
else:
|
|
|
nose = (self.x + self.robot_radius * math.cos(self.angle),
|
|
|
self.y + self.robot_radius * math.sin(self.angle))
|
|
|
left = (self.x + self.robot_radius * math.cos(self.angle + 2.5),
|
|
|
self.y + self.robot_radius * math.sin(self.angle + 2.5))
|
|
|
right = (self.x + self.robot_radius * math.cos(self.angle - 2.5),
|
|
|
self.y + self.robot_radius * math.sin(self.angle - 2.5))
|
|
|
pygame.draw.polygon(self.screen, (0,0,255), [nose, left, right])
|
|
|
|
|
|
texts = [
|
|
|
f"Linear: {self.linear_speed:.2f}",
|
|
|
f"Angular: {self.angular_speed:.2f}",
|
|
|
]
|
|
|
y = 10
|
|
|
for t in texts:
|
|
|
surf = self.font.render(t, True, (0,0,0))
|
|
|
self.screen.blit(surf, (10, y))
|
|
|
y += 25
|
|
|
|
|
|
if self.game_over:
|
|
|
msg = self.font.render("GAME OVER – Press R to restart", True, (255,0,0))
|
|
|
self.screen.blit(msg, (self.width//2 - 150, self.height//2))
|
|
|
elif self.won:
|
|
|
msg = self.font.render("YOU WIN! – Press R to restart", True, (0,100,0))
|
|
|
self.screen.blit(msg, (self.width//2 - 120, self.height//2))
|
|
|
|
|
|
pygame.display.flip()
|
|
|
|
|
|
def handle_events(self):
|
|
|
for event in pygame.event.get():
|
|
|
if event.type == pygame.QUIT:
|
|
|
return False
|
|
|
if event.type == pygame.KEYDOWN and event.key == pygame.K_r:
|
|
|
self.reset()
|
|
|
return True
|
|
|
|
|
|
def step(self):
|
|
|
if not self.handle_events():
|
|
|
return False
|
|
|
self.update()
|
|
|
self.draw()
|
|
|
self.clock.tick(30)
|
|
|
return True
|
|
|
|
|
|
def quit(self):
|
|
|
pygame.quit()
|