О чем этот пример
При разработке интерактивных игр часто возникает задача, когда один и тот же объект должен реагировать и на клик, и на перетаскивание. Сделать это интуитивно понятным для игрока — непросто. Если игрок нажал на объект, чтобы его перетащить, но сразу же отпустил палец или кнопку мыши, был ли это клик или очень короткая попытка drag? Phaser решает эту проблему с помощью свойства `dragTimeThreshold`. Эта статья покажет, как использовать этот порог времени, чтобы четко разделить два типа взаимодействия и сделать управление в вашей игре отзывчивым и предсказуемым.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene
{
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('eye', 'assets/pics/lance-overdose-loader-eye.png');
}
create ()
{
const image = this.add.sprite(200, 300, 'eye').setInteractive();
this.input.setDraggable(image);
// The pointer has to be held down for 500ms before it's considered a drag
this.input.dragTimeThreshold = 500;
this.input.on('dragstart', (pointer, gameObject) =>
{
gameObject.setTint(0xff0000);
});
this.input.on('drag', (pointer, gameObject, dragX, dragY) =>
{
gameObject.x = dragX;
gameObject.y = dragY;
});
this.input.on('dragend', (pointer, gameObject) =>
{
gameObject.clearTint();
});
}
}
const config = {
type: Phaser.WEBGL,
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
Что такое dragTimeThreshold?
Свойство dragTimeThreshold объекта this.input определяет минимальное время (в миллисекундах), которое указатель (мышь или палец) должен удерживаться на перетаскиваемом объекте, прежде чем событие будет считаться началом перетаскивания (dragstart).
Если пользователь отпустит кнопку мыши или палец раньше, чем истечет это время, событие перетаскивания не сработает. По умолчанию это значение равно 0 мс, что означает, что любое движение указателя при зажатой кнопке сразу запускает drag. Установка порога позволяет игнорировать случайные микродвижения и четко разделять намеренный drag и обычный клик (или tap на сенсорных устройствах).
Подготовка перетаскиваемого объекта
Для начала нужно создать интерактивный спрайт и разрешить системе ввода перетаскивать его. Это делается в методе create сцены.
const image = this.add.sprite(200, 300, 'eye').setInteractive();
this.input.setDraggable(image);
Сначала мы создаем спрайт в координатах (200, 300) с текстом 'eye'. Вызов .setInteractive() делает этот спрайт чувствительным к событиям ввода. Затем метод this.input.setDraggable(image) регистрирует этот спрайт в системе ввода как объект, который можно перетаскивать.
Настройка порога времени
Ключевой шаг — установка порога. В примере он установлен на 500 миллисекунд (полсекунды). Это означает, что игрок должен удерживать палец или кнопку мыши на объекте не менее полусекунды, прежде чем его движение начнет считаться перетаскиванием.
this.input.dragTimeThreshold = 500;
Вы можете экспериментировать с этим значением. Для игр, где важна быстрая реакция, подойдет значение 100-200 мс. Для более размеренных или стратегических игр, где нужно четко отделить клик от drag, можно поставить и 1000 мс.
Обработка событий перетаскивания
После настройки порога мы подписываемся на три события: начало перетаскивания, сам процесс и его окончание. В данном примере логика проста: при начале объект окрашивается в красный, во время движения следит за указателем, а в конце цвет сбрасывается.
this.input.on('dragstart', (pointer, gameObject) => {
gameObject.setTint(0xff0000); // Подсвечиваем объект красным
});
this.input.on('drag', (pointer, gameObject, dragX, dragY) => {
gameObject.x = dragX; // Обновляем X-координату
gameObject.y = dragY; // Обновляем Y-координату
});
this.input.on('dragend', (pointer, gameObject) => {
gameObject.clearTint(); // Убираем подсветку
});
Важно: события dragstart, drag и dragend сработают только в том случае, если указатель удерживался на объекте дольше, чем dragTimeThreshold. Если пользователь отпустит раньше, эти события вызваны не будут.
Полный код примера
Вот полный код сцены и конфигурации игры, который объединяет все шаги.
class Example extends Phaser.Scene {
preload() {
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('eye', 'assets/pics/lance-overdose-loader-eye.png');
}
create() {
const image = this.add.sprite(200, 300, 'eye').setInteractive();
this.input.setDraggable(image);
// The pointer has to be held down for 500ms before it's considered a drag
this.input.dragTimeThreshold = 500;
this.input.on('dragstart', (pointer, gameObject) => {
gameObject.setTint(0xff0000);
});
this.input.on('drag', (pointer, gameObject, dragX, dragY) => {
gameObject.x = dragX;
gameObject.y = dragY;
});
this.input.on('dragend', (pointer, gameObject) => {
gameObject.clearTint();
});
}
}
const config = {
type: Phaser.WEBGL,
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
Что попробовать дальше
Свойство dragTimeThreshold — это простой, но мощный инструмент для тонкой настройки управления. Оно позволяет сделать взаимодействие с игровыми объектами более точным и удобным, устраняя ложные срабатывания.
**Идеи для экспериментов:**
1. Попробуйте связать dragTimeThreshold со сложностью уровня или характеристиками игрового персонажа (например, чем выше ловкость, тем меньше порог).
2. Используйте разные пороги для разных типов объектов в игре (например, тяжелые ящики требуют более долгого удержания).
3. Визуализируйте процесс «заряда» перетаскивания с помощью прогресс-бара или изменяющегося тинта, чтобы давать игроку обратную связь.
