О чем этот пример
Разработка игр — это управление состоянием и конфигурацией. Часто код обращается к глубоко вложенным свойствам объектов, что грозит ошибками `Cannot read property 'x' of undefined`. Встроенный хелпер Phaser `GetValue` позволяет безопасно извлекать значения по строковому пути, задавая значение по умолчанию. Эта статья покажет, как использовать этот инструмент для написания чистого и надёжного кода, избегая многословных проверок.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
var config = {
type: Phaser.AUTO,
parent: 'phaser-example',
width: 800,
height: 600,
scale: {
width: 400,
height: 300
},
scene: {
create: create
}
};
var game = new Phaser.Game(config);
function create ()
{
var srcA = {
a: {
c: 100
}
}
var srcB = {
b: {
}
}
var value = Phaser.Utils.Objects.GetValue(srcA, 'a.b.c', 66, srcB)
console.log(value)
this.add.text(200, 200, 'hello: ' + value);
}
Проблема: обращение к несуществующим свойствам
Представьте, что в игре есть конфигурационный объект для персонажа, который может быть неполным или изменяться динамически. Прямой доступ к свойству, например, config.abilities.attack.damage, вызовет ошибку, если на любом уровне вложенности (abilities, attack) встретится undefined.
Традиционное решение — серия проверок, которая загромождает код:
let damage = 66; // Значение по умолчанию
if (config && config.abilities && config.abilities.attack) {
damage = config.abilities.attack.damage;
}
Phaser предлагает более элегантный способ с помощью Phaser.Utils.Objects.GetValue.
Синтаксис и параметры GetValue
Метод Phaser.Utils.Objects.GetValue принимает четыре аргумента и возвращает значение свойства или значение по умолчанию.
// Сигнатура метода
var result = Phaser.Utils.Objects.GetValue(source, key, defaultValue, altSource);
* source (объект): Первичный объект для поиска.
* key (строка): Путь к свойству в формате 'a.b.c'.
* defaultValue (любой): Значение, которое вернётся, если свойство не найдено.
* altSource (объект, опционально): Альтернативный объект, в котором будет произведён поиск, если в source свойство не найдено.
Метод проходит по цепочке свойств, указанной в key. Если на каком-то шаге встречается undefined, поиск прекращается и возвращается defaultValue.
Разбор примера из исходного кода
Давайте шаг за шагом разберём исходный пример, чтобы понять логику работы.
var srcA = {
a: {
c: 100
}
};
var srcB = {
b: {
// Пустой объект
}
};
var value = Phaser.Utils.Objects.GetValue(srcA, 'a.b.c', 66, srcB);
console.log(value); // Выведет: 66
1. Поиск начинается в объекте srcA по пути 'a.b.c'.
2. Находится свойство srcA.a (объект { c: 100 }).
3. Далее ищется свойство `bвнутриsrcA.a. Его **нет** (там только свойствоc). ЗначениеsrcA.a.b—undefined`.
4. Поскольку поиск в srcA не увенчался успехом, метод переключается на альтернативный источник — объект srcB.
5. В srcB поиск идёт с начала пути 'a.b.c'. Свойства srcB.a не существует, оно равно undefined.
6. Так как свойство не найдено ни в srcA, ни в srcB, метод возвращает значение по умолчанию — 66.
Ключевой вывод: altSource — это не «продолжение» пути из srcA, а **полностью альтернативный объект** для поиска по тому же самому пути с начала.
Практическое применение в игровых сценах
Вот как можно использовать GetValue для настройки игровых объектов, например, спрайтов с опциональными свойствами.
function create() {
// Конфиг врага. Свойство 'projectile.speed' отсутствует.
var enemyConfig = {
texture: 'orc',
health: 50,
projectile: {
texture: 'fireball'
}
};
// Безопасное извлечение скорости снаряда с значением по умолчанию.
var projectileSpeed = Phaser.Utils.Objects.GetValue(enemyConfig, 'projectile.speed', 200);
// Извлечение текстуры врага. Путь существует.
var enemyTexture = Phaser.Utils.Objects.GetValue(enemyConfig, 'texture', 'default_enemy');
this.add.text(10, 10, `Скорость снаряда: ${projectileSpeed}`, { fill: '#0f0' });
this.add.sprite(100, 300, enemyTexture);
}
Этот подход идеален для: * Загрузки уровней из JSON-файлов, где некоторые параметры могут быть опущены. * Создания систем диалогов или событий с ветвлением. * Настройки физических свойств объектов, где часть параметров общая, а часть — уникальна.
Что попробовать дальше
Phaser.Utils.Objects.GetValue — это мощный инструмент для работы с конфигурацией, который делает код безопаснее и чище, избавляя от каскада условных операторов. Он особенно полезен при загрузке внешних данных или работе с большими иерархическими объектами состояния игры.
**Идеи для экспериментов:**
1. Создайте систему настроек игры, где пользователь может менять только часть параметров, а остальные берутся из конфига по умолчанию.
2. Реализуйте диалоговую систему, где ответ NPC зависит от цепочки флагов player.quests.forest.elderSpoke, безопасно извлекаемой через GetValue.
3. Используйте altSource для создания системы наследования свойств: сначала ищите в конфиге конкретного монстра, а если свойства нет — в конфиге его типа (например, 'goblin').
