Оптимизируй код, сделай это как игру, есть персонаж, каждый шаг он издает звуковые волны, есть карта с стенами, от стен звуки отражаются естественно.
Убери все лишнее и сделай это как игру:
```python
import numpy as np
import pygame
from numba import njit, prange
import sys

# Инициализация Pygame
pygame.init()

# Параметры окна
WIDTH, HEIGHT = 800, 800
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Симуляция распространения звуковых волн")

# Цвета
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)

# Настройка шрифтов для отображения текста
FONT = pygame.font.SysFont(None, 24)

# Параметры волны
speed = 300.0             # Скорость распространения волны (пикселей/секунда)
initial_frequency = 2.0   # Начальная частота волны (Гц)
wavelength = speed / initial_frequency
k = 2 * np.pi / wavelength  # Волновое число
omega = 2 * np.pi * initial_frequency  # Угловая частота

# Коэффициент затухания
spatial_damping_coefficient = 0.001   # Пространственное затухание
temporal_damping_coefficient = 0.0001 # Временное затухание

# Диапазон координат (в пикселях)
x_min, x_max = 0, WIDTH
y_min, y_max = 0, HEIGHT
resolution = 400  # Размер сетки (разделение по одной оси)

# Создание сетки координат
x = np.linspace(x_min, x_max, resolution)
y = np.linspace(y_min, y_max, resolution)
X, Y = np.meshgrid(x, y)

# Определение источников без использования классов
# Храните координаты, частоты и скорости как отдельные массивы
source_positions = np.array([[WIDTH//2, HEIGHT//2]], dtype=np.float64)  # Начальная позиция (x, y)
source_frequencies = np.array([initial_frequency], dtype=np.float64)    # Частоты
source_moving = np.array([True], dtype=np.bool_)                        # Флаг движения
source_velocities = np.array([[100.0, 60.0]], dtype=np.float64)         # Скорости (vx, vy)

def add_mirror_sources(source_positions, x_min, x_max, y_min, y_max):
    """
    Создание зеркальных источников для отражения волн от границ.
    Отражения добавляются по осям X и Y.
    """
    mirrors = []
    for pos in source_positions:
        # Отражение по оси X
        mirror_x1 = 2 * x_min - pos[0]
        mirror_x2 = 2 * x_max - pos[0]
        mirrors.append([mirror_x1, pos[1]])
        mirrors.append([mirror_x2, pos[1]])
        # Отражение по оси Y
        mirror_y1 = 2 * y_min - pos[1]
        mirror_y2 = 2 * y_max - pos[1]
        mirrors.append([pos[0], mirror_y1])
        mirrors.append([pos[0], mirror_y2])
    return np.array(mirrors, dtype=np.float64)

@njit(parallel=True)
def compute_total_amplitude(X, Y, main_sources_pos, main_sources_freq, mirror_sources_pos, mirror_sources_freq, t, spatial_damping, temporal_damping):
    """
    Вычисление общей амплитуды волны в каждой точке сетки.
    Учитываются основные и зеркальные источники.
    """
    total = np.zeros(X.shape, dtype=np.float64)
    num_main = main_sources_pos.shape[0]
    num_mirror = mirror_sources_pos.shape[0]
    
    # Обработка основных источников
    for i in prange(num_main):
        sx = main_sources_pos[i, 0]
        sy = main_sources_pos[i, 1]
        freq = main_sources_freq[i]
        omega_i = 2 * np.pi * freq
        wavelength_i = speed / freq
        k_i = 2 * np.pi / wavelength_i
        R = np.sqrt((X - sx)**2 + (Y - sy)**2) + 1e-6  # Избегаем деления на ноль
        phase = k_i * R - omega_i * t
        # Пространственное и временное затухание
        amplitude = (1.0 / R) * np.sin(phase) * np.exp(-spatial_damping * R - temporal_damping * t)
        total += amplitude
    
    # Обработка зеркальных источников
    for i in prange(num_mirror):
        sx = mirror_sources_pos[i, 0]
        sy = mirror_sources_pos[i, 1]
        freq = mirror_sources_freq[i]
        omega_i = 2 * np.pi * freq
        wavelength_i = speed / freq
        k_i = 2 * np.pi / wavelength_i
        R = np.sqrt((X - sx)**2 + (Y - sy)**2) + 1e-6
        phase = k_i * R - omega_i * t
        # Пространственное и временное затухание с возможным фазовым сдвигом или усилением
        amplitude = (1.0 / R) * np.sin(phase + np.pi) * np.exp(-spatial_damping * R - temporal_damping * t)
        total += amplitude
    
    return total

def create_color_map():
    """
    Создание цветовой карты для отображения амплитуды.
    Используется градиент от синих (низкие значения) до красных (высокие значения).
    """
    color_map = np.zeros((256, 3), dtype=np.uint8)
    for i in range(256):
        # Простая градиентная карта: синий -> зеленый -> красный
        if i < 85:
            color_map[i] = [0, int(3 * i), 255 - int(3 * i)]
        elif i < 170:
            color_map[i] = [int(3 * (i - 85)), 255 - int(3 * (i - 85)), 0]
        else:
            color_map[i] = [255, 0, int(3 * (255 - i))]
    return color_map

color_map = create_color_map()

# Основной цикл симуляции
clock = pygame.time.Clock()
running = True
t = 0.0  # Время в секундах

while running:
    dt = clock.tick(60) / 1000.0  # Дельта времени в секундах (60 FPS)
    t += dt

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        # Управление частотой источника с помощью клавиш
        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_UP:
                source_frequencies += 0.1
            elif event.key == pygame.K_DOWN:
                source_frequencies = np.maximum(0.1, source_frequencies - 0.1)
            elif event.key == pygame.K_RIGHT:
                # Увеличение пространственного затухания
                spatial_damping_coefficient += 0.0001
            elif event.key == pygame.K_LEFT:
                # Уменьшение пространственного затухания
                spatial_damping_coefficient = max(0.0, spatial_damping_coefficient - 0.0001)
            elif event.key == pygame.K_w:
                # Увеличение временного затухания
                temporal_damping_coefficient += 0.0001
            elif event.key == pygame.K_s:
                # Уменьшение временного затухания
                temporal_damping_coefficient = max(0.0, temporal_damping_coefficient - 0.0001)
            elif event.key == pygame.K_SPACE:
                # Добавление нового источника по позиции курсора
                if pygame.mouse.get_pressed()[0]:
                    pos = pygame.mouse.get_pos()
                    source_positions = np.vstack((source_positions, [pos[0], pos[1]]))
                    source_frequencies = np.append(source_frequencies, initial_frequency)
                    source_moving = np.append(source_moving, False)
                    source_velocities = np.vstack((source_velocities, [0.0, 0.0]))
            elif event.key == pygame.K_m:
                # Переключение движения всех источников
                source_moving = np.logical_not(source_moving)
            elif event.key == pygame.K_c:
                # Очистка всех источников, кроме основного
                source_positions = np.array([[WIDTH//2, HEIGHT//2]], dtype=np.float64)
                source_frequencies = np.array([initial_frequency], dtype=np.float64)
                source_moving = np.array([True], dtype=np.bool_)
                source_velocities = np.array([[100.0, 60.0]], dtype=np.float64)

    # Обработка движения источников
    for i in range(source_positions.shape[0]):
        if source_moving[i]:
            # Обновление позиции
            source_positions[i, 0] += source_velocities[i, 0] * dt
            source_positions[i, 1] += source_velocities[i, 1] * dt
            # Отражение от границ
            if source_positions[i, 0] < x_min or source_positions[i, 0] > x_max:
                source_velocities[i, 0] *= -1
                source_positions[i, 0] = np.clip(source_positions[i, 0], x_min, x_max)
            if source_positions[i, 1] < y_min or source_positions[i, 1] > y_max:
                source_velocities[i, 1] *= -1
                source_positions[i, 1] = np.clip(source_positions[i, 1], y_min, y_max)

    # Добавление зеркальных источников для отражений
    mirror_sources_pos = add_mirror_sources(source_positions, x_min, x_max, y_min, y_max)
    mirror_sources_freq = np.copy(source_frequencies)  # Частоты зеркальных источников такие же

    # Вычисление амплитуды волн
    amplitude = compute_total_amplitude(
        X, Y,
        source_positions,
        source_frequencies,
        mirror_sources_pos,
        mirror_sources_freq,
        t,
        spatial_damping_coefficient,
        temporal_damping_coefficient
    )

    # Нормализация амплитуды для отображения
    normalized_amplitude = np.clip(amplitude, -0.5, 0.5)
    normalized_amplitude = (normalized_amplitude + 0.5) / 1.0  # Преобразование в диапазон [0,1]
    normalized_amplitude = (normalized_amplitude * 255).astype(np.uint8)  # Преобразование в диапазон [0,255]

    # Применение цветовой карты
    colored_amplitude = color_map[normalized_amplitude]

    # Создание цветового изображения
    surface = pygame.surfarray.make_surface(colored_amplitude)

    # Корректировка ориентации изображения
    surface = pygame.transform.rotate(surface, -90)
    surface = pygame.transform.flip(surface, True, False)

    # Отображение на экране
    screen.blit(surface, (0, 0))

    # Отображение основных источников
    for pos in source_positions:
        pygame.draw.circle(screen, (255, 0, 0), (int(pos[0]), int(pos[1])), 5)

    # Отображение пользовательского интерфейса
    info_lines = [
        f'Частота источников: {source_frequencies[0]:.2f} Гц (измените с помощью ↑/↓)',
        f'Пространственное затухание: {spatial_damping_coefficient:.4f} (измените с помощью ←/→)',
        f'Временное затухание: {temporal_damping_coefficient:.4f} (измените с помощью W/S)',
        'Клавиши:',
        '  SPACE - Добавить источник',
        '  M - Переключить движение источников',
        '  C - Очистить источники',
        '  ↑/↓ - Увеличить/уменьшить частоту',
        '  ←/→ - Увеличить/уменьшить пространственное затухание',
        '  W/S - Увеличить/уменьшить временное затухание'
    ]

    for idx, line in enumerate(info_lines):
        text_surface = FONT.render(line, True, WHITE)
        screen.blit(text_surface, (10, 10 + idx * 20))

    # Обновление экрана
    pygame.display.flip()

pygame.quit()
sys.exit()
```