
- •Оглавление
- •Вступление
- •Глава 1. Язык сценариев. ActionScript: начальные сведения
- •Проект 1: Прыгающий мяч (программная анимация)
- •1.1. Среда разработки ActionScript: настройка и приемы работы
- •1.1.1. Различие между стандартной и профессиональной версиями Flash
- •1.1.2. Панель Actions
- •1.1.3. Режим упрощенного ввода кода. Панель Behaviors
- •1.1.4. Как упростить создание кода на панели Actions
- •1.1.5. Типы сценариев
- •1.1.6. Централизация кода
- •1.1.7. Инструменты работы с кодом
- •1.1.8. Настройки стиля кода
- •1.1.9. Сохранение ActionScript-кода
- •1.1.10. Функция trace() и панель Output
- •1.1.11. Справочная информация
- •1.2. Синтаксис ActionScript
- •1.2.1. Пробельные символы
- •1.2.2. Завершение предложений
- •1.2.3. Чувствительность к регистру
- •1.2.4. Зарезервированные слова ActionScript
- •1.2.5. Принципы присвоения имен
- •1.2.6. Комментарии
- •1.3. Основные понятия
- •1.3.2. ActionScript как скриптовый язык Flash-плейера
- •1.3.3. Интерпретатор ActionScript. Flash-ассемблер
- •1.3.4. Символы и экземпляры символов
- •1.3.5. Переменные
- •1.3.6. Функции
- •1.3.7. Условные предложения
- •1.3.8. Циклы
- •1.3.9. Массивы
- •1.3.10. Объектная модель ActionScript
- •1.3.11. Свойства _root, _parent, Leveln и ключевое слово this
- •1.3.12. Области видимости кода
- •1.3.1. ЕСМА-262 как основа ActionScript
- •Глава 2. Типы данных
- •2.3. Математические функции и константы. Объект Math
- •2.3.1. Особенности реализации математических функций
- •2.3.2. Возведение в степень и вычисление квадратного корня
- •2.3.3. Экспонента и натуральный логарифм
- •2.3.5. Случайные числа
- •2.3.6. Округление до целого числа
- •2.3.7. Сравнение пары чисел
- •2.3.8. Тригонометрические функции
- •2.3.9. Математические константы
- •2.4. Строки (тип string)
- •2.4.1. Создание строк
- •2.4.2. Элементарные операции со строками
- •2.4.3. Класс String
- •2.4.4. Определение длины строки. Свойство lengths
- •2.4.5. Соединение строк. Метод concat()
- •2.4.6. Выделение символа строки по индексу. Метод charAt()
- •2.4.7. Поиск в строке. Методы indexOf() и lastIndexOff()
- •2.4.8. Извлечение подстроки. Методы substring(), substr(), slice()
- •2.4.9. Преобразование строк в массивы. Метод split()
- •2.4.12. Преобразование строк в идентификаторы. Функция eval()
- •2.4.13. Текстовые поля
- •2.5. Кодировка символов. Уникод во Flash
- •2.5.1. Немного истории
- •2.5.2. Поддержка уникода Flash-плейером
- •2.5.3. Поддержка уникода средой разработки
- •2.5.4. Добавление символов уникода
- •2.6. Логические величины (тип boolean)
- •2.6.1. Класс Boolean
- •2.7. Тип undefined
- •2.8. Тип null
- •2.9. Объекты (тип object)
- •2.9.1. Атрибуты свойств
- •2.9.2. Изменение атрибутов свойств. Функция ASSetPropFlags()
- •2.10. Клипы (тип movieclip)
- •2.11. Преобразование типов данных
- •2.11.1. Правила преобразования типов
- •2.11.2. Автоматическое преобразование типов
- •2.12. Строгая типизация в ActionScript
- •Проект 2: Калькулятор
- •2.1. Определение типа объекта данных
- •2.2. Числа (тип number)
- •2.2.1. Виды чисел в ActionScript
- •2.2.2. Особенности представления чисел
- •2.2.3. Операции с числами
- •2.2.4. Класс Number — методы и свойства
- •2.2.5. Преобразование строк в числа. Функции parseInt() и parseFloat()
- •Глава 3. Переменные
- •3.1. Создание переменных
- •3.2. Особенности типизации переменных
- •3.3. Локальные переменные функций
- •3.4. Глобальные переменные
- •3.5. Особенности операции присваивания
- •3.6. Есть ли переменные в ActionScript?
- •3.7. Удаление переменных
- •Проект 3: Пружинный маятник
- •Глава 4. Функции
- •4.1. Создание функций
- •4.2. Вызов функций
- •4.3. Предложение return
- •4.4. Рекурсия
- •4.5. Особенности цепочки областей видимости функций
- •4.6. Объект arguments
- •4.6.1. Формальные параметры и объект arguments
- •4.6.2. Свойства объекта arguments
- •4.7. Особенности передачи в функции составных объектов данных
- •4.8. Функции как объекты
- •4.8.1. Класс Function
- •4.8.2. Свойство prototype
- •4.8.3. Методы вызова функции
- •4.9. Функции на стадии выполнения. Объект активации
- •Проект 4: Крестики-нолики
- •Глава 5. Операторы
- •5.1. Виды операторов
- •5.2. Иерархия операций
- •5.3. Сочетательность операций
- •5.4. Арифметические операторы
- •5.5. Операторы присваивания
- •5.5.1. Оператор =
- •5.5.2. Операторы присваивания с модификацией
- •5.5.3. Инкрементирование и декрементирование
- •5.6. Операторы равенства и сравнения
- •5.6.1. Операторы равенства
- •5.6.2. Операторы сравнения
- •5.7. Логические операторы
- •5.8. Условный оператор (?:)
- •5.9. Служебные операторы
- •5.9.1. Инициализаторы литералов
- •5.9.2. Оператор группирования
- •5.9.3. Операторы доступа к свойствам
- •5.9.4. Оператор вызова функции
- •5.9.5. Оператор new
- •5.9.6. Оператор super
- •5.9.7. Оператор delete
- •5.9.8. Оператор typeof
- •5.9.9. Оператор instanceof
- •5.9.10. Оператор void
- •5.9.11. Оператор «запятая»
- •5.10. Поразрядные операторы
- •5.10.1. Логические поразрядные операторы
- •5.10.2. Операторы поразрядного сдвига
- •Проект 5: 3D-конструктор
- •Глава 6. Предложения
- •6.1. Блок предложений
- •6.2. Предложения var и function
- •6.3. Предложения выражений и пустые предложения
- •6.4. Предложение return
- •6.5. Предложение with
- •6.6. Условные предложения
- •6.6.1. Предложение if
- •6.6.2. Предложение switch
- •6.7. Циклы
- •6.7.1. Циклы с предусловием (while и do—while)
- •6.7.2. Цикл с параметром (for)
- •6.7.4. Предложения break и continue
- •6.7.5. Ограничение на время выполнения кода
- •6.7.6. Циклы события onEnterFrame и временной диаграммы
- •6.7.7. Циклический вызов функций. Функция setInterval()
- •Проект 6: Тетрис
- •Глава 7. Массивы (класс Array)
- •7.1. Создание массивов
- •7.2. Извлечение и переопределение элементов массива
- •7.3. Длина массива. Свойство length
- •7.4. Добавление элементов в массив
- •7.5. Удаление элементов массива
- •7.6. Слияние массивов
- •7.7. Выделение фрагмента массива
- •7.8. Инверсия массива
- •7.9. Сортировка массива
- •7.10. Преобразование массива в строку
- •7.11. Многомерные массивы
- •7.13. Особенности реализации массивов в ActionScript
- •Проект 7: Пиксельное табло
- •Глава 8. События
- •8.1. Модель событий Генератор—Листенеры
- •8.1.1. Обработчики событий
- •8.1.2. Листенеры
- •8.2. Событийные методы
- •8.3. Модель событий Flash 5
- •8.4. Обновление экрана при событиях
- •Проект 8: Создаем события сами
- •Глава 9. Объектно-ориентированное программирование
- •9.2.1. Объекты
- •9.2.2. Свойства
- •9.2.3. Методы
- •9.2.4. Классы
- •9.2.5. Наследование
- •9.2.6. Создание надклассов и подклассов
- •9.2.7. Концепция создания надклассов Flash 6
- •9.2.8. Оператор super
- •9.2.9. Свойства и методы конструктора класса
- •9.2.10. Определение принадлежности объекта к классу
- •9.2.11. Цепочка областей видимости. Объект Global
- •9.3. Класс Object
- •9.3.1. Создание объектов класса Object
- •9.3.2. Метод registerClass(). Выделение экземпляров клипа в класс
- •9.3.3. Метод addProperty(). Свойства типа getter/setter
- •9.3.4. Методы watch() и unwatch(). События изменений свойств
- •9.3.5. Прочие методы класса Object
- •9.4.1. Создание классов
- •9.4.2. Задание наследуемых свойств и методов класса
- •9.4.3. Конструктор класса. Инициализация собственных свойств и методов объектов
- •9.4.4. Особенности задания методов в AciionScript2.0
- •9.4.5. Статичные члены класса
- •9.4.7. Динамические классы
- •9.4.8. Наследование
- •9.4.9. Интерфейсы
- •9.4.10. Свойства типа getter/setter
- •9.4.11. Выделение экземпляров символа в подкласс
- •9.4.12. Особенности контроля на этапе компиляции
- •9.4.13. Особенности импорта внешних классов
- •9.4.14. Пакеты
- •9.4.15. Встроенные классы. Директива intrinsic
- •Проект 9: Модель идеального газа
- •Глава 10. Клипы
- •10.1. Глобальные функции и свойства
- •10.2. Отличия клипов от объектов
- •10.2.1. Свойства клипов
- •10.3. Клипы как носители кода
- •10.3.1. Последовательность выполнения кода
- •10.3.2. Особенности использования свойств и методов класса MovieClip
- •10.4. Особенности основной временной диаграммы _root
- •10.5. Создание экземпляров клипов
- •10.5.1. Метод duplicateMovieClip()
- •10.5.3. Метод createEmptyMovieClip(). Создание пустого клипа
- •10.6. Виртуальные слои клипов
- •10.6.1. Изменение глубины клипа. Метод swapDepths()
- •10.7. Импорт внешних фильмов и изображений
- •10.7.2. Импорт внешних фильмов при помощи функций loadMovie() и loadMovieNum()
- •10.7.3. Импорт изображений
- •10.7.4. Импорт фильмов и изображений при помощи класса MovieClipLoader
- •10.7.5. Создание предзагрузчиков
- •10.7.6. Кэширование swf-фильмов
- •10.7.7. Изменение глубины основной временной диаграммы
- •10.7.8. Доступ из одного фильма к объектам другого
- •10.7.9. Обобщенные библиотеки
- •10.8. Имена экземпляров клипов
- •10.9. Ссылки на клипы
- •10.9.1. Свойство _lockroot
- •10.9.2. Определение пути к клипу
- •10.9.3. Инструмент Insert Target Path
- •10.10. Система координат клипов
- •10.10.1. Свойство _x и _y
- •10.10.2. Пересчет координат из одной системы в другую
- •10.10.3. Масштаб осей
- •10.10.4. Размер клипа
- •10.10.5. Границы клипа
- •10.10.6. Поворот системы координат
- •10.11. Прозрачность и видимость клипа
- •10.11.1. Свойство _alpha
- •10.11.2. Свойство _visible
- •10.12. Перемещаемые клипы. Метод startDrag()
- •10.12.1. Свойство _droptarget
- •10.13. Коллизии клипов. Метод hitTest()
- •10.13.1. Определение пересечения двух клипов
- •10.13.2. Определение принадлежности точки к клипу
- •10.13.3. Определение коллизии клипов с использованием поточечного перебора
- •10.14. Управление временной диаграммой
- •10.14.1. Начало и остановка проигрывания клипа
- •10.14.2. Переход на новый кадр
- •10.14.3. Определение номера проигрываемого кадра
- •10.15. Программные маски
- •10.16. Удаление экземпляров клипов и фильмов
- •10.16.1. Удаление экземпляров. Метод removeMovieClip()
- •10.16.2. Выгрузка содержимого экземпляров. Метод unloadMovie()
- •10.16.3. Выгрузка фильмов
- •10.17. События
- •10.17.1. Создание обработчиков событий в стиле Flash 5
- •10.17.2. Событие смены кадров (onEnterFrame)
- •10.17.3. Событие загрузки клипа (onLoad)
- •10.17.4. Событие выгрузки клипа (onUnload)
- •10.17.5. Событие поступления данных (onData)
- •10.17.6. События мыши (onMouseDown, onMouseUp, onMouseMove)
- •10.17.7. События клавиатуры (onKeyDown, onKeyUp)
- •10.17.8. «Кнопочные» события
- •10.17.9. События фокуса (onSetFocus, onKillFocus)
- •10.18. Программное рисование
- •10.18.1. Рисование прямыми отрезками
- •10.18.2. Рисование фрагментами парабол
- •10.18.3. Однородная заливка
- •10.18.4. Градиентная заливка
- •10.18.5. Удаление программной графики
- •10.19. Управление цветом клипов. Класс Color
- •10.19.1. Цветовые модели
- •10.19.2. Задание формулы цвета
- •10.19.3. Задание цвета клипа. Метод setRGB()
- •10.19.4. Цветовые трансформации. Метод setTransform()
- •Проект 10: Рисование 3D-объектов
- •Глава 11. Кнопки
- •11.1. Создание кнопок
- •11.2. Сходства и различия кнопок и клипов
- •11.3. События кнопок
- •11.3.1. Особенности событий кнопок
- •11.3.2. События кнопок в стиле Flash 5
- •11.4. Режим элемента меню
- •11.5. Вид указателя мыши
- •11.6. Отключение кнопок
- •11.7. Управление кнопками при помощи клавиатуры
- •11.7.1. Динамическое наведение фокуса
- •11.7.2. Свойство _focusrect
- •11.7.3. События onSetFocus и onKillFocus
- •11.7.4. Задание маршрута клавиатурного обхода
- •11.7.5. Особенности клавиатурного обхода и программного фокуса в случае клипов
- •11.8. Клипы как кнопки
- •Проект 11: Факел
- •Глава 12. Работа с мышью и клавиатурой
- •12.1. Работа с мышью
- •12.1.1. Определение координат указателя мыши
- •12.1.2. События мыши
- •12.1.3. Скрытие указателя мыши
- •12.1.4. Правая клавиша мыши
- •12.1.5. Определение выхода указателя мыши за пределы окна плейера
- •12.2. Контекстное меню
- •12.2.1. Настройка контекстного меню. Класс ContextMenu
- •12.2.2. Введение в контекстное меню собственных команд
- •12.3. Работа с клавиатурой
- •12.3.1. Особенности событий клавиатуры
- •12.3.2. События onKeyDown и onKeyUp
- •12.3.3. Определение кода нажатой клавиши. Метод getCode()
- •12.3.4. Определение кода введенного символа. Метод getAscii()
- •12.3.5. Проверка нажатия клавиши. Метод isDown()
- •12.3.6. Проверка активности специальных режимов. Метод isToggled()
- •Проект 12: Эластики
- •Глава 13. Работа с текстом
- •13.1. Создание текстовых полей
- •13.1.1. Создание текстовых полей при помощи инструмента Text
- •13.1.2. Переменная поля
- •13.1.3. Динамическое создание текстовых полей
- •13.2. Удаление текстовых полей
- •13.3. Текстовые поля как визуальные объекты
- •13.4. Задание и извлечение текста поля
- •13.5. Настройка текстового поля
- •13.5.1. Управление размером поля
- •13.5.2. Рамка и задний фон
- •13.5.3. Поля однострочные и многострочные
- •13.5.4. Ограничение на количество символов
- •13.5.5. Поле паролей
- •13.5.6. Ограничение на вводимые символы
- •13.5.7. Выделение текста поля
- •13.6. Настройка стиля текста. Класс TextFormat
- •13.6.1. Задание гарнитуры
- •13.6.2. Размер шрифта
- •13.6.3. Цвет шрифта
- •13.6.4. Начертание шрифта
- •13.6.5. Выключка
- •13.6.6. Подчеркнутый шрифт
- •13.6.7. Гиперссылки
- •13.6.8. Форматирование текста
- •13.6.9. Определение размерных параметров текста
- •13.7. Работа со шрифтами
- •13.7.1. Шрифты системные и встроенные
- •13.7.2. Ненаправленные гарнитуры
- •13.7.3. Особенности встраивания шрифтов
- •13.7.4. Встраивание в фильм целого шрифта
- •13.7.5. Встраивание глифов отдельных символов и последовательностей символов
- •13.7.6. Проблема читабельности при отображении мелкого текста
- •13.8. Событие onChanged
- •13.9. Прокрутка текстовых полей
- •13.10. Работа с фокусом
- •13.11. Форматирование текста при помощи HTML
- •13.11.5. Тег <FONT> ... </FONT>
- •13.11.10. Тег <TEXTFORMAT> ... <TEXTFORMAT>
- •13.11.11. Тег <SPAN> ... </SPAN>
- •13.11.13. Автоматическое удаление пробелов. Свойство condenseWhite
- •13.12. Форматирование текста с использованием каскадных таблиц стиля (CSS)
- •13.12.1. Основные положения технологии CSS
- •13.12.2. Создание объекта таблиц стиля
- •13.12.3. Применение объекта стиля к текстовому полю
- •13.12.4. Элементы CSS, поддерживаемые Flash-плейером
- •13.13. Работа с выделением. Объект Selection
- •13.13.1. Управление фокусом поля. Методы getFocus() и setFocus()
- •13.13.2. Событие изменения фокуса (onSetFocus)
- •13.13.4. Определение и задание положения курсора ввода
- •13.13.5. Динамическое задание выделения. Метод setSelection()
- •13.13.6. Динамическая замена выделенного текста. Метод replaceSel()
- •13.14. Работа со статичным текстом. Объект TextSnapshot
- •13.14.1. Создание объектов класса TextSnapshot
- •13.14.2. Считывание текста статичных полей
- •13.14.3. Поиск строки в статичном тексте
- •13.14.4. Программное выделение статичного текста
- •13.14.5. Определение ближайшего к точке символа статичного текста
- •13.15. Копирование текста в буфер обмена
- •13.16. Поддержка многоязычности. Панель Strings
- •Проект 13: Текстовые эффекты
- •Глава 14. Время и дата
- •14.1. Основные понятия теории измерения времени
- •14.2. Компьютерное время
- •14.3. Класс Date
- •14.3.1. Создание объектов класса Date
- •14.3.2. Методы класса Date
- •14.4. Определение времени, прошедшего с начала проигрывания фильма
- •Проект 14: Программные часы
- •Глава 15. Работа со звуком
- •15.1. Основные понятия теории цифрового звука
- •15.1.1. Частота дискретизации
- •15.1.2. Разрядность выборок
- •15.1.3. Количество каналов
- •15.1.4. Алгоритмы компрессии
- •15.1.5. Форматы хранения
- •15.2. Событийный (event) и потоковый (stream) звук
- •15.3. Операции со звуком без использования программирования
- •15.4. Создание объектов класса Sound
- •15.5. Динамическое присоединение звука. Метод attachSound()
- •15.6. Импортирование внешних МР3-файлов
- •15.6.1. Метод loadSound()
- •15.6.2. Отслеживание окончания загрузки. Событие onLoad
- •15.6.3. Создание предзагрузчиков для импортируемых звуков
- •15.7. Управление воспроизведением звуков
- •15.7.1. Запуск воспроизведения. Метод start()
- •15.7.3. Событие onSoundComplete
- •15.8. Свойства position и duration
- •15.9. Управление параметрами воспроизведения
- •15.9.1. Громкость звука
- •15.9.2. Баланс
- •15.9.3. Детальное управление стереозвучанием. Метод setTransform()
- •15.10. Чтение ID3-тегов МР3-звуков
- •Проект 15: МР3-плейер
- •Глава 16. Взаимодействие с локальным окружением
- •16.1. Взаимодействие с импортированными фильмами
- •16.2. Взаимодействие с плейером
- •16.2.1. Определение версии и типа плейера
- •16.2.2. Режимы масштабирования
- •16.2.3. Типы выравнивания
- •16.2.4. Определение размеров фильма и величины окна плейера
- •16.2.5. Событие onResize
- •16.2.6. Цвет фона
- •16.2.7. Качество отображения
- •16.2.8. Панель небезопасных настроек плейера
- •16.3. Дополнительные возможности автономного плейера
- •16.3.1. Проекторы
- •16.3.2. Функция fscommandf()
- •16.4. Взаимодействие между фильмами, проигрываемыми разными плейерами
- •16.4.1. Создание кода отправки данных
- •16.4.2. Создание кода получения данных
- •16.4.3. Пример использования класса LocalConnection
- •16.5. Взаимодействие с браузером
- •16.5.1. Теги <EMBED> и <OBJECT>
- •16.5.2. Передача данных из HTML-окружения при загрузке фильма
- •16.5.3. Решение проблемы кнопок навигации браузера
- •16.5.4. Передача команд браузеру. Функция getURL()
- •16.5.5. Взаимодействие с JavaScript при помощи функции fscommand()
- •16.5.6. Управление SWF-фильмом посредством JavaScript
- •16.5.7. Определение наличия в системе Flash-плейера нужной версии
- •16.6. Взаимодействие со средой разработки
- •16.6.1. Настройка панели Actions
- •16.6.2. Объект CustomActions
- •16.6.3. Взаимодействие с JSFL
- •16.7. Взаимодействие со средствами чтения с экрана
- •16.8. Получение информации об использующемся аппаратном и программном обеспечении
- •16.9. Сохранение данных на диске
- •16.9.1. Создание объектов SharedObject
- •16.9.2. Чтение данных из объектов SharedObject
- •16.9.3. Удаление sol-файлов
- •16.9.4. Серверные объекты SharedObject
- •16.9.5. Решение проблемы выделения цветом посещенных ссылок
- •16.10. Взаимодействие с принтером
- •16.10.1. Функции печати
- •16.10.2. Класс PrintJob
- •Проект 16: Создаем свой инструмент
- •Глава 17. Обмен текстовыми данными с сервером
- •17.1. Принципы сетевой безопасности Flash MX 2004
- •17.1.1. Правила определения идентичности доменов
- •17.1.2. Требование идентичности протоколов
- •17.1.3. Снятие ограничений на доступ к содержимому фильма
- •17.1.4. Снятие ограничений на доступ к внешним данным
- •17.1.5. Преодоление ограничений для сокетов
- •17.1.6. Создание приложений, отвечающих принципам безопасности
- •17.2. Загрузка текстовых данных с сервера
- •17.2.1. Создание файла сданными
- •17.2.2. Функция loadVariables()
- •17.2.3. Класс LoadVars
- •17.3. Взаимодействие с серверным скриптом
- •17.3.1. Запрос с выводом результата в браузере
- •17.3.2. Запрос с отправкой результата в фильм
- •17.3.3. Задание заголовков запроса
- •17.4. Работа с сокетами
- •17.4.1. Класс XMLSocket
- •17.4.2. Создание сокета-сервера
- •17.5. Работа с XML
- •17.5.1. Введение в ХМL
- •17.5.2. Объектная модель XML. DOM
- •17.5.3. Преобразование XML-текста в дерево объектов DOM
- •17.5.4. Обход дерева DOM
- •17.5.5. Создание и модификация XML-документа
- •17.5.6. Обмен XML-данными с сервером
- •Проект 17: Создаем сетевую игру
- •Дополнительные главы
- •Глава 18. Обмен с сервером сложными данными
- •Глава 19. Компоненты
- •Глава 20. Полезные мелочи
этого физически в памяти содержатся уже два аналогичных и абсолютно не связанных значения — индивидуальное для каждой переменной.
var a: String = "Привет"; var b: String = а;
а += "!!!"; // Изменяем а: если переменная b является ссылкой на тот же
trace(а); |
// объект, изменится и ее значение |
// Выводит: Привет!!! |
|
trace(b); |
// Выводит: Привет (Следствие: b ссылается на иной объект |
|
// данных, чем а) |
Копирование объекта данных элементарного типа при присвоении одной переменной другой оправданно, так как иначе было бы весьма проблематично написать даже очень простой алгоритм — слишком сильно были бы «завязаны» величины друг на друге. Совершенно иная ситуация наблюдается, если присваиваемая переменная хранит значение составного типа. В этом случае не происходит копирования объекта данных, а новой переменной передается только ссылка на него. Это означает, что любые изменения, произошедшие в объекте данных посредством доступа через одну переменную, отразятся на значении, возвращаемом второй переменной:
var a:Object = {property:1}; // Переменная хранит объект со свойством
// property=1
var b:Object = а;
//Меняем свойство property: если а и b ссылаются на один объект данных, то
//b возвратит новое значение
a.property=2;
trace(b.property); // Выводит: 2 (объект данных был изменен)
Можно долго спорить, чего больше — хорошего или плохого — в особенностях присвоения переменной с составным значением. В передаче ссылки, а не копировании самого объекта данных имеются свои положительные и отрицательные стороны. Так, описанная тонкость зачастую ставит в тупик начинающих кодеров, которые часами не могут найти причины внезапного сбоя алгоритма. Однако нужно признать, что копирование по ссылке неизбежно — иначе нехватка оперативной памяти станет основной проблемой Flash-плейера.
«А что делать, — спросите вы, — если переменной необходимо передать именно индивидуальный объект данных?» Решений этой задачи можно найти много, в зависимости от типа объекта данных. В наиболее общем случае можно создать собственный класс и использовать затем его функциюконструктор. Если объектом данных является массив, то на помощь может прийти функция split(). Размножить клип можно, применив методы attachMovie() или duplicateMovieClip(). В общем, трудности, вызываемые особенностями операции присваивания для переменной с составным значением, легко решаемы.
3.6. Есть ли переменные в ActionScript?
Между понятиями «свойство» и «переменная» нет заметной разницы. И первое, и второе обозначают именованный контейнер для хранения данных — и на уровне реализации языка трудно найти различие между ними. Свойство является структурным элементом объекта, а переменная существует сама по себе — вот и вся разница. Однако в ActionScript стирается даже это отличие между свойствами и переменными. Так, размещая код на кадре основной временной шкалы, мы можем создать переменную с использованием ключевого слова var. Но если нам необходимо прочитать значение этой переменной из вложенного на _root клипа, то обратиться к ней мы должны как к свойству, применив оператор «.» или «[]». Переменные остаются переменными только в рамках «родной» временной шкалы. Вне ее они уже свойства определенного объекта класса MovieClip. To же самое можно сказать про локальные переменные функций: их вполне можно считать свойствами ее объекта активации (и, как будет показано в главе 4, они таковыми и являются).
Учитывая сказанное выше, правильнее было бы назвать эту главу не «Переменные», а «Свойства». Впрочем, практически все, что было изложено ранее, в равной степени справедливо как для переменных, так и для свойств. Например, присваивание свойству другого свойства с составным зна-
чением будет означать передачу ссылки на объект данных, а не его копирование.
Расположение кода на кадрах клипов делает сценарии фильмов Flash чрезвычайно гибкими. Однако это вносит и значительную путаницу во многие вопросы языка. Например, нужно ли использовать var, если переменная клипа создается удаленно? Ответ; нет, так как при этом она рассматривается как свойство. Нужно ли ключевое слово var, если объявляется глобальная переменная? Ответ: нет, так как она есть просто свойство объекта Global. Вообще оператор точки и var не совместимы: такое сочетание вызывает ошибку.
var _root.myVar=0; // Ошибка: переменная не может быть свойством
ВЕСМА-262 с каждым исполнимым кодом связана особая служебная структура, называемая объектом переменных (variable object). Свойства этого объекта имеют такие же имена, как и определенные в коде переменные и функции. Значениями же этих свойств являются объекты данных, с которыми при помощи операции присваивания связываются соответствующие переменные. При необходимости получить доступ к некоторой переменной считывается значение созданного на основании ее определения свойства объекта переменных. Понятие «объект переменных» вводится для того, чтобы стала возможной инкапсуляция исполнимого кода и реализация концепции цепочек областей видимости.
ВActionScript роль объекта переменных основного кода выполняет клип, на кадре которого код расположен. С одной стороны, это хорошо, так как способствует упрощению языка. Например, чтобы обратиться к какому-то свойству или методу клипа из кода, расположенного на нем, совсем не обязательно использовать имя клипа, Достаточно набрать просто имя свойства:
trace(_х); |
// |
Выводит: |
0 |
trace(_root._x) // |
Выводит: |
0 |
С другой стороны, создание на основании определения переменной свойства клипа означает, что различия между понятиями «переменная» и «свойство» нивелируются. Интересные особенности возникают при обращении к свойству клипа из расположенного на нем кода. Так, если мы попытаемся получить к нему доступ, не используя имя клипа и оператор точки, а набрав только имя, то на его наличие будет просмотрена связанная с исполнимым кодом цепочка областей видимости. Это означает, что в данном случае идентификатор рассматривается как имя переменной. Если же к свойству мы пытаемся обратиться, используя имя клипа и оператор точки, то просматривается связанная с клипом цепочка прототипов (идентификатор интерпретируется как свойство). Так как три звена (сам клип, прототип конструктора MovieClip, прототип конструктора Object) у цепочки наследования клипа и цепочки областей видимости расположенного на нем кода совпадают, то в подавляющем большинстве случаев не возникает никаких различий от того, как происходит обращение к свойству клипа или переменной кода. Однако если переменная является глобальной, то обратиться к ней как к свойству клипа невозможно. Это связано с тем, что объект Global имеется в любой цепочке областей видимости, однако в цепочку наследования клипов он не входит:
_global.per="Привет"; // |
Создаем глобальную переменную |
|
trace(per); |
// |
Выводит: Привет (per воспринимается как переменная) |
trace(_root.per); |
// |
Выводит: undefined (per воспринимается как свойство) |
Из-за того, что переменные и функции одновременно являются свойствами и методами клипаносителя кода, путаются понятия цепочки областей видимости и цепочки прототипов. Формально в цепочку областей видимости кода, расположенного на кадре клипа, входят сам клип и объект Global. Но из-за того, что при обращении к свойству клипа на его наличие просматриваются еще и прототипы конструкторов MovieClip и Object, количество объектов, фактически входящих в цепочку областей видимости, увеличивается до четырех. Конечно, между свойствами, получаемыми из цепочки наследования клипа, и «настоящими» переменными, принадлежащими к полноценным объектам цепочки областей видимости исполнимого кода, имеются определенные отличия. Так, наследуемое свойство клипа переопределено не может быть, а собственное свойство клипа — с легкостью. Однако в подавляющем большинстве случаев свойства, принадлежащие к прототипам
конструкторов MovieClip и Object, и свойства самого клипа и объекта Global ведут себя при обращении из кода к идентификатору абсолютно идентично. Поэтому для простоты мы будем считать, что цепочка областей видимости кода клипа выглядит следующим образом: сам клип, прототип конструктора MovieClip, прототип конструктора Object, объект Global. На самом же деле, как вы уже знаете, структура цепочки областей видимости кода клипа куда проще. Ее видимое удлинение возникает из-за того, что при обращении к свойству клипа на его наличие проверяется также характерная для него цепочка прототипов.
Если бы для кода, расположенного на кадре клипа, создавался специальный объект переменных, а не использовался с этой целью сам клип, то понятия «переменная» и «свойство» было бы легко различить, и не возникало бы такой путаницы с цепочками областей видимости и цепочками прототипов. Будем надеяться, что в следующих версиях Flash ситуация в этом отношении изменится. Имеется только одно серьезное отличие между переменными и свойствами. Переменную можно строго типизировать, а свойство — нет. Впрочем, эта особенность существует лишь до компиляции. В транслированном коде обнаружить различие между свойством клипа и переменной расположенного на нем кода невозможно.
Проанализировав приведенные факты, мы можем сделать следующее заключение: в ActionScript в принципе нет переменных, а есть переменные-свойства. Такой странный симбиоз возник из-за применения не слишком удачной концепции языка программирования. Согласитесь, что не так много общего между браузером и программой векторной анимации, чтобы использовать для них один стандарт скриптового языка (а ЕСМА-262 — это стандарт именно Web-скриптов). Пожалуй, определенной стройности ActionScript можно было бы добиться, отказавшись от жесткой привязки сценариев к временной шкале — но это радикально усложнит кодирование, поэтому разработчики вряд ли на это пойдут (но первый шаг разработчиками к этому уже сделан — в область видимости кода методов внешних классов входят только объект, вызвавший метод, и объект Global).
Автор этой книги считает запутанность понятий переменная-свойство одним из главных недостатков ActionScript. При всем желании невозможно описать эту головоломку какой-то стройной схемой. Да и лучше этого не делать — вывод, к которому вы придете, приведен в предыдущем абзаце. Действуйте интуитивно — это самый верный подход во многих вопросах программирования во Flash.
3.7. Удаление переменных
Удалить переменную можно, используя оператор delete:
var new_var:Number=3; delete new_var;
trace(new_var); // Выводит: undefined (переменная удалена)
В том случае, если операция удаления произошла успешно, оператор delete возвращает true. Если же переданный идентификатор изначально не указывал на определенный объект данных, то результат — false:
var new_var=3;
trace(delete new_var); // Выводит: true
trace(delete new_var); // Выводит: false (переменной new_var больше не
// существует)
Свои особенности имеет удаление объектов данных составного типа. Так, если вы используете в качестве операнда delete переменную, значением которой является объект или клип, то произойдет удаление указателя, связывающего переменную и объект данных, а не самого объекта данных. Любой объект типа object будет существовать в памяти до тех пор, пока на него имеется хотя бы одна ссылка. Чтобы удалить его, нужно использовать оператор delete по отношению ко всем указывающим на него переменным. Только в этом случае при ближайшей чистке памяти данный объект будет выгружен как мусор. Чтобы удалить клип, нужно использовать метод removeMovieClip()
— применение же по отношению к его идентификатору оператора delete не даст никакого результата.
Любая переменная и любое свойство могут быть защищены от удаления. Как это сделать, мы обсуждали в предыдущей главе в разделе, посвященном атрибутам свойств.
Проект 3: Пружинный маятник
Эта глава — одна из самых маленьких в книге. Поэтому и третий наш проект будет относительно несложным, Мы создадим модель пружинного маятника.
Пружинный маятник — это простая физическая система, представляющая собой груз на прикрепленной к опоре пружине, Если немного оттянуть груз (выведя тем самым систему из равновесия), а затем отпустить, то маятник начнет совершать колебания. В идеальном случае полного отсутствия трения колебательное движение будет гармоническим, т. е. будет происходить неограниченно продолжительное время с постоянной амплитудой, В реальных системах трение всегда присутствует, поэтому колебания пружинного маятника происходят с затуханием.
Подробно описывать физику движения пружинного маятника мы не будем — данный вопрос лежит вне специфики этой книги. Воспользуемся уже готовой формулой, определяющей абсолютное смещение груза в зависимости от времени:
Y = Ay cos((k / m)12 t +ϕ0 ) e−αt .
Сложная формула? Совсем нет! Вы без труда в ней разберетесь, прочитав описание входящих в нее величин:
•Y – величина абсолютного удлинения пружины в момент времени t. Периодически изменяется в интервале от 0 до Ау.
•Ау — амплитуда колебаний, т. е. максимальное удлинение пружины, Если скорость груза при начале движения равна 0, то амплитуда соответствует удлинению пружины в этот момент.
•m — масса груза. Чем она больше, тем более плавными будут колебания (т. е. частота колебательного движения будет ниже),
•к — жесткость пружины. Чем она больше, тем более резкими будут колебания (т. е. их частота будет выше).
•t — время от начала колебательного движения.
•ϕ0 — смещение фазы. Возникает, если в начальный момент времени скорость груза не равна нулю. В нашей модели эта величина не понадобится.
•а — коэффициент, учитывающий вклад трения. Чем он больше, тем быстрее затухают колебания.
Вы можете сказать: «Мы хотим научиться программировать на ActionScript, а нам читают лекции по физике! Нельзя ли без формул?» Увы — нет. Математика — единственный язык, на котором можно описывать явления вокруг нас. Любая игра, эффект или даже анимация — это прежде всего математическая модель. Уверенное владение основами математики хотя бы за курс средней школы просто необходимо тому, кто хочет проявить себя на поприще Flash-программирования. В этой книге мы будем создавать много моделей, в которых будет активно использоваться королева наук
— и вы увидите, какой это мощный инструмент (в умелых руках, разумеется).
Не будем утомлять вас длинными теоретическими выкладками и приступим-таки к реализации задуманного проекта.
С чего бы начать? Разумно будет вначале создать пружинный маятник в «железе» и лишь затем приступать к написанию кода (иначе мы просто не сможем его тестировать).
В том, чтобы нарисовать груз или опору, нет никакой сложности. А вот как изобразить пружину? Рисовать несколько часов одно кольцо за другим? Слишком сложно. Тем более, что звенья пружины вряд ли при всем старании получатся одинаковыми, отчего она будет казаться грубой, а сам

