О чем этот пример
Статичный текст — это скучно. В игровых интерфейсах, меню и диалогах хочется динамики. Класс `DynamicBitmapText` в Phaser позволяет управлять отображением каждого символа по отдельности через callback-функцию. Это открывает двери для создания уникальных эффектов: от легкой дрожи и волны до сложной анимации букв. В этой статье мы разберем, как с помощью `setDisplayCallback` добавить эффект хаотичного "вибления" (wibble) к bitmap-тексту, сделав его живым и привлекательным, а также совместим эту технику с базовой твин-анимацией всего объекта.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene
{
constructor ()
{
super();
}
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.bitmapFont('desyrel', 'assets/fonts/bitmap/desyrel.png', 'assets/fonts/bitmap/desyrel.xml');
}
create()
{
var text = this.add.dynamicBitmapText(60, 200, 'desyrel', 'HELLO WORLD!', 64);
text.setDisplayCallback(this.textCallback);
this.tweens.add({
targets: text,
duration: 2000,
delay: 2000,
scaleX: 2,
scaleY: 2,
ease: 'Sine.easeInOut',
repeat: -1,
yoyo: true
});
}
// data = { index: index, charCode: charCode, x: x, y: y, scaleX: scaleX, scaleY: scaleY }
textCallback (data)
{
data.x = Phaser.Math.Between(data.x - 2, data.x + 2);
data.y = Phaser.Math.Between(data.y - 4, data.y + 4);
return data;
}
}
const config = {
type: Phaser.WEBGL,
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
Загрузка bitmap-шрифта и создание динамического текста
Перед работой с текстом необходимо загрузить bitmap-шрифт. В отличие от системных шрифтов, bitmap-шрифт — это набор готовых изображений символов, что гарантирует идентичное отображение на всех устройствах.
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.bitmapFont('desyrel', 'assets/fonts/bitmap/desyrel.png', 'assets/fonts/bitmap/desyrel.xml');
}
После загрузки в методе create мы создаем объект динамического текста. Ключевое отличие DynamicBitmapText от обычного BitmapText — возможность задать функцию обратного вызова для модификации свойств каждого символа.
create()
{
var text = this.add.dynamicBitmapText(60, 200, 'desyrel', 'HELLO WORLD!', 64);
}
Аргументы при создании: позиция X, Y, ключ шрифта, строка текста и размер.
Сердце эффекта: функция обратного вызова `setDisplayCallback`
Метод setDisplayCallback — это главный инструмент. Он принимает функцию, которая будет вызвана для подготовки к отрисовке **каждого символа** в каждом кадре.
text.setDisplayCallback(this.textCallback);
Функция textCallback получает объект data с параметрами текущего символа. Важно: эта функция должна **вернуть** объект data, даже если вы его изменили.
Структура объекта data:
- index: порядковый номер символа в строке.
- charCode: код символа.
- `x,y`: текущие координаты символа.
- scaleX, scaleY: текущий масштаб символа.
В нашем примере функция слегка случайным образом смещает символ относительно его исходной позиции, создавая эффект дрожания.
// data = { index: index, charCode: charCode, x: x, y: y, scaleX: scaleX, scaleY: scaleY }
textCallback (data)
{
data.x = Phaser.Math.Between(data.x - 2, data.x + 2);
data.y = Phaser.Math.Between(data.y - 4, data.y + 4);
return data;
}
Phaser.Math.Between возвращает случайное целое число в заданном диапазоне. Смещение по Y (-4, +4) сделано больше, чем по X (-2, +2), чтобы дрожание казалось более естественным.
Сочетание с общей анимацией: работа твинов
Эффект callback-функции прекрасно комбинируется с системой анимаций Phaser (tweens). В примере мы добавляем твин, который циклически масштабирует весь текстовый объект.
this.tweens.add({
targets: text, // Цель анимации — наш объект text
duration: 2000, // Длительность одного цикла — 2 секунды
delay: 2000, // Задержка перед стартом — 2 секунды
scaleX: 2, // Конечный масштаб по X
scaleY: 2, // Конечный масштаб по Y
ease: 'Sine.easeInOut', // Плавная функция easing
repeat: -1, // Бесконечное повторение
yoyo: true // Движение "туда-обратно"
});
Важный момент: функция textCallback работает с **исходными** координатами символа внутри объекта. Даже когда scaleX и scaleY всего объекта меняются твином, callback-эффект дрожания применяется корректно, так как он модифицирует позицию символа до применения общего трансформа объекта. Это демонстрирует мощь и гибкость разделения логики: callback управляет символом, а твин — всем объектом в сцене.
Конфигурация игры и запуск сцены
Код завершается стандартной для Phaser 3 конфигурацией игры и ее инстанцированием.
const config = {
type: Phaser.WEBGL, // Используем WebGL рендерер
parent: 'phaser-example', // ID DOM-элемента для канваса
scene: Example // Наша основная сцена
};
const game = new Phaser.Game(config);
Указание type: Phaser.WEBGL обеспечивает аппаратное ускорение графики, что важно для плавности эффектов, особенно при большом количестве анимированных объектов.
Что попробовать дальше
DynamicBitmapText с setDisplayCallback — это мощный инструмент для оживления текста в вашей игре. Мы реализовали простой, но эффектный "wibble"-эффект, который легко комбинируется с другими анимациями.
**Идеи для экспериментов:**
1. Свяжите силу дрожания (Phaser.Math.Between) со значением из игрового процесса (например, здоровьем персонажа или уровнем напряжения).
2. Внутри callback используйте data.index для создания волнообразных эффектов, применяя синус или косинус к смещению символов.
3. Попробуйте анимировать не только `xиy, но иscaleX,scaleY` каждого символа для эффекта пульсации.
