Записки
     из интернета

Генератор деревьев

12 Январь 2010 . Alex пишет -

Данная заметка посвящена рисованию деревьев естественного вида с применением стандартных средств (рекурсия/многократное применение алгоритма с масштабированием). В дальнейшем будет показано, как создать движение с использованием внутренней иерархии анимационных клипов.

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

Когда то Джош Дэвис (Josh Davis) говорил о мотивации своей работы. Если свести его 45-минутную речь к одной фразе, он сказал: «Взгляните на природу, на то, что находится у вас прямо перед глазами, - а затем подумайте, что с этим можно сделать во Flash». Всемирная паутина полна подобных экспериментов.

Вот что мне удалось узнать о деревьях, не выходя за порог дома. Деревья растут по очень простому принципу, который обычно неукоснительно соблюдается. Ветка растет прямой до определенной длины, после чего сама разветвляется. Как правило, толщина родительской ветки связана с толщиной веток, растущих из нее, отношением, сохраняющим значение площади поперечного среза (общая толщина ствола примерно равно толщине всех ветвей, растущих из него, или пропорциональна ей). А это означает, что отросток растет и делится точно по тем же правилам, что и основная ветвь: их относительные размеры остаются одинаковыми.

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

Учитывая все сказанное, я разработал случайный генератор деревьев

Оба дерева (а также множество других) были сгенерированы одной функцией.

Далее приведен код файла treeGen.fla.

function counter () {

if (branchCounter = = undefined) {

branchCounter =0;

}

return (branchCounter++);

}

function grow() {

// Вырастить ветвь…

this.lineStyle(trunkThickness, 0×0. 100);

this.moveTo(0, 0);

this ЛineTo(0. trunkLength);

// Если это не ствол, изменить угол и размер ветви

if (this._name != “trunk”) {

this._rotation = (Math.random()*angle) - angle/2;

this._xscale *=’branchSize:

this._yscale *= branchSize;

}

. // Сгенерировать ростки…

var seed = Math.ceil(Math.random()*branch);

for (var i = 0; i < seed; i++) {

if (counterO < 3000) {

var segment = this.createEmptyMovieClip(”segment” + i. i)

segment.onEnterFrame = grow;

segment.+y = trunkLength; }

}

delete (this.onEnterFrame);

// Определить позицию ствола и назначить обработчиком

// события onEnterFrame функцию grow()

this.createEmptyMovieClip(”trunk”. 0);

trunk._x = 200;

trunk._y = 400:

trunk.onEnterFrame = grow;

// Параметры дерева

var angle = 100;

var branch = 5;

var trunkThickness = 8;

var trunkLength = -100;

var branchSize =0.7;

Базовая форма дерева определяется параметрами, значения которых задаются

в завершающих строках листинга:

angle - максимальный угол ветви по отношению к родителю;

branch - максимальное количество ростков (дочерних ветвей) для любой ветви;

• trunkThickness - толщина ствола дерева;

• trunkLength - длина ствола дерева;

branchSize - отношение размеров дочерней и родительской ветвей (ветви уменьшаются по мере удаления от ствола).

Сначала мы создаем ствол и задаем его позицию, после чего назначаем функцию grow() обработчиком события onEnterFrame. Как подсказывает само название, функция grow() «выращивает» пустое дерево в нашем клипе, для чего она выполняет две операции. Сначала функция создает исходную ветвь, рисуя вертикальную линию высотой trunkLength и толщиной trunkThickness. Если в настоящее время рисуется ствол, он оставляется в первоначальном виде (фаза 1).

Если же рисуется ветвь, она поворачивается на угол +/- angle (фаза 2) и масштабируется с коэффициентом branchSize (фаза 3).

Затем функция создает от 1 до branch новых «ростков». Весь фокус в том, что ростки получают тот же обработчик onEnterFrame, что и текущий, а именно grow(), поэтому в следующем кадре они отращивают собственные ростки и т. д. Здесь используется фрагмент кода, который создает новый анимационный клип для каждого ростка и назначает ему обработчик события onEnterFrame. Дерево могло бы создавать новые ростки до бесконечности, но процесс необходимо как-то ограничить, иначе Flash будет работать все медленнее и в итоге просто «зависнет». Чтобы предотвратить эту ситуацию, функция counter() ограничивает общее количество ветвей пороговым значением 3000:

var seed = Math.cei1(Math.randomC)*branch);

for (var i = 0; i < seed: i++) {

if (counterO < 3000) {

var segment = this.createEmptyMovieClip(”segment” + i. i);

segment.onEnterFrame = grow:

segment.+y = trunkLength: }

}

В завершение grow() удаляет себя, поскольку она должна выполняться только один раз для каждой ветви.

Итак, мы используем функцию, которая вызывает сама себя (а точнее, создает копии ветвей, с которыми связана та же функция) для построения рекурсивного дерева. В итоге иерархия построенного дерева, состоящего из ветвей и субветвей, отражается на временных диаграммах клипов. В этом нетрудно убедиться при помощи отладчика (возможно, максимальное количество ветвей стоит выбрать меньшим 3000 - в противном случае ждать придется довольно долго!).

Результат своей строгой простотой напоминает восточные гравюры. Тем не менее, в нем не задействована анимация, а генераторы статических деревьев на Java  встречаются на каждом углу. По этой причине в следующей заметке мы слегка оживим свое дерево.

Рубрики: Флеш |

Комментариев нет

Комментариев нет.

Оставить трекбек со своего сайта.
адрес - http://www.free-notes.ru/wp-trackback.php?p=121

Оставить комментарий

Вам нужно войти для комментирования.