маятник — не особо похожим на оригинал. Мы поступим по-другому. Нарисовав фрагмент, соответствующий одному шагу спирали, мы создадим нужное число его копий (10-20). Совмещая затем участки пружины, получим необходимое изображение с минимальными усилиями. Несколько советов:
•Чтобы нарисовать элемент пружины, создайте эллипс, а затем, разрезав его кольцо при помощи ластика, просто сместите один конец кривой вверх, а другой — вниз (рис. 3.1, а).
•Работайте в увеличенном масштабе (300-500 %) — при этом проще совмещать концы фрагментов пружины.
•Соединив 4—5 фрагментов, в дальнейшем используйте полученный элемент для сборки пружины — это значительно ускорит выполнение поставленной задачи.
•Чтобы создать копию фрагмента, выделите его и выполните протаскивание мышью при нажатой клавише <Ctrl>.
•Когда нужное число витков будет соединено, немного удлините свободные концы пружины — за один из них она будет прикреплена к основе, к другому будет присоединен груз. Затем трансформируйте пружину (инструмент Free Transform) так, чтобы она выглядела сжатой (рис. 3.1, b). Переведите изображение пружины в клип (<F8>).
Рис. 3.1. Заготовка для пружины (а) и пружина (b)
Жестко закрепленная пружина удлиняется относительно точки крепления. По умолчанию же центр клипа, относительно которого система просчитывает все трансформации, располагается ровно посередине его графической доставляющей. Это означает, что если мы попытаемся растянуть программно пружину, то она удлинится на одинаковую величину в обе стороны. Нам же необходимо, чтобы деформация осуществлялась только в одном направлении. Чтобы этого добиться, зайдите в режим редактирования клипа (выполнив двойной щелчок по нему) и переместите изображение пружины так, чтобы ее верхний конец в точности совпал с точкой отсчета системы координат (ей соответствует черный крестик на рабочем поле). Выполнив описанную операцию, немного поэкспериментируйте, растягивая пружину. Если в состоянии деформации она будет похожа на свой реальный прототип, то продолжайте работу. В противном случае попробуйте внести в свое творение изменения или просто воспользуйтесь готовым объектом из архива примеров.
|
Теперь необходимо нарисовать груз. Как он будет выглядеть — |
|
это решать только вашей фантазии. Наиболее очевидный вариант |
|
— небольшой металлический цилиндр (рис. 3.2). Нарисовав гру- |
|
зик, переведите его в клип. |
|
Третьим необходимым элементом пружинного маятника является |
|
подвес. Чтобы не тратить много времени, изобразите его просто |
|
как узкий и длинный прямоугольник. Сохранить его необходимо |
|
как символ типа graph. |
Рис. 3.2. Пружинный маятник |
Собираем маятник из созданных компонентов. У вас должно по- |
лучиться приблизительно то же, что и на рис. 3.2. |
Итак, работа руками завершена. Пришло время для работы головой — приступаем к созданию кода.
Для начала даем клипам с изображением пружины и груза идентификаторы. Первый называем pruzina, второй — gruz.
Создаем новый слой и, назвав его «Код», размешаем выше существующего. Выделяем его первый кадр и нажимаем <F9>. При этом открывается наш основной холст — панель Actions, заставляя задуматься: с чего бы лучше начать?
Начинать всегда надо с задания переменных. Конечно, трудно сейчас предполагать, какие служебные переменные нам понадобятся в будущем. Однако четыре из них вполне очевидны: это параметры самого маятника, входящие в приведенную выше формулу:
var k:Number = 1000; |
// |
Жесткость пружины |
var n:Number = 200; |
// |
Масса груза |
var alpha:Number = 0.1; // |
Коэффициент трения |
|
var A:Number = null; |
// |
Амплитуда (она будет задана при смещении груза) |
Присвоенные значения взяты навскидку: при тестировании модели мы их заменим более подходящими. Пока трудно предполагать, чему должна равняться каждая переменная — хотя бы потому, что смещение мы будем измерять не в метрах, а в пикселях.
Выводить колебательную систему из равновесия пользователь будет самостоятельно, оттягивая указателем мыши грузик на нужное расстояние вниз. Чтобы обеспечить соответствующие трансформации, нам необходимо как-то регистрировать событие нажатия кнопки мыши в тот момент, когда курсор располагается над клипом gruz. Сделать это можно несколькими способами, самый простой из которых связан с использованием «кнопочного» события onPress (во Flash MX клипы стали листенерами таких событий):
gruz.onPress=function():Void { trace (this);
}
Войдите в режим тестирования. Если после «щелчка» по грузу откроется панель Output со строкой «_level0.gruz», то, удалив функцию trace(), продолжайте выполнение проекта. Иначе — ищите ошибку.
О том, что пользователь начал протаскивание грузика, должны узнать остальные Функцииобработчики сценария. Для этого при наступлении события onPress клипа gruz будем устанавливать булев флаг в специальной переменной:
gruz_press=true; // Эта переменная должна быть создана там же, где и // остальные, со значением false
После того как произойдет щелчок курсором по грузу, он должен начать перемешаться вслед за курсором мыши. Причем смещение должно происходить только По вертикали и в определенных пределах (пружина не может растягиваться и сжиматься до бесконечности). Справиться с этой задачей очень просто, воспользовавшись мощным методом класса MovieClip startDrag (center, xmin, ymin, xmax, ymax), где:
•center — параметр, определяющий, перемешается ли клип относительно той точки, в которой находился указатель мыши в момент активации метода (false), или же точка его центра и указатель жестко связываются (true). Очевидно, что нам скорее подходит первый режим;
•xmin, ymin, xmax, ymax — точки, задающие границу области перемещения клипа.
Определяем граничные точки следующим образом:
•xmin. Смещения по горизонтали происходить не должно, поэтому задаем левую границу области, равную текущей координате X клипа: this._x.
•ymin. Груз не должен подниматься выше того положения, когда маятник находится в равновесии. Конечно, это отклонение от физической модели пружинного маятника, в которой насколько пружина растягивается, настолько она потом и сжимается. Однако будем считать, что пружина у нас достаточно жесткая и полностью сжата. А это означает, что при колебаниях ее длина никогда не будет заметно меньшей, чем в состоянии покоя.
Положение груза при равновесии фиксируем в специальной переменной (она должна быть задана вместе с остальными):
var gruz_pos :Number=gruZ._y;
•xmax. Задаем аналогично xmin.
•ymax. Даже самая пластичная пружина не может растянуться более, чем в 3—4 раза от ее начальной длины. Поэтому нижний предел смещения груза стоит ограничить 3 значениями ширины клипа pruzina, отсчитанными от его положения в состоянии равновесия. Так как ширина пружины будет непрерывно меняться, то необходимо зафиксировать ее начальную величину, создав для этого отдельную переменную:
var pruz_height:Nυ =pruzina._height;
Строку с методом startDrag() заносим в тело единственной пока функции-обработчика:
gruz.startDrag(false,this._x, gruz_pos, this,_x, 3*pruz_height+gruz_pos);
При отпускании кнопки мыши протаскивание груза должно быть закончено. «Отловить» соответствующее событие можно несколькими способами. Во-первых, можно воспользоваться встроенным «кнопочным» событием onRelease. Однако при этом не будет фиксироваться отпускание кнопки мыши в том случае, если указатель находится не над клипом. Чтобы предусмотреть такую ситуацию, придется использовать специальный обработчик onReleaseOutside. Два обработчика для одного события — это слишком много. Мы поступим по-другому: «отлавливая» событие отпускания кнопки мыши при помощи обработчика onMouseUp, будем проверять, чему равняется переменная graz_press. Если она равна true, значит, груз протаскивался. При этом необходимо остановить работу метода startDragO (для чего используем метод stopDragO), а также указать в переменной gruz_press, что перемещения клипа gruz больше не происходит. В виде ActionScript описанные действия материализуются как:
_root.onMouseUp = function():Void { if(gruz_press) {
gru2_press = false; gruz.StopDrag();
}
};
Тестируем фильм и проверяем, все ли работает так, как задумано. Если да, то продолжаем выполнение проекта.
Раз груз жестко закреплен на пружине, то при его смещении она должна растягиваться. Этот процесс должен быть непрерывным, поэтому реализующий деформацию код следует вызывать достаточно часто. Для этого можно или создать функцию-обработчик события onEnterFrame, или воспользоваться таймером setInterval(). Мы, ввиду простоты, применим первый вариант:
_root,onEnterFrame = function():Void { };
При вызове созданного обработчика будем проверять, чему равна переменная gruz_press. Если ей соответствует true, значит, груз протаскивается. При этом пружина должна быть удлинена на-
столько, насколько он сместился относительно своего начального положения:
pruzina._height = pruz_height+gruz._y-gruz_pos;
Тестируем фильм и пробуем перемешать грузик. Вроде бы все неплохо... Хотя по какой-то неизвестной причине при деформации пружины изменяется не только ее длина, но и ширина. Так как свойство _width у нас в коде нигде не фигурирует, ошибку в сценарии можно сразу исключить. Дело тут в другом.
Возникшие трудности связаны с тем, что мы сместили точку отсчета системы координат клипа. А обойти их предельно просто: для этого каждый раз, меняя длину пружины, будем устанавливать изначальное значение ее ширины. С этой целью создадим специальную переменную:
var pruz_width:Number = pruzina._width;
Ниже выражения, определяющего длину пружины, в теле обработчика onEnterFrame наберите следующую строку:
pruzina._width = pruz_width;
Тестируем фильм. Вот теперь действительно все работает так, как надо!
В том случае, если переменная pruz_press равна false (груз был отпущен), по событию onEnterFrame будем запускать механизм, реализующий колебания маятника. Для его создания переведем на язык ActionScript рассмотренную в начале описания проекта формулу:
else { // Math.abs — метод, вычисляющий абсолютную величину числа pruzina._height = pruz_height + Math.abs(A*Math.cos (Math.sqrt (k/m)*time) *Math.exp (-alpha*time));
pruzina._width = pruz_width;
gruz._y = gruz_pos+Math.abs (A*Math.cos (Math.sqrt(k/m)*time) *Math.exp(-alpha*time));
}
Проанализировав приведенные выражения, вы обнаружите, что они несколько отличаются от формулы колебаний маятника, которая была предложена изначально. Внесенные изменения связаны с тем, что пружина нашего маятника деформируется относительно исходного состояния только в одном направлении. Поэтому отрицательных величин смешения быть не может, и мы работаем с модулями вычисленных значений. Кстати, модель от этого не становится физически не адекватной: приблизительно так ведут себя маятники с достаточно жесткими пружинами и небольшим грузом.
В заданных формулах используются величины, которые мы еще не описали:
•Амплитуда А. Должна быть вычислена в момент отпускания груза как разность между его положением и координатой точки равновесия:
А = gruz._y-gruz_pos; // Строку добавляем в тело обработчика события onMouseUp
•Время time. Должно быть определено равным 0, там же, где и амплитуда. Явно переменную time надо задать вместе с остальными, присвоив значение null. Менять значение времени мы будем сразу же после вычисления текущего значения смешения:
time+=l/12; // Заносим выражение в блок предложения else обработчика
// onEnterFrame
Более точно время колебаний можно измерять, воспользовавшись возможностями класса Date или глобальной функцией getTimer(). Однако не будем забегать вперед.
Чтобы вычисления колебаний маятника не происходили до того, как он будет выведен из равновесия, соответствующие выражения будем выполнять лишь в том случае, если time отлична от null:
if(time!=null) {
}
Модель готова. Остался последний штрих. Мы должны предоставить пользователю удобный интерфейс, при помощи которого можно будет менять значения параметров. Для этого создадим три поля ввода и, подписав их «Масса», «Жесткость», «Трение», свяжем (поле Var) с переменными m, k, alpha. Теперь любое изменение текста в полях будет сопровождаться переопределением переменных, что позволит быстро проверить работу модели при самом различном сочетании значений параметров.
Если при тестировании созданный вами фильм не будет работать, то найти ошибку вы сможете, сравнив его с авторским проектом, который сохранен в папке ПроектЗ архива проектов.