Нативные курсоры. Делаем!

3

В этой записи решил рассказать о нативных курсорах на Flash платформе. О их преимуществах и собственно как их реализовать.

Часто стал замечал, что во многих играх разработчики используют свои курсоры. Особенно если игра не может обойтись обычным системным курсором (различные квесты, hiden objects и другие игры где нужно менять состояние курсора для большей интуитивности в игре). Это безусловно можно отнести к плюсам конечной игры. Но, то что мне не нравится в таком подходе, так это подтормаживание тех самых курсоров. Возможно через 10 минут игры об этом и забывается, но поначалу приходят только негативные эмоции, т.к. кажется, что игра работает не на максимуме FPS.

Также в играх, где пользователю приходится что-то быстро нажимать и на что-то быстро реагировать мышкой, геймплей начинает казаться слегка замедленным, будто желе двигаешь, а не мышь:) Этот неприятный эффект мы и попытаемся устранить.


Это как?
Всего есть 2 способа заменить системный белый курсор своим:

  1. Мы создаем MovieClip, добавляем событие MOUSE_MOVE (которое возникает при движении мыши) и дальше просто присваиваем координаты нашему курсору
    Mouse.hide(); //Прячем системный курсор
    
    myCursor = new MyCursor(); // Создаем свой
    addChild(myCursor);
    
    addEventListener(MouseEvent.MOUSE_MOVE, mouseMove); // Добавляем слушатель события
    
    private function mouseMove(e:MouseEvent):void {
            myCursor.x = e.stageX; // Задаем x нашему курсору
            myCursor.y = e.stageY; // Задаем y нашему курсору
            e.updateAfterEvent(); // Дополнительно делаем обновление
    }
    //И хоть мы дополнительно вызываем метод updateAfterEvent(), 100% скорости курсора этим способом не добиться.
  2. Второй способ намного лучше первого. С его помощью можно добиться идеальной скорости курсора. Функционал для данного метода добавлен уже в 10.2 версии флешплеера, но как и писал выше не многие им пользуются. Этот способ мы и будем реализовывать. Идем дальше.



Наглядный пример

Я думаю тут сразу можно заметить преимущества нативного курсора 
над курсором реализованным способом MOUSE_MOVE.



Как сделать?
Способ прост. Создается объект MouseCursorData, в его свойство data передается Vector из BitmapData. Одна BitmapData – 1 кадр. Если она единственная в векторе, то курсор будет статичным. После курсор надо всего лишь зарегистрировать.

Но вам не придется в этом копаться. Как это бывает, когда в процессе игры наткнешься на то, что нужно доработать/оптимизировать, то через пару дней всё таки напишешь класс, чтобы всё это удобно использовать. Вот я и написал несколько классов и поделюсь ими, возможно они кому-то облегчат работу с нативными курсорами.


Как использовать?

addCursor(MyCursor, "MY_CURSOR");
  • MyCursor – класс нашего курсора. Его не надо создавать, просто передавать ссылку например из вашего .swc или же ссылку на embed класс.
  • «MY_CURSOR» – имя нашего курсора. Может быть любым. В дальнейшем оно служит для переключения курсоров (если их больше одного).
changeCursor("MY_CURSOR"); //Включает указанный курсор.


И вот наконец минимальный код который нужен для того чтобы добавить и включить наш курсор.

import com.remindgames.ui.RemindCursors;

_cursorsNative = new RemindCursors(); // Создаем класс для работы с нативными курсорами
_cursorsNative.addCursor(UI_CursorNative, "MY_CURSOR"); // Добавляем наш курсор и даем ему имя
_cursorsNative.changeCursor("MY_CURSOR"); // Включаем курсор
// Всё!:) Курсор уже работает




Дополнительно
Дабы еще удобней это всё использовать, добавил в этот мини-фреймворк пару нужных вещей.

removeCursor($name:String); //Удаляет курсор по заданному имени

