Опубликован: 07.11.2006 | Уровень: специалист | Доступ: свободно
Лекция 8:

Обнаружение коллизий

Математическое обнаружение коллизий

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

Что мы на самом деле ищем при проверке на коллизию? Коллизия - это столкновение или соприкосновение двух объектов.

Пусть у нас есть объект в определенном месте. Если другой объект находится в том же самом месте, тогда между ними происходит коллизия. Предположим, имеется стена, расположение которой _x=500. Если координата _x другого объекта больше 500, то он должен быть в состоянии столкновения со стеной, так? Да, поскольку мы решили, что у стены бесконечная высота, так как мы не проверяем значение _y. Самое замечательное заключается в том, что нам даже не нужно создавать стену. Мы просто говорим, что она там есть, посредством указания значений ее позиции. Самый простой способ - установить константу в начале фильма, к примеру right=500 ;. Давайте рассмотрим этот случай и попробуем с ним поработать.

Живой шарик

  1. Откройте новый фильм. Находясь в нем, установите левую стенку, реализуя ее в функции init. Переименуйте слой по умолчанию actions и введите следующий код.
    init();
     function init () Х
      right = 500;
      left = 50;
     }
  2. Теперь нужно реализовать некоторую коллизию с участием стенок. Начнем с простого шарика. Нарисуйте шарик, преобразуйте его в фильм с именем ball и дайте его инстансу имя ball_mc.
  3. Далее нужно обеспечить движение шарика. До этого мы использовали термин speed. Здесь мы поступим несколько более точно с технической точки зрения и используем velocity. Velocity - это скорость в определенном направлении. Мы ограничим возможные направления правой и левой сторонами, поэтому нашей скоростью Velocity будет либо +speed, либо -speed. Мы назовем ее velX, в виде сокращения от "Velocity по оси x". Добавим нужный код в init.
    init ();
     function init() {
      right = 500;
      left = 50;
      ball_mc. velX = 5;
     }
  4. Для функции реализации движения шарика используем управляющий элемент onEnterFrame. Присвоим функцию управления в секции init и после этого создадим функцию move. Добавьте следующий код в имеющуюся программу.
    init ();
      function init()  {
      right = 500;
      left = 50;
      ball_mc.velX = 5;
      ball_mc.onEnterFrame = move;
     }
     function move() {
      this._x += this.velX;
     }

    Здесь берется скорость velocity и прибавляется к позиции _x. Так как velX = 5, эта функция прибавляет 5 к позиции _x шарика в каждом кадре. Запустив этот фильм, вы увидите, что шарик переместится вправо и исчезнет. Итак, сейчас мы займемся обнаружением столкновений с использованием стенки.

  5. Вспомните нашу прежнюю проверке коллизий с точкой: контур всегда больше той точки, в которой он находится. При проверке удара объекта о стенку нужно учитывать толщину объекта. Предположим, что шарик имеет диаметр 20 пикселей. Это означает, что край шарика находится в 10 пикселях от центра (если шарик имеет центральную точку регистрации). Мы можем принимать это в расчет при проверке позиции шарика относительно стенки. Код будет выглядеть примерно так.
    if (this._x>right-(this._width/2)) {
      // then we have a hit
     }

    Мы добавим этот код в функцию move сразу после того, как настроим позицию шарика.

    Берем параметр _width фильма ball и делим его на два. Это даст расстояние от центра круга до его края (т.е. радиус). Имейте в виду, что это будет работать только в случае с объектами, у которых имеется центральная точка регистрации, и которые отцентрированы по оси x.


  6. Ударившись о стенку, шарик отскакивает. В нашем случае он двигается строго перпендикулярно к поверхности, поэтому после удара просто будет двигаться в обратном направлении. Другими словами, если до столкновения его скорость равна +5, после столкновения она будет равна -5. Вместо реализации скорости -5 мы просто будем умножать любую скорость на -1. Давайте добавим эту функциональность в наш код в функции move.
    function move() {
      this._x += this.velX;
      if (this._x>right-(this._width/2)) {
       this.velX *= -1;
      }
     }
  7. Теперь можном немного изменить этот код, чтобы создать аналогичное выражение if для проверки столкновения между шариком и левой стенкой. Добавьте следующий новый код в функцию move.
    if (this._x<left+(this._width/2)) {
      this.velX *= -1;
      }
  8. Вот весь код, который мы имеем на данный момент.
    init();
      function init() {
      right = 500;
      left = 50;
      ball_mc.velX = 5;
      ball_mc.onEnterFrame = move;
      }
      function move() {
      this._x += this.velX;
      if (this._x>right-(this._width/2)) {
        this.velX *= -1;
      }
      if (this._x<left+(this._width/2)) {
        this.velX *= -1;
      }
      }
  9. Вы можете нарисовать линии на позициях 50 и 500 по оси x, чтобы видеть, что именно происходит. Помните, что эти линии являются лишь графическими элементами, которые не взаимодействуют с кодом и действием в фильме. Проверка коллизий - процесс сугубо математический.

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

    Если вы не видите этого, уменьшите либо частоту кадров фильма, либо значение скорости. Когда вы бросаете мяч в направлении стены, он ведь не проникает в нее, а просто отскакивает! (Имеется в виду обычный человек, бросающий в стену обычный теннисный мячик, а не Арнольд Шварценеггер, кидающий железное ядро). Сейчас мы постараемся решить эту проблему.

  11. Мы видим, что при ударе о стенку шарик немного проникает внутрь стены. Это показано на рисунке выше. Вручную переместим шарик так, чтобы он лишь касался края стены. Внесите следующие изменения в функцию move (функция init остается прежней)
    function move() {
        this._x += this.velX;
        if (this._x>right-(this._width/2)) {
          this.velX *= -1;
          this, x = right-(this, width/2);
        }
        if (this._x<left+(this._width/2)) {
          this.velX *= -1;
          this._x = left+(this._width/2);
        }
      }
  12. Если вы запустите фильм сейчас, шарик немного войдет в стенку, будет зарегистрировано столкновение, и шарик переместится к краю стенки. Но, так как Flash не обновляет экран, пока не выполнится весь код, мы на самом деле никогда не увидим, как шарик проникнет в стенку, а будем наблюдать лишь касание. Итак, одна из "странных" особенностей функционирования Flash была использована на наше же благо!
  13. Теперь я совершу "квантовый скачок" и добавлю в фильм совершенно новое измерение. Я продублирую строки, содержащие _x или velX с использованием _y и velY, а также добавлю новые переменные с именами top и bottom. Также _width будет заменено на _height. Нарисуйте еще две линии вверху и внизу рабочего места на позициях (x,50) и (x, 350) для отображения стенок. Следующий код не представляет проблем.
    init();
      function init() {
        right = 500;
        left = 50;
        top = 50;
        bottom = 350;
        ball_mc.velX = 5;
        ball_mc.velY = 5;
        ball_mc.onEnterFrame = move;
      }
      function move() {
        this._x += this.velX;
        this._y += this.velY;
        if (this._x>right-(this._width/2)) {
          this.velX *= -1;
          this._x = right-(this._width/2);
        }
        if (this._x<left+(this._width/2)) {
          this.velX *= -1;
          this._x = left+(this._width/2);
        }
        if (this._y>bottorn-(this._height/2)) {
          this.velY *= -1;
          this._y = bottom-(this._height/2);
        }
        if (this._y<top+(this._height/2)) {
          this.velY *= -1;
          this._y = top+(this._height/2);
        }
      }
    Пример 7.1.
  14. Запустите фильм. Теперь все это напоминает старый добрый пинг-понг, в который я играл еще ребенком. Ну, раз уж на то пошло, давайте доведем дело до конца.
Игорь Хан
Игорь Хан
След не остается
Александр Коргапольцев
Александр Коргапольцев
Вопрос по содержанию лекции №2, курс Flash MX Studio
Татьяна Ефимова
Татьяна Ефимова
Россия, г. Чебоксары