new fire sim working fine

master
Eliza Moscovskaya 1 month ago
parent 4d82dc76da
commit e522b73dd1

@ -31,6 +31,7 @@ class Config:
# ===== Симулятор робота =====
MAP_WIDTH = 800
MAP_HEIGHT = 600
BORDER_THICKNESS = 10
MAP_OBSTACLES = [
(200, 150, 100, 200),
(500, 300, 150, 50),
@ -41,7 +42,7 @@ class Config:
ROBOT_IMAGE_PATH = 'robot.png' # или None
INITIAL_HP = 100
INITIAL_CHARGE = 100
INITIAL_FIRE_CHARGE = 4
COLLISION_DAMAGE = 10
# Конус перед роботом

@ -63,6 +63,7 @@ def main():
landmarks = result['landmarks']
# Статический жест
special = special_detector.predict(landmarks)
# Вкл/выкл управления жестами
if special == 'cross' and cross_cooldown == 0:
@ -94,10 +95,12 @@ def main():
last_dynamic = dynamic_gesture
dynamic_counter = 30
'''
if dynamic_gesture == 'wave_left':
robot.reset_position()
elif dynamic_gesture == 'wave_right':
robot.restart_game()
robot.restart()
'''
# Отрисовка
vis = detector.draw_landmarks(frame, result['pose_landmarks'])

@ -19,7 +19,18 @@ class DummySimRobot(RobotController):
self.clock = pygame.time.Clock()
self.font = pygame.font.SysFont(None, 28)
self.obstacles = config.MAP_OBSTACLES
border_thickness = config.BORDER_THICKNESS
if border_thickness > 0:
border_obstacles = [
(0, 0, self.width, border_thickness),
(0, self.height - border_thickness, self.width, border_thickness),
(0, 0, border_thickness, self.height),
(self.width - border_thickness, 0, border_thickness, self.height)
]
self.obstacles = list(config.MAP_OBSTACLES) + border_obstacles
else:
self.obstacles = list(config.MAP_OBSTACLES)
self.start = config.START_POS
self.finish = config.FINISH_POS
self.robot_radius = config.ROBOT_RADIUS
@ -34,8 +45,8 @@ class DummySimRobot(RobotController):
self.max_hp = config.INITIAL_HP
self.hp = self.max_hp
self.max_charge = config.INITIAL_CHARGE
self.charge = self.max_charge
self.max_fire_charge = config.INITIAL_FIRE_CHARGE
self.charge = self.max_fire_charge
self.collision_damage = config.COLLISION_DAMAGE
self.extinguish_radius = config.EXTINGUISH_RADIUS
self.extinguish_angle = math.radians(config.EXTINGUISH_ANGLE)
@ -43,10 +54,19 @@ class DummySimRobot(RobotController):
self.fires = []
self.num_fires = config.NUM_FIRES
self.fire_radius = config.FIRE_RADIUS
self.score = 0
self.game_over = False
self.won = False
self.extinguish_active = False
self.extinguish_timer = 0
self.extinguish_cooldown = 0
self.extinguish_cone_length = 80
self.invincibility_timer = 0
self.x, self.y = self.start
self.angle = 0.0
self.linear_speed = 0.0
@ -57,18 +77,42 @@ class DummySimRobot(RobotController):
def _generate_fires(self):
self.fires.clear()
attempts = 0
while len(self.fires) < self.num_fires and attempts < 1000:
fx = random.randint(self.robot_radius, self.width - self.robot_radius)
fy = random.randint(self.robot_radius, self.height - self.robot_radius)
margin = 30 # минимальное расстояние между центрами костров
while len(self.fires) < self.num_fires and attempts < 2000:
fx = random.randint(self.robot_radius + 10, self.width - self.robot_radius - 10)
fy = random.randint(self.robot_radius + 10, self.height - self.robot_radius - 10)
# Проверка: не на препятствии
if self._point_collides_with_obstacle(fx, fy, self.robot_radius):
attempts += 1
continue
if math.hypot(fx - self.start[0], fy - self.start[1]) < self.robot_radius * 2:
# Проверка: не слишком близко к старту
if math.hypot(fx - self.start[0], fy - self.start[1]) < self.robot_radius * 3:
attempts += 1
continue
if math.hypot(fx - self.finish[0], fy - self.finish[1]) < self.robot_radius * 2:
# Проверка: не слишком близко к финишу
if math.hypot(fx - self.finish[0], fy - self.finish[1]) < self.robot_radius * 3:
attempts += 1
continue
# Проверка: не пересекается с уже существующими кострами
overlap = False
for fire in self.fires:
if math.hypot(fx - fire.x, fy - fire.y) < 2 * self.fire_radius + margin:
overlap = True
break
if overlap:
attempts += 1
continue
self.fires.append(Fire(fx, fy, 15))
self.fires.append(Fire(fx, fy, self.fire_radius))
attempts += 1
print(f"Сгенерировано {len(self.fires)} очагов возгорания")
def _point_collides_with_obstacle(self, x, y, radius):
for ox, oy, ow, oh in self.obstacles:
closest_x = max(ox, min(x, ox + ow))
@ -81,6 +125,7 @@ class DummySimRobot(RobotController):
self.linear_speed = max(-1.0, min(1.0, v))
self.angular_speed = max(-1.0, min(1.0, w))
'''
def send_fire_ext_burst_cmd(self):
if self.charge <= 0:
return False
@ -91,36 +136,72 @@ class DummySimRobot(RobotController):
self.score += self.score_per_fire
return True
return False
'''
def _is_fire_in_front(self, fire):
dx = fire.x - self.x
dy = fire.y - self.y
dist = math.hypot(dx, dy)
if dist > self.extinguish_radius:
def send_fire_ext_burst_cmd(self):
if self.extinguish_cooldown > 0 or self.extinguish_active:
return False
if self.charge <= 0:
return False
angle_to_fire = math.atan2(dy, dx)
angle_diff = abs(angle_to_fire - self.angle)
angle_diff = min(angle_diff, 2*math.pi - angle_diff)
return angle_diff < self.extinguish_angle / 2
self.extinguish_active = True
self.extinguish_timer = 30
self.extinguish_cooldown = 10
self.charge -= 1
cone_len = self.extinguish_cone_length
cone_angle_half = self.extinguish_angle / 2
extinguished = False
for fire in self.fires[:]:
dx = fire.x - self.x
dy = fire.y - self.y
dist = math.hypot(dx, dy)
if dist > cone_len:
continue
angle_to_fire = math.atan2(dy, dx)
angle_diff = angle_to_fire - self.angle
angle_diff = (angle_diff + math.pi) % (2*math.pi) - math.pi #[-π, π]
if abs(angle_diff) <= cone_angle_half:
self.fires.remove(fire)
self.score += self.score_per_fire
extinguished = True
break
return extinguished
def update(self, dt=1/30.0):
if self.game_over or self.won:
return
if self.invincibility_timer > 0:
self.invincibility_timer -= 1
if self.extinguish_timer > 0:
self.extinguish_timer -= 1
if self.extinguish_timer == 0:
self.extinguish_active = False
if self.extinguish_cooldown > 0:
self.extinguish_cooldown -= 1
# Движение
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 self._point_collides_with_obstacle(new_x, new_y, self.robot_radius):
self.hp -= self.collision_damage
if self.invincibility_timer == 0:
self.hp -= self.collision_damage
self.invincibility_timer = 30
else:
self.x, self.y = new_x, new_y
# Конец игры?
if math.hypot(self.x - self.finish[0], self.y - self.finish[1]) < self.robot_radius:
self.won = True
if self.hp <= 0:
@ -128,26 +209,53 @@ class DummySimRobot(RobotController):
def draw(self):
self.screen.fill((255,255,255))
# Препятствия
for ox, oy, ow, oh in self.obstacles:
pygame.draw.rect(self.screen, (100,100,100), (ox, oy, ow, oh))
# Финиш
pygame.draw.circle(self.screen, (0,200,0), (int(self.finish[0]), int(self.finish[1])), self.robot_radius, 3)
# Костры
for fire in self.fires:
pygame.draw.circle(self.screen, (255,0,0), (int(fire.x), int(fire.y)), fire.radius)
pygame.draw.circle(self.screen, (255,100,0), (int(fire.x), int(fire.y)), fire.radius-3)
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)
# Конус тушения
if self.extinguish_active:
cone_surface = pygame.Surface((self.width, self.height), pygame.SRCALPHA)
num_points = 20
points = [(self.x, self.y)]
half_angle = self.extinguish_angle / 2
cone_len = self.extinguish_cone_length
for i in range(num_points + 1):
angle = self.angle - half_angle + (self.extinguish_angle) * (i / num_points)
x = self.x + cone_len * math.cos(angle)
y = self.y + cone_len * math.sin(angle)
points.append((x, y))
if len(points) > 2:
pygame.draw.polygon(cone_surface, (0, 200, 255, 80), points)
self.screen.blit(cone_surface, (0, 0))
# Робот
if self.invincibility_timer > 0 and (self.invincibility_timer % 6 < 3):
pass
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])
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])
# Статистика
hp_text = self.font.render(f"HP: {self.hp}", True, (0,0,0))
charge_text = self.font.render(f"Charge: {self.charge}", True, (0,0,0))
score_text = self.font.render(f"Score: {self.score}", True, (0,0,0))
@ -157,6 +265,7 @@ class DummySimRobot(RobotController):
self.screen.blit(score_text, (10, 70))
self.screen.blit(fires_text, (10, 100))
# Конец игры
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))
@ -195,6 +304,10 @@ class DummySimRobot(RobotController):
self.score = 0
self.game_over = False
self.won = False
self.invincibility_timer = 0
self.extinguish_active = False
self.extinguish_timer = 0
self.extinguish_cooldown = 0
self._generate_fires()
def reset_position(self):

Loading…
Cancel
Save