removeCursorAt($id:int); //Удаляет курсор по заданному индексу

removeAllCursors(); //Удаляет все ранее добавленные курсоры

currentCursorName //Имя текущего курсора

numCursors //Текущее кол-во добавленных курсоров

И напоследок:

setButtonCursor($mainCursorName:String, $buttonCursorName: String,
                   $stage:Stage, $buttonCursorClass: Class = null);
Задает курсор для кнопок
  • $mainCursorName – имя основного курсора
  • $buttonCursorName – имя курсора, который будет использоваться при наведении на кнопки
  • $stage ссылка на наш stage
  • $buttonCursorClass – класс кнопок. Если не задан, то будет SimpleButton
resetButtonCursor(); //Чтобы сбросить настройки для кнопок


Пример использования setButtonCursor();




Исходники RemindCursors
Для использования поместите папку ‘com’ в ваш проект
Надеюсь это облегчит работу с курсорами. Удачи!
  • +13

Комментарии (10)

0
Поумничаю:
1. Честно говоря, не сталкивался с проблемой «торможения» кастомного курсора. Хотя проблему встречал в вопросах на разных форумах. Она, как обычно «в голове». Возникакет из-за непонимания механизмов работы плеера: она будет в любом случае, т.к. завязана на ФПС мувика. Ну не сможете вы физически рендерить в мувике с пфс около 30 (обычно, а дефолтно вроде 15 стоит вообще) свою картинку курсора с такой-же частотой как и нативный, который с частотой обновления экрана рендерится (50...100+ фпс). Т.е. эту проблему решить радикально можно только нативным кодом плеера.
2. Дефолтный курсор тоже можно менять комбинацией флагов у спрайта buttonMode и useHandCursor — ленивый метод такой…
Но чтобы быть честным, собственный класс нормального кастомного курсора с двумя состояними занимает у меня больше, чем приведенные в начале 9 строк. Но работает норм и при контекстном меню и при выходах за мувик и прочих замеченных «тонкостях» (вот кстати на флешке-примере можно попробовать с контекстным меню в зоне ненативного кастомного курсора… и еще там кастомный не пропадает при выходе за мувик...).
Сложности — написал 1 раз и используй везде. Но когда за тебя уже все написали, еще и правильно, то оно конечно же лучше. Хотя автор все-же «написал несколько классов» даже и для такого случая :)
В любом случае — автору спасибо за пост и исходники.
0
А это только у меня нативный курсор мерцает? А то всю статью прочитал вроде бы про данный эффект не слова нету.
0
Chrome, Firefox полёт нормальный.
Оперу и ИЕ не проверял.
0
в моем случае мерцает на Firefox, OSX 10.8.5
0
Сначала тоже не обратил внимания, присмотрелся — действительно красный курсор мерцает. OSX 10.9.2. В Firefox, Chrome и Safari проявляется одинаково.
0
Проверьте плз демку по этой ссылке speedart.3dn.ru/remindgames/1.html
0
Симптомы ухудшились, мигает значительно чаще с периодическими подвисаниями анимации.
0
Хм…
А теперь? (по той же ссылке)
0
Теперь мерцает реже, но иногда есть.
0
Спасибо. Разобрался в чём может быть проблема.

OS X:
Если в теге embed-флеша прописано:
wmode: «opaque» либо wmode: «transparent», то начинается конфликт с курсором.
Соответственно опции window, direct и gpu работают более стабильно.

Windows:
Chrome, FireFox — работает без проблем с любым тегом.

Opera:
wmode: «opaque» — мерцает курсор.
wmode: «transparent» — мерцает курсор.
wmode: «window» — идеально
wmode: «direct» — идеально
wmode: «gpu» — идеально

Слава богу на порталах не используются «opaque» и «transparent». При том очень малая доля людей с Mac'ами играют в флеш. Поэтому думаю можно использовать и не обращать внимания на редкие глюки у небольшого процента аудитории.
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.