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

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

Кубок мира по пинг-понгу

  1. Оставьте последний фильм открытым на протяжении всего данного упражнения, так как мы будем использовать его код в качестве основы. Удалите левую и правую стенки и замените их "ракетками". В качестве ракетки вы можете просто нарисовать вертикальную линию любой длины и преобразовать ее в фильм с именем pc (я добавил надписи на ракетках, чтобы следующий рисунок был понятнее).
  2. Создайте дубликат фильма pc и назовите его player. Перетащите инстансы обоих фильмов на рабочее место и разместите их на новом слое с именем paddles.
  3. Назовите инстансы именами pc_mc и player_mc соответственно. Вручную разместите pc на позиции (50,200) и player на (500, 200). Позиции _y не так важны, так как они будут динамически обновляться в нашем ActionScript, а их стартовым значением будет центр поля.

  4. Начнем с добавления нескольких управляющих элементов onEnterFrame для двух ракеток.
    init();
      function init() {
        RIGHT = 500;
        LEFT = 50;
        TOP = 50;
        BOTTOM = 350;
        ball_mc.velX = 0;
        ball_mc.velY = 0;
        ball_mc.onEnterFrame = move;
        pc_mc.onEnterFrame = pcMove;
        player_mc.onEnterFrame = playerMove;
      }
  5. Дальше определяем функции pcMove и playerMove. pcMove начинается как простое уравнение приближения, поэтому ракетка компьютера будет всегда пытаться попасть на позицию шарика. Чтобы было интереснее, мы позволим этой ракетке двигаться только в том случае, если шарик передвигается в ее направлении (ball_mc.velX<0). Ракетка player, т.е. ракетка игрока? будет просто проверять нажатие клавиш [ВВЕРХ] и [ВНИЗ] и, в случае нажатия, перемещаться, соответственно, вверх или вниз. В обоих случаях с ракетками будет использоваться проверка коллизий по расстоянию, чтобы не допустить их исчезновения с игрового поля.
    function pcMove() {
        if (ball_mc.velX<0) {
          this._y += (ball_mc._y-this._y)/5;
        }
        if (this._y>bottom-this._height/2) {
          this._y = bottom-this._height/2;
          this.vy = 0;
        }
        if (this._y<top+this._height/2) {
          this._y = top+this._height/2;
          this.vy = 0;
        }
      }
      function playerMove() {
        if (Key.isDown(Key.UP)) {
          this._y -= 10;
        } else if (Key.isDown(Key.DOWN)) {
          this._y += 10;
        }
        if (this._y>bottom-this._height/2) {
          this._y = bottom-this._height/2;
          this.vy = 0;
        }
        if (this._y<top+this._height/2) {
          this._y = top+this._height/2;
          this.vy = 0;
        }
      }
    Пример 7.2.
  6. Начальные скорости шарика установлены на значение 0, чтобы можно было принимать решение, где и когда начинать игру. Это реализуется присвоением _root функции приемника событий Key, а также установкой события onKeyDown на начало движения шарика. Добавьте следующие четыре строки в функцию init и затем создайте функцию serve в конце всего кода.
    Key.addListener(_root);
      _root.onKeyDown = serve;
      pcServe = true;
      baseSpeed = 10;
    
      function serve() {
        if (Key.getCode(j == Key.SPACE) {
          if (playerServe) {
            ball_mc.velX = -baseSpeed;
            ball_mc.velY = Math.random()*20-10;
            playerServe = false;
          } else if (pcServe) {
            ball_mc.velX = baseSpeed;
            ball_mc.velY = Math.random()*20-10;
            pcServe = false;
          }
        }
      }

    Теперь при запуске игры, шарик не движется до тех пор, пока вы не нажмете пробел. Когда значением pcServe станет "истина", будет выполнен второй блок, и шарик направится к ракетке игрока.

  7. Если запустить код сейчас, перед вами будет неплохая игра в пинг-понг, однако будет заметен один недостаток. Попробуйте упустить шарик - он все равно отскочит. Вспомните, что мы не реализуем здесь настоящего столкновения с ракеткой, а лишь пользуемся математическим вычислением позиции шарика. Вместо того, чтобы переделывать пол-игры, мы лишь внесем некоторые изменения. Мы будем проверять, ударяется ли шарик перед отскоком именно о ракетку.

    Это значит, что шарик должен находиться ниже верхнего края ракетки, но выше нижнего ее края. Если он находится между этими двумя точками при ударе о right, значит, есть попадание. Если шарик пролетел мимо, он исчезает. Здесь мы могли бы применить старый добрый hitTest, однако я воспользуюсь этим случаем для представления новой концепции и действия под названием getBounds. Это одна из редко используемых команд. Она как бы разбивает hitTest на составные части и позволяет использовать именно те из них, которые необходимы.

    getBounds - это метод объекта movieClip. При вызове он возвращает объект. Этот объект имеет четыре параметра, которые сообщают нам о местоположении фильма. Вот способ использования данного метода.

    boundsObject=movieClip.getBounds (scope);

    boundsObject имеет следующие четыре параметра: xMin, xMax, yMin и yMax. Они логически соответствуют четырем краям граничного прямоугольника фильма. Однако, вместо того, чтобы заставлять Flash вычислять, что находится внутри, а что вне рамки, мы теперь можем работать с численными значениями. Теперь можно математическим путем определять наши собственные коллизии, пользуясь значением ширины и т.п., как мы делали в случае со стенками.

    Единственное, что осталось здесь определить, это параметр scope (область). Параметры min и max возвращаемого объекта boundsObject представлены в пикселях, но относительно чего? Это и есть наша область. В основном вам нужно будет вводить _root в качестве области, или любую другую позицию на временной диаграмме, на которой вы осуществляете проверку коллизий. Это даст вам значения X и Y фильма из _root.

    Если вы сделали сам фильм областью, он будет возвращать значения своих углов такими, каковы они есть с его точки зрения. Например, квадрат со стороной 100 пикселей с центральной точкой регистрации всегда будет возвращать значения -50 и 50 в качестве минимального и максимального значений, независимо от того, в каком месте экрана находится фильм. С точки зрения фильма, он распространяется на 50 пикселей вверх от центра, на 50 пикселей вниз, на 50 влево и на 50 вправо.


Игорь Хан
Игорь Хан

у меня аналогичная ситуация. Однако, если взять пример из приложения (ball_motion_04_click for trial.fla) то след остается. при этом заметил, что в моем проекте в поле "One item in library" виден кружок, в то время как в приложенном примере такого кружка нет.

Вопрос знатокам, что не так?

Александр Коргапольцев
Александр Коргапольцев

объект созданый мной упорно не желает оставлять след(единственное что добился, так это то что шарик резво гоняется за курсором) функция duplicateMovieClip остаётся не активной, т.е. следа от объекта не остаётся, но если я тоже самый код вбиваю в учебный файл всё работает, не могу понять где я ошибаюсь и почему в документе созданном заново, не работает код начиная от функции duplicateMovieClip? 

Тамара Ионова
Тамара Ионова
Россия, Нижний Новгород, НГПУ, 2009
Магомед Алисултанов
Магомед Алисултанов
Россия, Волгоград, лицей 2