Загрузка уровней и данных с сервера

Загрузка уровней и внешних данных — ключевой элемент современных веб-игр. Библиотека Phaser (версия 3) предоставляет встроенный механизм загрузки ресурсов через систему Loader, а также позволяет интегрироваться с удалёнными серверами через HTTP-запросы, WebSocket и другие протоколы.

В типичной игре данные могут поступать из следующих источников:

  • JSON-файлы уровней
  • Конфигурационные файлы
  • REST API
  • Сервер авторизации
  • Облачное хранилище
  • Сервер многопользовательской синхронизации

Для работы с такими источниками используются:

  • this.load — загрузка на этапе preload
  • this.cache — кэширование данных
  • fetch / XMLHttpRequest — ручные HTTP-запросы
  • WebSocket — двусторонняя связь в реальном времени

Загрузка JSON-уровней через Loader

Phaser предоставляет встроенный метод загрузки JSON:

preload() {
    this.load.json('level1', 'assets/levels/level1.json');
}

После завершения загрузки данные доступны через систему кэширования:

create() {
    const levelData = this.cache.json.get('level1');
    console.log(levelData);
}

Как работает процесс

  1. Loader инициирует HTTP-запрос.
  2. Ответ сохраняется во внутренний кэш.
  3. Данные становятся доступны через this.cache.

Загрузка выполняется асинхронно, но сцена не перейдёт к create(), пока preload() полностью не завершится.


Структура JSON-файла уровня

Типичный файл уровня может содержать:

{
  "player": {
    "x": 100,
    "y": 200
  },
  "enemies": [
    { "type": "orc", "x": 400, "y": 300 },
    { "type": "archer", "x": 600, "y": 250 }
  ],
  "platforms": [
    { "x": 0, "y": 500, "width": 800, "height": 50 }
  ]
}

Использование:

create() {
    const data = this.cache.json.get('level1');

    this.player = this.physics.add.sprite(data.player.x, data.player.y, 'hero');

    data.enemies.forEach(enemy => {
        this.spawnEnemy(enemy);
    });
}

Динамическая загрузка уровней во время игры

Иногда требуется загрузка нового уровня без перезапуска сцены. Для этого используется динамический Loader:

loadLevel(key, url) {
    this.load.json(key, url);

    this.load.once('complete', () => {
        const data = this.cache.json.get(key);
        this.buildLevel(data);
    });

    this.load.start();
}

Особенности

  • this.load.start() запускает процесс вручную.
  • Событие complete сигнализирует об окончании.
  • Загрузка происходит асинхронно.

Работа с Tilemap и Tiled

Phaser поддерживает карты, созданные в редакторе Tiled. Формат — JSON.

Загрузка:

preload() {
    this.load.tilemapTiledJSON('map', 'assets/maps/map1.json');
    this.load.image('tiles', 'assets/tilesets/tiles.png');
}

Создание карты:

create() {
    const map = this.make.tilemap({ key: 'map' });
    const tileset = map.addTilesetImage('tileset_name', 'tiles');

    const layer = map.createLayer('Ground', tileset, 0, 0);
}

JSON карты может храниться локально или загружаться с удалённого сервера.


Загрузка данных с REST API

Для взаимодействия с сервером используется стандартный fetch:

fetch('https://example.com/api/level/1')
    .then(response => response.json())
    .then(data => {
        this.buildLevel(data);
    })
    .catch(error => {
        console.error(error);
    });

Интеграция с жизненным циклом сцены

Асинхронные операции желательно оборачивать в методы сцены:

async loadLevelFromServer(id) {
    try {
        const response = await fetch(`/api/levels/${id}`);
        const data = await response.json();
        this.buildLevel(data);
    } catch (error) {
        console.error('Ошибка загрузки уровня:', error);
    }
}

Обработка ошибок загрузки

Phaser позволяет отслеживать ошибки Loader:

this.load.on('loaderror', (file) => {
    console.error('Ошибка загрузки:', file.key);
});

Для fetch используется стандартный блок catch.

Также рекомендуется:

  • Проверять response.ok
  • Реализовывать повторные попытки
  • Добавлять fallback-данные

Индикатор прогресса загрузки

Phaser предоставляет событие progress:

preload() {
    const progressBar = this.add.graphics();

    this.load.on('progress', (value) => {
        progressBar.clear();
        progressBar.fillStyle(0xffffff, 1);
        progressBar.fillRect(0, 0, 800 * value, 20);
    });
}

Значение value находится в диапазоне от 0 до 1.


Кэширование серверных данных

Phaser имеет систему кэша:

  • this.cache.json
  • this.cache.text
  • this.cache.binary

Ручное добавление данных в кэш:

this.cache.json.add('serverLevel', serverData);

Преимущества:

  • Повторное использование
  • Отсутствие повторных запросов
  • Быстрый доступ

Загрузка пользовательских данных (сохранения)

Часто используется гибридная модель:

  1. Сервер хранит глобальный прогресс.
  2. Локальное хранилище (localStorage) — временные данные.

Пример:

async saveProgress(data) {
    await fetch('/api/save', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(data)
    });
}

Использование WebSocket для многопользовательских уровней

Для игр в реальном времени применяется WebSocket:

const socket = new WebSocket('wss://example.com/game');

socket.onmess age = (event) => {
    const data = JSON.parse(event.data);
    this.updateRemotePlayer(data);
};

Особенности:

  • Постоянное соединение
  • Мгновенная передача данных
  • Не требует повторных HTTP-запросов

Ленивые загрузки (Lazy Loading)

При больших проектах рекомендуется:

  • Загружать только текущий уровень
  • Освобождать неиспользуемые ресурсы
  • Разделять сцены

Удаление из кэша:

this.cache.json.remove('level1');
this.textures.remove('enemyTexture');

Безопасность при загрузке данных

Серверные данные требуют проверки:

  • Валидация структуры JSON
  • Проверка типов
  • Защита от внедрения кода

Пример базовой проверки:

function validateLevel(data) {
    return data.player &&
           typeof data.player.x === 'number' &&
           Array.isArray(data.enemies);
}

Архитектурные рекомендации

Разделение ответственности:

  • Loader отвечает за получение данных
  • Сцена — за построение уровня
  • Сервисный слой — за взаимодействие с сервером

Рекомендуемая структура:

/scenes
/services
/levels
/utils

Подход к масштабируемости:

  • Использование промисов и async/await
  • Централизованный менеджер загрузки
  • Очереди запросов
  • Кэширование ответов сервера

Комбинированная схема загрузки

В сложных проектах применяется следующая последовательность:

  1. Загрузка базовых ассетов через preload()
  2. Авторизация пользователя
  3. Получение списка доступных уровней
  4. Загрузка конкретного уровня
  5. Построение сцены
  6. Подключение WebSocket при необходимости

Такая модель позволяет создавать:

  • Многопользовательские игры
  • Игры с прогрессией
  • Облачные сохранения
  • Динамически генерируемые уровни

Система загрузки данных в Phaser гибко интегрируется с серверной инфраструктурой и позволяет реализовывать как простые статические уровни, так и полностью динамические игровые миры.