Колізії кліпів
Використовуючи метод hitTest(), можна вирішити дві задачі, що мають виняткову важливість для практики: перевірити, чи не перетинаються два кліпи, і визначити, чи входить точка з певними координатами в кліп. Оскільки ці завдання досить різнопланові, розглянемо їх окремо.
Визначення перетину двох кліпівЩоб визначити, чи перетинаються два кліпи, метод hitTest() необхідно задіяти в наступній формі:
тут clip1 та clip2 — кліпи, перевірку колізії яких потрібно провести.
Як результат метод hitTest() повертає булеву величину true, якщо кліпи мають спільні точки, і false, якщо вони не перекриваються.
В ідеалі факт перетину двох кліпів слід вважати таким, що відбулося, якщо у них є хоча б по одній заповненій точці, які мають однакові глобальні координати. На жаль, перевірити колізію з такою точністю можна далеко не завжди. Для цього довелося б послідовно перебрати значну кількість точок, що неприпустимо з позиції виконання коду. Тому метод hitTest() порівнює не положення заповнених точок двох кліпів, а лише їх граничні координати (отримати які можна, використовуючи метод getBounds()).
Це означає, що факт колізії буде підтверджений не тоді, коли об'єкти внутрішньої структури двох кліпів дійсно перекривають один одного, а тоді, коли перетинаються області, обмежені описаними навколо них прямокутними рамками. Визначення колізій об'єктів довільної форми - ця одна з найскладніших і, на жаль, поки що до кінця не вирішених завдань програмування у Flash. Не існує універсального способу, використовуючи який можна було б з точністю до однієї точки встановити факт перекривання двох кліпів. Єлише окремі випадки, у яких колізію можна визначити досить надійно і безпосередньо не використовуючи метод hilTest().
По-перше, подібна можливість є для фігур, які можуть бути описані за допомогою математичних формул (кола, еліпси) або задані крапково (наприклад, трикутники або ромби). При цьому визначення колізії зведеться до розв'язання елементарних систем рівнянь чи порівняння положень вузлових точок.
По-друге, підвищити точність визначення колізій фігур округлої форми можна, ввівши їм умовний радіус (простіше кажучи, вважаючи їх колами). При цьому перевірка перетину двох кліпів зведеться до визначення відстані між їхніми центрами: якщо вона виявиться меншою за суму умовних радіусів, то колізію слід визнати такою, що відбулася.
По-третє, підвищити точність визначення факту перетину досить великого кліпу складної форми з іншим кліпом можна в такий спосіб.
По контуру кліпу розташувати маленькі невидимі кліпи-датчики. При необхідності встановити колізію потрібно просто перевірити, чи повертає метод hitTest() для кожного з датчиків. Якщо виявиться, що один із них перетинається з відповідним кліпом, то факт колізії має бути підтверджений. Ефективність описаного підходу безпосередньо визначається кількістю кліпів-датчиків. Однак навіть досить велике їх число не дозволяє дізнатися, чи перекриваються два кліпи з точністю до пікселя. Втім, на практиці кліпи-датчики використовуються набагато частіше, ніж поточковий перебір, тому що вони дають цілком задовільну точність визначення колізій при невеликому обсязі необхідної обчислювальної роботи.
По-четверте, якщо кліпи, факт колізії яких потрібно встановити, мають середні чи невеликі розміри, можна просто порівняти їх поточечно.
Визначення приналежності точки до кліпуЩоб перевірити, чи належить точка з деякими координатами кліпу, потрібно використовувати метод hitTest() у такій формі:
clip.hitTest(х, у, shapeFlag), де:
• x та y — координати точки. Повинні бути задані у системі координат основної часової діаграми.
Якщо відома позиція точки лише виходячи з локальної системи координат кліпу, то перетворити відповідні координати на глобальні можна, скориставшись методом localToGlobaI();
• shapeFlag —булева величина, що задає, чи вважатиметься точка, що належить кліпу, якщо вона дійсно заповнена (true) або якщо вона просто входить в область, обмежену описаною навколо об'єктів кліпу прямокутною рамкою (false).
Якщо приналежність точки до кліпу підтверджується, метод hitTest() повертає true. Інакше результат – false.
Як приклад наведемо код, який робить кліп протягується, якщо по ньому було зроблено клацання:
this.onMouseDown = function():Void if (mov.hitTest(_root._xmouse, _root. _ymouse, true)) mov.startDrag(true); > >;
Зверніть увагу, як було визначено позицію, що займається на момент клацання курсором миші.
Для цього ми використовували спеціальні властивості _xmouse та _ymouse. Так як метод hitTest() вимагає завдання координат точки щодо системи координат основної часової діаграми, дані властивості повинні бути задіяні як властивості _root. Треба визнати, що факт приналежності точки до кліпу метод hitTest() визначає набагато якісніше, ніж наявність загальних точок у двох кліпів. Так, він дозволяє дізнатися, чи дійсно точка відповідає об'єкту внутрішньої структури кліпу, а не тільки, чи входить вона в область, обмеженуописаним навколо нього прямокутником. Найчастіше розглянута форма методу hitTest() використовується для визначення того, чи не розташовувався деякий кліп під покажчиком миші в момент натискання її лівої клавіші. Починаючи з Flash MX, впоратися з подібним завданням можна і простіше завдяки тому, що кліпи стали листенерами «кнопкових» подій. «Відловити» подію клацання по кліпу можна, використовуючи обробник onPress. Так, наведений вище приклад при цьому перепишеться так:
mov.onPress = function():Void this.startDrag(true); >;
Єдиним недоліком використання «кнопкових» подій є те, що при наведенні на кліп курсору він набуває форми руки. Щоб цього не відбувалося, потрібно набрати наступний рядок:
Визначення колізії кліпів з використанням поточкового переборуЯк було продемонстровано вище, метод hitTest() абсолютно неефективний, якщо необхідно визначити наявність перекриття між кліпами, форма яких далека від прямокутної. Однак без інструмента, що дозволяє з точністю до декількох пікселів реєструвати наявність колізії між кліпами складної форми, неможливо створення якісних ігор та багатьох ефектів. У цьому підрозділі ми покажемо, як можна створити такий інструмент, використовуючи кілька простих ідей та базові засоби ActionScript.
Що такий кліп? Для спостерігача це лише безліч точок на моніторі. Що таке колізія кліпів? Це коли два кліпи мають точки з однаковими координатами. А якщо просто послідовно порівняти всі точки кліпів — виявляться такі, що мають подібне розташування, значить, кліпи перетинаються.
Як крапково просканувати кліп, ми придумали. Але як можна порівняти два масиви з образами кліпів на предмет відповідності елементів,якщо вони можуть мати різні розміри та абсолютно несупадні точки відліку? А оминути цю проблему дуже просто. Для цього "скануватися" обидва кліпи повинні виходячи з прямокутника меж меншого з них (це дозволить мінімізувати час розрахунку). Якщо кліпи не перетинаються, то не виявиться жодного пікселя, який би виявився заповнений щодо їх обох. Якщо виявиться хоча б один квадратик, точка центру якого належить обом кліпам, то факт колізії можна вважати доведеним. Реалізується описана ідея наступним кодом: