Работа с мышью

Объект Mouse появился еще во Flash 5. Тогда выполняемые им функции были чрезвычайно скромны и ограничивались только управлением отображения указателя мыши при помощи методов hide() и show(). Во Flash MX, в связи с внедрением новой модели событий, объект Mouse стал генератором трех чрезвычайно важных для практики событий — on Mouse Move, on MouseDown nonMouseUp. В связи с этим его полезность возросла многократно. Во Flash MX 2004 у него появилось новое событие onMouseWheel, возникающее при прокрутке колеса мыши.

Определение координат указателя мыши
Координаты точки, в которой располагается указатель мыши, можно узнать, используя свойства _xmouse (положение по оси X) и _ymouse (координата по оси Y). В качестве примера применения данных свойств приведем код, заставляющий шарик вращаться вокруг указателя:

// Создаем клип в виде шарика и называем его ball
var R:Number = 30, STEP:Number = 0.5; // Переменные, определяющие радиус и
// скорость вращения шарика
_root.onEnterFrame = function():Void { // Каждый кадр поворачиваем шарик
// на угол step
// Центр вращения динамичен и определяется положением указателя
ball._x = _xmouse+R*Math.cos(phi);
ball._y = _ymouse+R*Math.sin(phi);

Свойства _xmouse и _ymouse доступны только для чтения: изменить расположение указателя, переопределив их, невозможно.

Важно учитывать, что _xmouse и _ymouse определяют положение указателя мыши в системе координат того клипа или кнопки, в качестве свойств которого они вызываются.


Это означает, что если необходимо сместить клип в точку расположения указателя, то нужно использовать значения координат, возвращенные свойствами _xmouse и _ymousc содержащего его клипа. Или же можно просто пересчитать глобальные координаты в локальные, используя метод localToGlobal().

Свойства _xmouse и _ymouse применимы и к текстовым полям. Как это ни странно, но они также имеют систему координат. Ее центр располагается в левом верхнем углу поля, а оси имеют такое же направление и размерность, как в случае клипов и кнопок. Кстати, благодаря этому текстовым полям присуши свойства, выполняющие трансформацию системы координат.

Если указатель мыши располагается не над окном плейера, свойства _xmouse и _ymouse равны не undefined, как было бы логично предположить. Они хранят координаты той точки, в которой указатель был зарегистрирован в последний раз. Причем данная точка совсем не обязательно будет находиться на границе фильма. Потенциально она может располагаться за десятки пикселей от точки, в которой указатель пересек границу — все зависит оттого, как быстро он перемещался.

Это, например, означает, что нельзя установить факт выхода курсора за окно плейера, используя только свойства _xmouse и _ymouse.

Если при выходе указателя за пределы фильма левая кнопка мыши была нажата, то его координаты продолжат отслеживаться до тех пор, пока она не будет отпущена.


Так, если ширина фильма равна 550 пикселей, а вы уведете указатель на 200 пикселей вправо от его правой границы, то значение свойства _xmouse будет равняться 750 пикселей. Данная особенность может быть полезна, если вы хотите реализовать эффект, основанный на протаскивании клипа за границу фильма.

События мыши
Во Flash 5 события были присущи только клипам и кнопкам. Среди событий, доступных обработчикам onClipEvent(event), имелись и непосредственно связанные с мышью — mouseDown, mouseUp, mouseMove. Они позволяли реагировать на нажатие и отпускание левой клавиши мыши, а также давали возможность обнаруживать движение ее указателя. Во Flash MX генератором этих событий формально стал объект Mouse. Однако клипы полностью сохранили свою восприимчивость к событиям мыши (в отличие от событий клавиатуры). Поэтому вполне можно считать, что клипы по умолчанию являются листенерами объекта Mouse (правда, им недоступно событие onMouseWheel):

_root.onMouseDown = function():Void{ // Данный код работоспособен изначально
trace{"Кнопка мыши нажата!")
}

Если необходимо, чтобы листенером «мышиного» события был не клип, а, например, объект класса Object, то он должен быть явно зарегистрирован в качестве такового при помощи метода addListener():

var obj:Object = {};
Mouse.addListener (obj);
obj.onMouseDown = function():Void { // Изначально только клипы "слушают"
// события мыши
trace("Кнопка мыши нажата!");
};

Удалить объект из списка листенеров можно, используя метод removeMovieClip().


Особенностью всех событий объекта Mouse является то, что они происходят лишь в том случае, если указатель мыши располагается в границах окна Flash-плейера. Если же вывести его за пределы фильма, то нажатие левой кнопки мыши не будет сопровождаться событием onMouseDown, ее отпускание — onMouseUp, а ее движение — событием onMouseMove. Это достаточно существенная проблема, особенно при разработке игр.

События onMouseDown и onMouseUp
Событие onMouseDown возникает при нажатии левой (но не правой) клавиши мыши. Соответственно событие onMouseUp происходит при ее отпускании.

События onMouseDown и onMouseUp — это основные инструменты, обеспечивающие интерактивность в ActionScript. Достойную конкуренцию им составляют лишь события кнопок. Так, если нужно определить факт щелчка по определенному клипу, то применение события onPress более технично, чем сочетание события onMouseDown и метода hit Test (), Во Flash 5 подобное применение «кнопочных» событий было сильно ограничено тем, что при наведении указателя на кнопку его форма менялась на вид руки. Однако во Flash MX это перестало быть проблемой благодаря наличию свойства useHandCursor.

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


Однако если левая кнопка мыши была нажата за границами плейера, а отпущена над ним, то события onMouseUp не будет.

Событие onMouseMove
Событие onMouseMove возникает при движении указателя мыши. Так как оно характеризует непрерывный процесс, происходить оно может с чрезвычайно высокой частотой — 100 и более вызовов обработчика в секунду. Однако на практике такая частота наблюдается не очень часто. Дело в том, что новое событие onMouseMove не наступает до тех пор, пока полностью не будет проделан код всех его обработчиков в фильме, активированных в результате предыдущего события, Поэтому реакция на движение мыши может быть недопустимо запоздалой и излишне дискретной.

Чтобы этого не происходило, не создавайте обработчики onMouseMove для очень большого числа клипов и старайтесь не помещать в них код, требующий объемных вычислений. Следовать этим советам стоит и потому, что событие onMouseMove требует весьма заметных процессорных ресурсов.

Как мы уже отмечали выше, события мыши не происходят, если ее указатель располагается вне границ плейера. Однако если зажать правую клавишу мыши и вывести указатель за границы фильма, то событие onMouseMove будет возникать до тех пор, пока она не будет отпущена.

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

Обычно событие onMouseMove используется, если изменение положения указателя мыши может привести к каким-то переменам в фильме.


В качестве примера приведем код, позволяющий рисо вать в окне плейера:

// При нажатии левой кнопки мыши начинаем рисовать линию
_root.onMouseDown = function():Void {
this.lineStyle(2, 0xFF0000); // Задаем стиль линии
this.moveTo(this._xmouse, this._ymousel; // Определяем начало линии
this.draw = true; // Флар, показывающий, рисуется ли линия
};
_root.onMouseMove = function():Void { // Рисуем линию по траектории
// движения мыши
if (this.draw) { // Если флаг установлен, проводим отрезок в точку
// нахождения курсора
this.lineTo(this,_xmouse, this._ymouse);
}
};
_root.onMouseUp = function():Void { // При отпускании кнопки мыши прекращаем
// рисование
this.draw = false;
};

Данный код позволяет рисовать достаточно гладкие линии, но лишь в том случае, если указатель мыши движется не очень быстро. Иначе линии получаются ломаными. Причина этого — недостаточная частота возникновения события onMouseMove. Обойти данную проблему можно, приближая траекторию не прямыми отрезками, а фрагментами парабол (как вы помните, их рисует метод curveTo()).

Событие onMouseWheel
Событие onMouseWheel возникает при прокрутке колеса мыши. Оно характерно только для Flash-плейера под Windows (у компьютеров Macintosh попросту нет на мыши колеса). Появилось событие onMouseWheel только во Flash MX 2004, До этого в ActionScript не имелось абсолютно никаких инструментов для работы с колесом мыши. Это был большой недостаток Flash, так как невозможно было создавать элементы управления (полосы прокрутки, меню), которые бы могли управляться колесом мыши, полностью имитируя аналогичные элементы Windows-приложений. Самым же серьезным неудобством было то, что текстовые поля нельзя было прокручивать при помощи колеса мыши. Все эти недостатки были исправлены в новой версии Flash.

Функции-обработчику события onMouseWheel передается два параметра:

• delta — показывает, на сколько строк прокрутится текстовое поле, если оно располагается в фокусе. Величина одного шага зависит от установок операционной системы и скорости вращения колеса — и изменить ее средствами ActionScript невозможно. Обычно delta постоянна и равняемся по модулю 1, 2 или 3. Однако если вы повернете колесико очень резко, то значение delta может быть в два или даже три раза больше обычного. То, в какую сторону было повернуто колесо, показывает знак delta. Если вращение происходит вверх, то ее величина отрицательна, если вниз — положительна;

• object — хранит ссылку на клип или текстовое поле, над которым располагался указатель мыши в момент возникновения события. Если под указателем было несколько объектов, в object записывается ссылка на верхний из них. Нахождение указателя над кнопкой не регистрируется. Если указатель располагался над пустым экраном, то параметру object будет соответствовать undefined.

Для примера приведем код, перемещающий клип или текстовое поле, над которым располагается указатель мыши, при вращении ее колеса по вертикали на величину 5 delta ⋅ пикселей:

// Создайте несколько клипов и текстовых полей
Mouse.addListener(_root);
_root.onMouseWheel = function(delta:Number, object:MovieClip):Void {
object._y+=delta*5;
};

Событие onMouseWheel регистрируется лишь в том случае, если окно плейера находится в фокусе.

Скрытие указателя мыши
Довольно часто на практике бывает необходимо отключать отображение указателя мыши. Решается эта задача при помощи метода hide() объекта Mouse. Возвратить же затем указатель на рабочее поле можно, используя метод show().

Например:
_root.onMouseDown = function():Void { // При нажатии кнопки мыши указатель
// исчезнет
Mouse.hide();
};
_root.onMouseUp = function():Void { // При отпускании кнопки мыши
// указатель появится вновь
Mouse.show();
};

Отключение отображения указателя совсем не означает, что перестанет отслеживаться его перемещение или нажатие кнопки мыши. Свойства _xmouse и _ymouse и «мышиные» события при этом будут работать как ни в чем не бывало.

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

Метод hide() отключает отображение указателя в стандартной форме стрелки и в форме руки. Однако текстовый курсор остается видимым. Это означает, что при наведении указателя на текстовое поле курсор в форме буквы I появится в любом случае. Это нужно учитывать, если в фильме применяется пользовательский указатель.

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

// Рисуем небольшую стрелку (20-25 пикселей} и помещаем над ней
// динамическое текстовое поле, назвав его coord. Затем переводим это
// сочетание в клип и называем его cursor.
cursor.swapDepths(100000); // Размещаем клип-указатель выше всех
// остальных объектов
Mouse.hide(); // Прячем стандартный курсор
cursor.coord.eelectable^false; // Делаем поле невыделяемым (иначе появится
// текстовый курсор)
cursor.onMouseMove = function():Void {
// Обновляем значение координат
this.coord.text=Math.round(_xmouse} + ", " + Math.round(_ymouse);
// Перемещаем клип-указатель в новое положение
this._x=_xmouse, this._y=_ymouse;
updateAfterEvent(); // Обновляем экран
};

Главная сложность в использовании пользовательских курсоров связана с потенциальным выходом указателя за пределы окна плейера. При этом появится стандартный указатель, а изображавший его в фильме клип продолжит отображаться на границе плейера. На экране появятся сразу два указателя, один из которых будет неработоспособен. Чтобы этого избежать, в момент пересечения указателем границы фильма пользовательский указатель должен быть сделан невидимым.

Потенциально сложности может вызвать и то, что текстовый курсор не скрывается методом hide(), Если в фильме присутствуют только динамические текстовые поля, то блокировать его появление над ними очень просто. Для этого нужно сделать их невыделяемыми при помощи свойства selectable. Если же применяются поля ввода, То их нужно поместить в кнопки и отслеживать для них событие onRollOver. При его возникновении пользовательский указатель нужно скрыть. При выходе курсора за пределы поля (ему соответствует событие onRollOut) отображение пользовательского указателя должно быть восстановлено.

Правая клавиша мыши
Официально в ActionScript до выхода последней версии Flash не существовало элемента, используя который можно было бы среагировать на нажатие правой клавиши мыши. Однако решить эту задачу все же было реально, если знать, что кнопки мыши во многом являются такими же клавишами, как клавиши клавиатуры. Нет, это не значит, что при нажатии правой кнопки мыши возникнет событие on KeyPress объекта Key. Подобная особенность не может быть реализована, так как она была бы чревата многочисленными сбоями. Метод getCode(), возвращающий номер задействованной последней клавиши, также не способен регистрировать факт нажатия кнопок мыши. А вот метод isDown(), определяющий, нажата ли клавиша с определенным номером, применим и к клавишам мыши. В этом несложно убедиться, зная, что левой кнопке мыши соответствует код 1, а правой — 2:

// Наберите этот код и "пощелкайте" клавишами мыши
this.onEnCerFrame = function():Void {
if (Key.isDown(1)) {
trace("Левая клавиша мыши нажата");
} else if (Key.isDown(2)) {
trace("Правая клавиша мыши нажата");
}
};

Используя данную особенность метода isDown(), совсем несложно создать код, генерирующий событие щелчка правой кнопки мыши. Описание того, как это сделать, используя методы недокументированного объекта AsBroadcaster.

Хотя самостоятельно реализовать событие правого щелчка совсем несложно, на практике данное событие использовалось крайне редко. Причина тому — контекстное меню, которое появляется над окном плейера. Трудно представить, какие функции должна выполнять правая клавиша мыши, чтобы оно не было помехой. В частности, из-за него невозможно создать собственное контекстное меню, подобно тому, как создаются пользовательские курсоры (однако ввести собственные элементы в стандартное меню во Flash 7 стало возможно — см. раздел 12.2). А это очень и очень большой недостаток, мешающий качественной разработке интерфейсов.

Полностью убрать контекстное меню плейера невозможно. Можно лишь минимизировать его до двух строчек — Settings (настройки опций плейера) и About Macromedia Flash Player (краткая информация о плейере). Минимизация контекстного меню — это очень полезная возможность. Однако она не делает событие правого щелчка более доступным.

Во Flash MX 2004 появился класс ContextMenu, отвечающий за работу с контекстным меню плейера. Его единственное событие onSelect происходит при появлении контекстного меню. Следовательно, оно может быть использовано для отслеживания нажатия правой клавиши мыши:

// При щелчке правой клавишей мыши в Output будет выведено сообщение
var myMenu:ContextMenu = new ContextMenu();
myMenu.onSelect = function():Void {
trace("Правая кнопка мыши нажата!");
};
_root.menu = myMenu;

Можно быть уверенным, что в ближайших версиях Flash Macromedia не откажется от обязательного отображения контекстного меню. Почему? Все дело в строчке «About Macromedia Flash Player».

Подумайте, какая это замечательная реклама. В сети имеются миллионы и миллионы баннеров, мультфильмов и сайтов, изготовленных при помощи Flash. Пользователь, видя что-то впечатляющее, с весьма высокой вероятностью захочет получить дополнительную информацию, щелкнув правой клавишей мыши. При этом появится контекстное меню, и он узнает, что это чудо сделано с использованием Flash. Очевидно, что многие разработчики захотят освоить данную программу, а заказчики — получить такой же сайт или презентацию. Вообще, многие специалисты считают, что значительной доле своей известности Flash обязан именно контекстному меню плейера.

Что же делать, если вы хотите написать игру, в которой просто необходимо использовать правую кнопку мыши? На данный момент есть только один путь решения этой задачи — применить нестандартный плейер. Такие плейеры объединяют с фильмом некоторые утилиты, позволяющие создавать на базе swf-файла исполнимые (*.ехе) файлы. Подобных утилит довольно много, и они весьма значительно отличаются как по своей стоимости, так и по возможностям. В данный момент наиболее распространены следующие: Flash Studio Pro, Swiff Canvas, Jugglor, Flash Tuner.

Приведенные утилиты позволяют отключать отображение контекстного меню. Некоторые это делают простой блокировкой сообщений о нажатии правой клавиши мыши. Другие же, более мощные, убирают непосредственно меню, сохраняя возможность создания события правого щелчка.

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

Определение выхода указателя мыши за пределы окна плейера
В полноэкранном режиме swf-фильмы проигрываются редко, и это создает определенные сложности, связанные с выходом указателя мыши за пределы окна плейера. Наиболее очевидный пример — применение пользовательского курсора. При выходе указателя мыши за границы фильма системный курсор визуализируется. Клип же, изображавший в фильме указатель, продолжит отображаться в точке, в которой мышь пересекла границу окна плейера. Естественно, что подобная ситуация совершенно недопустима. Каким-то образом необходимо регистрировать момент выхода указателя мыши за пределы фильма, чтобы скрывать при этом пользовательский курсор. При возвращении указателя в границы окна плейера отображение пользовательского курсора должно быть восстановлено.

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

Если в вашем фильме нет полей ввода и вы можете обойтись без применения кнопок и «кнопочных» событий, то наиболее оптимальным представляется следующий подход:

• Рисуем полностью прозрачный клип в виде прямоугольника, по размерам совпадающего с полем фильма.

• Созданный клип помещаем на основную временную диаграмму выше всех остальных объектов. Располагаем его так, чтобы он закрывал все поле.

• Выходу указателя мыши за пределы окна плейера будет соответствовать событие onRollOut созданного клипа, его возвращению — событие onRollOver. Если необходимо учитывать выход или возвращение указателя при нажатой левой клавише мыши, то нужно использовать события onDragOut и onDragOver.

• Чтобы указатель мыши не менял форму со стрелки на очертания руки, используем свойство
useHandCursor.

Используя возможности программного рисования и метод broadcastMessage() недокументированного объекта AsBroadcaster (см. главу 8), можно создать, применив описанный алгоритм, собственные события, возникающие при выходе указателя за границы окна фильма и возвращении его в них:

// Объект, который будет генерировать задуманные события
_global.borderWatcher={};
// Регистрируем borderWatcher как генератор событий
AsBroadcaster.initialize (borderWatcher);
borderWatcher.init = function():Void {
// Создаем пустой клип на очень большой глубине основной временной диаграммы
var clipMovieClip = _root.createEmptyMovieClip("list clip" +
Math.random), 100000);
// Обводку и заливку задаем полностью прозрачными
clip.lineStyle(1, 0, 0);
clip.beginFill(0, 0);
// Рисуем в клипе clip прямоугольник по контуру границ фильма
clip.moveTo(0, 0);
var xMax:Number = Stage.width, yMax:Number = Stage.height;
clip.lineTo(0, yMax), clip.lineTo(xMax, yMax), clip.lineTo(xMax, 0),
clip.lineTo(0);
clip.endFill();
clip.useHandCursor = false; // Отключаем отображение указателя-"руки"
// При выходе указателя за пределы клипа clip всем листенерам объекта
// borderWatcher отправляем сообщение о событии onStageRollOut
clip.onRollOut = function():Void {
borderWatcher.broadcastMessage("onStageRollOut");
};
// При появлении указателя в границах клипа clip сообщаем о событии
// onStageRollOver
clip.onRollOver = function():Void {
borderWatcher.broadcastMessage("onStageRollOver");
};
};
// Активируем генерацию событий onStageRollOut и onStageRoIlOver
borderWatcher.init();
//*********************************************************
// Создаем динамическое текстовое поле и называем его info
// Делаем info листенером событий объекта Stage
borderWatcher.addListener(info);
// В зависимости от события выводим в поле info необходимое сообщение
info.onStageRollOut = function():Void {
this.text = "Указатель вышел за границы фильма";
};
info.onStageRollOver = function():Void {
this.text = "Указатель вошел в границы фильма";
};

Приведенный код работает очень стабильно. Однако его применение сильно ограничено тем, что в фильме не должно быть полей ввода и кнопок. Если данное условие соблюдено быть не может, то нужно использовать следующий алгоритм:

• Рисуем прозрачный клип, контуры которого совпадают с границами фильма.

• При помощи метода swapDepths() помешаем клип на самую маленькую из доступных глубин:
—16384-ю. Данная глубина является зарезервированной, и по умолчанию она всегда свободна.

• Отслеживаем для клипа события onRollOul и onRollOver, соответствующие выходу указателя за границы фильма и возвращению его в них. При необходимости учесть возможность движения указателя при нажатой левой клавише мыши применяем события onDragOver и onDragOul

• Если одно из событий происходит, проверяем, чему равны значения свойств _xmouse и _ymouse. Если определяемая ими точка располагается достаточно близко к границе, с большой степенью точности можно утверждать, что произошло ее пересечение. В противном случае указатель просто вошел в область одного из клипов, кнопок или текстовых полей, имеющихся в фильме.

Данный алгоритм куда менее точен, чем описанный ранее. Так, факт пересечения указателем границы может быть не зарегистрирован, если он двигался слишком быстро или если линия границы фильма в точке пересечения проходит по клипу, кнопке или текстовому полю. Однако этот алгоритм не имеет жестких ограничений на используемые в фильме объекты. Какой из подходов стоит применить, определяется особенностями создаваемого проекта.

Оцените статью: (0 голосов)
0 5 0

Статьи из раздела Action Script на эту тему:
Контекстное меню
Определение кода введенного символа. Метод getAscii()
Проверка активности специальных режимов. Метод isToggled()
Проверка нажатия клавиши. Метод isDown()
Работа с клавиатурой