|
|||||||
АвтоАвтоматизацияАрхитектураАстрономияАудитБиологияБухгалтерияВоенное делоГенетикаГеографияГеологияГосударствоДомДругоеЖурналистика и СМИИзобретательствоИностранные языкиИнформатикаИскусствоИсторияКомпьютерыКулинарияКультураЛексикологияЛитератураЛогикаМаркетингМатематикаМашиностроениеМедицинаМенеджментМеталлы и СваркаМеханикаМузыкаНаселениеОбразованиеОхрана безопасности жизниОхрана ТрудаПедагогикаПолитикаПравоПриборостроениеПрограммированиеПроизводствоПромышленностьПсихологияРадиоРегилияСвязьСоциологияСпортСтандартизацияСтроительствоТехнологииТорговляТуризмФизикаФизиологияФилософияФинансыХимияХозяйствоЦеннообразованиеЧерчениеЭкологияЭконометрикаЭкономикаЭлектроникаЮриспунденкция |
D-конструктор
Эффект, который мы создадим, будет действительно необычен. Это куб, составленный из маленьких кубиков. «Ну и что, — скажете вы, — я нарисую такой объект за одну минуту». Да, действительно, не надо быть корифеем во Flash, чтобы изобразить подобную геометрическую фигуру. Но наш куб будет с секретом! При щелчке по любому из составляющих его кубиков последний будет исчезать. Используя это, можно будет получить из куба, например, пирамиду. Интересно? Тогда — вперед.
Flash не предоставляет абсолютно никаких специализированных инструментов для создания трехмерной графики. Любые объекты в нем двумерны и поэтому обладают лишь 2 координатами — х и у — и 2 пространственными характеристиками — шириной и высотой. Как при этом возможно создать трехмерный объект?
Да, задача, конечно, не из самых простых. Но она вполне решаема! Чтобы это понять, вспомните, что в компьютере изначально заложена только двумерная система координат — это горизонталь и вертикаль монитора. Между тем существуют такие великолепные программы, как 3DStudio Max или Bruce 3D, позволяющие создавать абсолютно реалистичные изображения пространственных объектов. Но как это им удается, если средства, которыми обладали их создатели, ничем не шире наших?
Чтобы ответить на этот вопрос, нужно понять, что мы не видим на самом деле объема окружающего мира. Воспринимаемые нами «картинки» — это лишь проекции реальной действительности на плоскость нашего зрения. И не более того. Эффект же объемности создается перспективой и игрой светотени. Именно поэтому художникам удается повторять трехмерную реальность на плоских холстах.
Почему картины средневековья кажутся плоскими и нереалистичными, а полотна эпохи классицизма очень и очень похожи на фотографии? Ведь изображают они одинаковые вещи. Дело в том, что ранние мастера плохо владели законами перспективы — от того их творения и кажутся сейчас примитивными. Нужно понимать, почему дом, стоящий в ста метрах от наблюдателя, будет казаться меньше более близкого, и почему боковая сторона куба должна быть нарисована меньшей по сравнению с центральной. Ответы на все эти вопросы даются в теории перспективы и, отчасти, геометрической оптики. «Говорят» же эти науки на языке математики, а точнее, геометрии.
Как создаются трехмерные объекты, например, в Brace? В принципе, так же, как двумерные во Flash. Описываются положения узловых точек кривых, цвет заливок и распределение источников освещения. Но все это делается в памяти компьютера — ведь, как вы помните, трехмерных изображений быть не может. Перед отображением же на экран выполняется проецирование с учетом всех необходимых искажений и прорисовка теней.
Делаем вывод. Трехмерный мир объективно существует, но видим мы лишь его проекцию. Поэтому, чтобы создать трехмерный эффект во Flash, мы должны описать поведение объектов как пространственное, а затем в нужный момент спроецировать его на плоскость. Четкое понимание этого принципа позволяет делать многие удивительные вещи.
Однако теория без практики мертва, поэтому приступим к созданию задуманного эффекта.
Сперва мы должны нарисовать сам кубик. Для этого решим, как будут расположены оси системы координат. Наиболее простым вариантом с точки зрения математического аппарата является система координат, показанная на рис. 5.3, так как две из трех ее осей совпадают с осями фильма Flash.
Рис. 5.3. Система координат
Пускай для определенности длина ребра кубика будет равна 20 пикселям. Тогда какой длины должны быть параллельные плоскости ZOY ребра? Тоже 20 пикселей? На самом деле, отчего бы и нет, если все ребра равны, а оси перпендикулярны... Пробуем нарисовать куб исходя из этого предположения.
Линия, линия, линия. Заливка, заливка, заливка. И получается параллелепипед! Да, в чем-то мы явно ошиблись (рис. 5.4, а).
Дело в том, что по оси Z видимые размеры объектов сокращаются. Для прямоугольной диметрии (а именно такому виду аксонометрической проекции соответствует выбранное расположение осей) коэффициент искажения принимается равным 0,5, т. е. по оси Z линейные размеры объекта кажутся в два раза меньшими, чем по осям X и Y. Таким образом, длина боковых ребер должна быть меньше передних и составлять 10 пикселей. Учитывая это, рисуем кубик. Советы:
• Включите вспомогательную сетку (команда Grid ► Show Grid контекстного меню рабочего поля). Чтобы размеры ее ячейки совпад&чи с параметрами грани куба, задайте их самостоятельно, воспользовавшись командой Grid ► Edit Grid контекстного меню.
• Рисуйте в масштабе не менее 200 %.
• Чтобы нарисовать боковые ребра, действуйте следующим образом:
o нарисуйте при помощи инструмента Line (Линия) горизонтальный отрезок произвольной длины (чтобы он получился ровным, держите нажатой клавишу <Shift>);
o в окошке width Инспектора Свойств поменяйте величину его ширины на 10;
o чтобы повернуть отрезок на 45°, воспользуйтесь инструментом Free Transform (Свободная трансформация) при нажатой клавише <Shift>; o создайте две копии нарисованного отрезка;
o размещая ребра, перейдите в масштаб 500-800 % — эта работа должна быть выполнена предельно точно, иначе кубики не будут плотно прилегать друг к другу.
• Залить грани необходимо оттенками серого так, чтобы правая была освещена в наибольшей, а передняя — в наименьшей степени.
Рис. 5.4. Изображение кубика: а — неправильное; b — правильное
Мы достаточно подробно описали такую, казалось бы, элементарную операцию, как создание кубика (рис. 5.4, b), так как от нее зависит успешность всей остальной работы.
Переводим кубик в клип (<F8>), назвав его kubik.
Теперь необходимо решить, как мы «размножим» кубик, чтобы сложить из его экземпляров большой куб. Конечно, можно было бы воспользоваться уже знакомым нам методом duplicateMovieClip()- Но это нельзя назвать лучшим решением, так как в ActionScript имеется куда более мощный метод attachMovie().
Метод attachMovie(identifier, name, depth) требует задания следующих параметров:
• identifier — идентификатор символа (вводится в формате строки), экземпляр которого нужно создать. Чтобы его задать, щелкните по соответствующей клипу строке в библиотеке правой кнопкой мыши и задействуйте команду Linkage (Связывание) открывшегося контекстного меню. На появившейся панели поставьте флажок в окошко Export for ActionScript (Экспортировать для ActionScript) и введите в строку Identifier (Идентификатор) любую последовательность символов. Для нашего кубика подходящим идентификатором будет cub;
• name — имя создаваемого экземпляра, аналогично тому, которое прописывается в поле Instance Name Инспектора Свойств. Параметр должен быть задан как строка;
• depth — глубина в стеке объектов, на которую будет помещен экземпляр клипа. Чем больше будет depth экземпляра, тем выше относительно других он будет располагаться. На одной глубине может находиться только один объект. В нашем случае кубики дальнего нижнего левого угла куба должны иметь минимальный, а кубики ближнего верхнего правого угла — максимальный depth.
Как мы будем строить большой куб? Очевидно, так же, как складывается стена из кирпичей: кубик добавляем к кубику, пока не закончится рядок. Переходим к новому рядку и все повторяем заново. Когда завершается слой, начинаем новый и проделываем те же действия, что и на предыдущем.
Промоделировать описанный алгоритм можно, задав 3 вложенных цикла. Верхний будет отвечать за слои, средний — за рядки, нижний — за отдельные кубики в рядках. Соответственно первый будет менять координаты по Z, второй — по Y, третий — по X (другие варианты также возможны).
Пусть большой куб образован 5x5x5=125 маленькими кубиками:
for (var i = 0; i<5; i++) { for (var j = 0; j<5; j++) { for (var k = 0; k<5; k++) { } } }
Когда придет время разместить новый куб, прежде всего должен быть создан очередной экземпляр клипа kubik:
В приведенном коде есть два не оговаривавшихся нами элемента:
arr[n]=attachMovie("cub","cub",n); // "Перетаскиваем" экземпляр // на рабочее время n++; // Отмечаем, что кубиков стало больше // (это предложение должно быть в блоке всегда последним)
• Переменная n. Является счетчиком, определяющим порядковый номер созданного кубика. При ее помощи мы задаем глубину объекта (введенные раньше кубики должны отображаться ниже, чем их более «молодые» коллеги), а также его индекс в массиве агг. Вместо п можно использовать и выражение из переменных циклов (n=25×i+5×j+k). Переменная п должна быть задана вне циклов как 0.
• Массив аrr. В нем мы будем хранить все 125 кубиков. Это куда удобнее (и экономичнее с точки зрения ресурсов компьютера), чем использование функции eval(). Кроме того, многие из задач, которые элементарно решаются при помощи массивов, становятся сверхтрудными при программировании без них. Задать пустой массив надо выше циклов:
var arr:Array[];
Когда кубик будет создан, необходимо вычислить положенные для него координаты.
Если считать, что большой куб располагается по центру рабочей области, то отсчет координат составляющих его кубиков нужно начать со значений X=150,Y=150, Z=0.
Координата по X текущего экземпляра может быть высчитана как произведение длины ребра кубика на количество уже имеющихся в рядке «кирпичиков» (переменная внутреннего цикла k) плюс значение соответствующей координаты точки отсчета:
x=150+20*k;
Координату по Y можно определить, отняв (с учетом выбранного направления оси) от ее начальной величины произведение числа заполненных рядков в слое (переменная среднего цикла j) на высоту рядка:
y=150-20*j;
Аналогично двум предыдущим координатам высчитываете* и Z. Однако в ее случае нужно помнить, что мы имеем дело не с самой осью, а с ее проекцией. Поэтому длину ребра нужно предварительно умножить на коэффициент искажения:
z=10*1;
Переменные х, у, z необходимо явно определить вне циклов, равными null.
Итак, расположение кубиков в пространстве мы описали. Но фильм Flash имеет только две координаты, за которые отвечают свойства _х и _у. Следовательно, мы должны спроецировать координату z на оси X и Y. Но как это сделать? Для того чтобы ответить на этот вопрос, взглянем на нашу систему координат после проецирования на плоскость (рис. 5.5).
Очевидно, что если точка имеет координаты Х=0, Y=0, Z=Z0, то при проецировании ее на плоскость зрения ей будут соответствовать координаты x=-Z0cos(45°) и y=Z0cos(45°) (исходя из рис. 5.5). Из этого следует, что если проецируется точка с координатами Х=Х0,Y=Y0, Z=Z0, то видеть ее мы будем в положении х=Х0 - Z0cos(45°) и y=Y0 + Z0cos(45°).
Исходя из полученных формул должны высчитываться положения кубиков:
arr[n]._x=x-z*Math.SQRTl_2; arr[n]._y=y+z*Math.SQRT1_2;
Вроде бы все. С тревогой в сердце нажимаем <Ctrl> + <Enter>. Неужели не получится?! Неужели о своих рассуждениях мы были не правы?! Ура! Работает (рис. 5.6)!
Изображением кубика трудно кого-то удивить. А вот если бы можно было щелчком мыши удалять любой из его кирпичиков, создавая тем самым более сложные геометрические фигуры — вот это было бы интересно. Но как это сделать?
Рис. 5.5. Спроецированная система координат
Рис. 5.6. Собранный кубик
Можно поступить следующим образом: при наступлении события onMouseDown запускать цикл и проверять, что возвращает метод hitTest() для каждого из экземпляров. Правда, в данном случае нужно было бы «прочесывать» массив с конца, так как должен быть убран тот из находившихся под указателем мыши во время щелчек экземпляров, который расположен выше всех остальных. Однако такой подход нельзя назвать техничным ввиду громоздкости его кода и большого количества пышных операций.
Подумайте, как все было бы просто, если бы наши кубики относились к классу Button. Достаточно было бы просто создать для каждого из них обработчик события onPress, содержащий в блоке удаляющий объект код. Но клипы — это, увы, не кнопки...
Д(клипы — это не кнопки, но во Flash MX Macromedia немало облегчила труд разработчиков, сделав «кнопочные» события «родными» и для класса MovieClip, т t события onPress, onRelease, onRollOut, onRollOver, onDragOut, onDragOver слушаются» и клипами точно также, как, например, onEnterFrame. И это существенно облегчает нашу задачу.
Возникает вопрос — мы же не можем создать отдельный обработчик для каждого из 125 экземпляров? Можно ли как-то «сказать» всем кубикам сразу, что при щелчке по одному из них он должен исчезнуть?
Кубики — это братья-близнецы. Более того — они даже ближе, поскольку являются лишь ссылками на клип в библиотеке. А что, если «повесить» код на временную шкалу этого клипа? Тогда ему будут следовать все его экземпляры.
Остается нерешенной одна техническая деталь. Как указать обработчику, что он должен «слушать» события именно того экземпляра, на временной шкале которого он «висит»? А сделать это можно очень просто, использовав ключевое слово this. Его особенность заключается в том, что оно всегда возвращает адрес той временной шкалы, на которой находится:
trace(this); // Выводит: _level0 (код введен на первый кадр основной // временной шкалы)
Код, который нужно ввести на первый кадр расположенного в библиотеке клипа kubik, должен выглядеть как:
this.onPress = function():Void { this.removeMovieClip (); }
Впрочем, учитывая правила цепочек областей видимости, использование this нужно скорее для стройности кода. Ничуть не хуже будет работать и следующий скрипт:
onPress=function() { removeMovieClip(); }
Тестируем фильм. Все получилось! Кубики действительно убираются так, как будто фигура объемная. Светотень же столь естественна, что это даже удивляет. Немного пощелкав по кубу, можно получить самую необычную форму (рис 5.7).
Рис. 5.7. Фигура, полученная из куба
Замечательно! Только вот, правда, мы нарушили один очень важный принцип: весь код должен быть в одном месте (т. е. централизован). Но как можно создать обработчик, действующий на все кубики, не «вешая» его на символ в библиотеке?
Экземпляры клипа наследуют свойства и методы класса MovieClip. Следовательно, чтобы сделать функцию-обработчик присущей сразу всему классу, нужно сохранить ее в прототипе конструктора класса:
MovieClip.prototype.onPress=function()Void { this.removeMovieClip(); }
Добавив этот код к остальному, мы получим тот же результат, что и при размещении обработчика на временной шкале клипа в библиотеке. Однако данный подход имеет огромное преимущество, заключающееся в том, что скрипт обработчика будет существовать в единственном экземпляре. Если же мы «повесим» код на временную шкалу символа в библиотеке, то для каждого экземпляра будет создана отдельная его копия. А это чревато, в случае наличия в фильме большого числа объектов, значительной потерей оперативной памяти. Кроме того, при этом нарушается n принцип централизации кода.
Продемонстрированный код эффективен, так как кроме кубиков в нашем фильме нет других клипов. А если бы были — ведь они бы тоже исчезали при щелчке по ним?
В том случае, если бы на поле присутствовали другие клипы, которые не должны I реагировать на щелчок мышью, мы создали бы новый подкласс на основе MovieClip I и сделали бы кубики его объектами. При этом мы бы могли «повесить» на него функцию, аналогичную приведенной выше, не изменив поведение остальных клипов. На самом деле, возможности объектно- ориентированного программирования в ActionScript очень широки. Мы разберем их досконально в главе 9.
Задуманный эффект уже практически создан. Осталось ликвидировать мелкие недоделки. Обратите внимание, что, как только мы начали «слушать» кнопочные события, при наведении на кубики вид указателя мыши стал меняться со стрелки на руку. Чтобы это изменение не происходило, обратимся к отвечающему за него свойству класса MovieClip useHandCursor. В блок циклов (выше инкрементирования n) введите:
arr[n].useHandCursor=false;
Было бы замечательно, если бы в начале работы фильма куб собирался из кирпичиков на глазах у пользователя. Но замедлить цикл невозможно, а переписывать коя не очень хочется. Мы поступим по-другому. Куб будет создаваться, как и рань-е — почти мгновенно, но из невидимых кирпичиков. Затем же мы будем просто «включать» их в нужной нам последовательности с подходящей частотой.
Чтобы все кубики стали невидимыми, введите в блок цикла:
arr[n]._visible=false.
Несмотря на то что кубики стали невидимыми, они будут реагировать на щелчок мышью точно так же, как и раньше. Это означает, что, если пользователь выполнит нажатие на один из кубиков собирающегося куба, исчезнет не он, а занимающий такое же положение, но расположенный на меньшей глубине его «коллега». Чтобы разрешить эту проблему, можно использовать свойство enabled, определяющее, будет ли слушать клип «кнопочные» события:
arr[n].enabled=false;
Частоту вызовов функции, визуализирующей кубики, мы можем связать с событием onEnterFrame. Но это не слишком рационально, так как не позволяет менять её значение в ходе работы фильма. Гораздо лучше воспользоваться уже знакомой нам по «крестикам-ноликам» функцией setInterval(). В нашем случае в секунду должно появляться 10 кубиков:
// Код нужно разместить строго нижу циклов var time:Number=setInteval(Visual,100); function Visual():Void { // Случайным образом выбираем кубик var t:Number=Math.round(Math.random()*arr.length); arr[t]._visible=true; // Делаем кубик видимым arr[t].enabled=true; }
Чтобы скорость появления кубиков не зависела от количества уже видимых «кирпичиков», «включенный» экземпляр должен удалятся из массива arr:
arr.splice(t,1); // Метод splice() удаляет произвольное число элементов
Когда все кубики станут видимыми, вызовы функции Visual() должны прекратиться. Для этого добавьте в неё следующий код:
if(arr.length==0) { clearInterval(time); }
Вот и все (рис. 5.8). Замечательный эффект готов! При желании вы без труда к нему интерфейс, при помощи которого пользователь сможет задавать число кубиков вдоль каждой из осей, а также начинать сборку заново (соответствующий авторский fla-файл сохранен в папке Проект5 как cub.fla).
Рис. 5.8. Кубик на этапе сборки
Рис.5.9. Сфера из шариков
Домашним же заданием будет следующее: попробуйте написать аналогичную программу, но организующую шарики в большой шар (рис.5.9). Это куда сложнее и будет хорошей проверкой для ваших способностей. Если же у вас нет настроения, то просто изучите созданный автором исходник (он подробно прокомментирован), сохраненный в папке Проект5 как sphere.fla.
Поиск по сайту: |
Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Студалл.Орг (0.022 сек.) |