О чем этот пример
При создании игр часто требуется разместить объекты вдоль пути, например, монеты на трассе или охрану по периметру. Просто взять точки из кривой недостаточно — они будут распределены неравномерно, сгущаясь на резких поворотах. В этой статье разберем, как метод `getDistancePoints` объекта `Phaser.Curves.Spline` позволяет легко получить набор точек, отстоящих друг от друга на заданное расстояние, что идеально подходит для расстановки игровых элементов.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene
{
graphics;
size = 32;
points;
curve;
create ()
{
this.graphics = this.add.graphics();
this.curve = new Phaser.Curves.Spline([
50, 300,
164, 246,
274, 342,
412, 257,
522, 341,
664, 264
]);
this.points = this.curve.getDistancePoints(this.size);
}
update ()
{
this.graphics.clear();
this.graphics.lineStyle(1, 0xffffff, 1);
this.curve.draw(this.graphics, 64);
this.graphics.fillStyle(0x00ff00, 1);
this.graphics.lineStyle(1, 0x00ff00, 1);
for (let i = 0; i < this.points.length; i++)
{
const p = this.points[i];
this.graphics.fillCircle(p.x, p.y, 2);
// var x = p.x - (size / 2);
// var y = p.y - (size / 2);
// graphics.strokeRect(x, y, size, size);
}
}
}
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
backgroundColor: '#2d2d2d',
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
Создание сплайна и подготовка
Работа начинается с создания сплайновой кривой. В Phaser 3 для этого используется класс Phaser.Curves.Spline. Ему передается массив чисел, где каждая пара представляет координаты (x, y) опорной точки. Кривая автоматически проводится через эти точки.
this.curve = new Phaser.Curves.Spline([
50, 300,
164, 246,
274, 342,
412, 257,
522, 341,
664, 264
]);
После создания кривой мы сразу вычисляем массив точек, равноотстоящих друг от друга, с помощью ключевого метода getDistancePoints. Ему передается желаемое расстояние между точками.
this.size = 32;
this.points = this.curve.getDistancePoints(this.size);
Здесь this.size = 32 означает, что расстояние между соседними точками вдоль кривой будет примерно 32 пикселя. Метод возвращает массив объектов Phaser.Math.Vector2.
Визуализация в методе update
Для анимации или динамического отображения вся отрисовка происходит в методе update. Первым делом очищаем холст графики от предыдущего кадра, чтобы избежать наложения.
this.graphics.clear();
Затем настраиваем стиль линии и рисуем саму сплайновую кривую для наглядности. Метод draw отрисует кривую, разбив ее на 64 сегмента для плавности.
this.graphics.lineStyle(1, 0xffffff, 1);
this.curve.draw(this.graphics, 64);
Далее меняем стиль на зеленый для отрисовки рассчитанных точек. Сначала устанавливаем стиль заливки для кружков, а затем — стиль линии (он может пригодиться для отладки, например, рисования квадратов).
this.graphics.fillStyle(0x00ff00, 1);
this.graphics.lineStyle(1, 0x00ff00, 1);
Отрисовка равноотстоящих точек
Имея массив точек this.points, мы проходим по нему в цикле. Для каждой точки `pмы рисуем маленький зеленый кружок с помощьюfillCircle`.
for (let i = 0; i < this.points.length; i++)
{
const p = this.points[i];
this.graphics.fillCircle(p.x, p.y, 2);
}
Этот простой цикл визуализирует результат работы getDistancePoints. В закомментированном коде показан альтернативный вариант отладки — рисование квадратов размером this.size вокруг каждой точки. Это наглядно демонстрирует, что расстояние между *центрами* точек действительно равно заданному значению.
// var x = p.x - (size / 2);
// var y = p.y - (size / 2);
// graphics.strokeRect(x, y, size, size);
Практическое применение в играх
Метод getDistancePoints — это не просто инструмент для визуализации. Его основная сила — в геймдизайне и логике.
* **Расстановка коллекционных предметов:** Размещайте монеты, патроны или бонусы на извилистой дорожке ровными рядами. * **Патрулирование врагов:** Задайте точкам, полученным от кривой, статус "контрольных". Пусть стражник перемещается от одной точки к следующей по циклу, создавая предсказуемый, но визуально сложный маршрут. * **Траектория движения:** Используйте массив точек как готовый путь для объекта, движущегося с постоянной скоростью. Это проще, чем вычислять позицию на кривой вручную.
Ключевое преимущество перед использованием getPoints — равномерность. getPoints возвращает точки, равномерно распределенные по *параметру t* кривой, что на резких изгибах дает их сгущение. getDistancePoints гарантирует равномерность по *длине пути*, что почти всегда является желаемым поведением в игре.
Что попробовать дальше
Метод getDistancePoints — это мощный и простой способ превратить любую сплайновую кривую в удобный маршрут для игровых объектов. Он решает проблему неравномерного распределения, позволяя сосредоточиться на дизайне уровней, а не на математических расчетах.
**Идеи для экспериментов:**
1. Динамически меняйте расстояние this.size в зависимости от скорости игрока, чтобы создавать разреженные или плотные группы объектов.
2. Вместо отрисовки кружков создавайте в этих точках спрайты (this.add.sprite) и анимируйте их.
3. Скомбинируйте несколько кривых и их точки, чтобы создать сложную сеть патрулей или разветвленную трассу для гонок.
