voliuf.narod.ru

главная

друзья

помощь сайту

Flash MX Studio

Бесплатные учебники по темам

Партнерская программа

1.Представление сайта

2.Форматирование текста

3.Рисование API

4.Компоненты

5.Движемся дальше

6.Интерфейсы AсtionScript

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

8.Математика и физика Flash

9.Анимация и интерактивность Drawing API

10.Реализация 3D-графики с помощью рисования API

11.Изучение SphereCage

12.Сайты с мультимедийным содержимым

13.Видеоданные

14.Аудио

15.Интеграция динамических данных

16.Динамический Flash: PHP

17.XML

18.Flash, ColdFusion и Remoting


 


Flash MX Studio
 
 
Внимание! Для работы с этой лекцией необходимы учебные файлы, которые Вы можете загрузить  здесь.

В лекции 6 мы рассмотрели некоторые способы взаимодействия пользователя с объектами на экране. Теперь мы рассмотрим, как объекты могут реагировать друг на друга при обнаружении коллизий. Целая лекция, посвященная обнаружению коллизий? Да, поскольку мы расскажем о многих сопутствующих моментах, разобравшись в которых, вы будете прекрасно разбираться в коллизиях.

 

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

 

Метод hitTest

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

 

Есть два способа использования hitTest, причем второй имеет две возможности, итого получается три различных метода работы с hitTest. Мы рассмотрим их в порядке возрастания сложности.

 

Наиболее простая интерпретация hitTest, как вы помните из предыдущей лекции, такова.

 
movieClip1_mc.hitTest (movieClip2_mc);

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

 
if (movieClip1_mc.hitTest(movieClip2_mc)) {
  // do something
}

Граничные прямоугольники

При использовании hitTest необходимо знать о так называемых граничных прямоугольниках. Это невидимые прямоугольники, полностью соответствующие границам фильма. Верх прямоугольника соответствует самому верхнему видимому элементу фильма, низ - самому нижнему видимому элементу, а левый и правый края прямоугольника соответствуют самым дальним левой и правой точкам фильма. Если вы расположите фильм на рабочем месте и затем щелкнете на нем, чтобы выделить его, вы увидите синюю рамку вокруг фильма (если вы не изменили цвет рамок по умолчанию). Это и будет прямоугольник, являющийся границей фильма:

 

 


 

 

Этот граничный прямоугольник является тем элементом, который используется hitTest для проверки коллизий. С его помощью этот процесс осуществляется быстро и эффективно, однако, к сожалению, во многих случаях он может давать довольно неточные результаты. За исключением случая, когда рассматриваемый фильм является прямоугольным, т.е. граничный прямоугольник содержит только сам фильм, граничный прямоугольник всегда содержит внутри себя лишнее место, помимо самого фильма. Поэтому hitTest может нередко обнаруживать коллизии, когда рисунки в фильмах визуально не касаются друг друга. Вот типичный пример описываемого случая:

 

 


 

 

Как можно обойти этот недостаток? Никак, если вы собираетесь использовать только данную версию hitTest. Это и есть та цена, которую вы платите за скорость и простоту использования данного метода. Хотя для многих приложений этот способ вполне годится. В небольшой игре-стрелялке, созданной нами в предыдущей лекции, все двигалось довольно быстро, и вы не заметили бы какие-либо неточности. Но представьте себе игру, например, Atari's Asteroids, где объекты могут двигаться довольно медленно. Вы собираетесь подвести ваш корабль близко к краю астероида, но тут он внезапно взрывается. "Я же его не касался!" - скажете вы. Да, как видите, эта версия hitTest не была бы хорошим решением в данной ситуации.

 

Вы наверняка использовали этот метод ранее, по крайней мере, в предыдущей лекции, поэтому мы не будем терять время на рассмотрение примеров с его использованием. Перейдем к следующему способу использования hitTest.

 

Использование shapeFlag

Приведем основной синтаксис для реализации hitTest с помощью shapeFlag.

 
movieClip_mc.hitTest (x, y, shapeFlag);

Я знаю, что вы сразу обратили внимание на параметр shapeFlag, но не торопитесь. Давайте прочтем выражение слева направо.

 

В начале мы видим movieClip_mc, который, очевидно, является именем проверяемого фильма. Заметьте, что мы в этот раз проверяем только один фильм. Итак, было ли попадание в этом фильме? Ответ является просто точкой. Эта точка определяется следующими двумя параметрами x и y. Здесь задаем вопрос, находится ли точка (x,y) внутри области фильма movieClip_mc.

 

Теперь переходим к параметру shapeFlag. С его помощью мы можем выбирать, нужно или не нужно использовать граничный прямоугольник фильма. Если shapeFlag установлен на значение "ложь" или 0, hitTest будет просто проверять, находится ли точка внутри фильма. Но если вы установите shapeFlag на значение "истина" или любое ненулевое численное значение, мы сможем выйти за рамки ограничений использования способа граничных прямоугольников и проверять, находится ли точка в видимой части фильма.

 

Да, этот способ намного эффективнее. Использование shapeFlag в качестве альтернативы методу hitTest довольно широко распространено. На самом деле я очень редко пользовался hitTest без shapeFlag.

 

Теперь все выглядит намного приличнее, однако прежде чем заключить, что все наши проблемы успешно решены, нужно выяснить, откуда берутся эти значения x и y. Вспомните, что с помощью первого рассмотренного нами способа фильм проверялся в сопопоставлении с другим фильмом. Мы можем имитировать это посредством использования одного фильма как фильма, выполняющего функцию, а параметры _x и _y второго фильма в качестве параметров x и y hitTest. Это будет выглядеть так.

 
movieClip1_mc.hitTest (movieClip2_mc._x, movieClip2_mc._y, true);

Посмотрев на следующий рисунок, вы поймете, с какой проблемой мы сейчас столкнемся.

 

Попадание не будет зарегистрировано, так как параметры x и y здесь ссылаются на центр movieClip2_mc, который не находится внутри нужной области попадания.

 

 


 

 

Итак, мы попали из огня да в полымя: Да, я люблю метафоры. Я хотел бы дать вам исчерпывающий совет по поводу того, как обойти эту проблему, однако так и не нашел поистине эффективного способа. Это задачка вроде поиска Св. Грааля: представить фильм с помощью shapeFlag для проверки попадания фильма. На самом деле выход существует всегда, поэтому не бейтесь головой о стену, думая, что вы упустили что-то очевидное. Я дам вам несколько советов, чтобы вам было легче.

 
  • Самый важный момент вполне понятен: всякие методы хороши в различных ситуациях, поэтому поэкспериментируйте со всеми тремя способами и выберите наиболее подходящий.
  • В большинстве случаев, если у вас есть большой и маленький объект, лучше всего использовать большой объект в качестве фильма, выполняющего hitTest, и маленький для предоставления параметров X и Y.
  • Если вы имеете дело с объектом неправильной формы, особенно если его размеры велики, лучше вызывать hitTest из этого объекта, так как вам нужна форма видимой области этого объекта.
  • Если у вас два более-менее прямоугольных объекта, используйте основной метод метод двух фильмов.
 

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

 

Использование различных типов hitTest

  1. Откройте новый основной фильм и создайте в нем два фильма с именами movieClip1 и movieClip2. Придайте обоим фильмам неправильную форму и назовите их инстансы именами movieClip1_mc и movieClip2_mc соответственно.
  2. Мы будем использовать проверку по двум фильмам, поэтому введите следующий код в кадре 1 нового слоя с именем actions.
    movieClipl_mc.onEnterFrame = function() {
      if (this.hitTest(movieClip2_mc)) {
        trace("hit");
      }
    };
    movieClip2_mc.onEnterFrame = function() {
      this._x = _xmouse;
      this._y = _ymouse;
    };
  3. Запустите ваш фильм и начните перетаскивать movieClip2. Вы увидите результат каждой проверки в окне Output.

     


     

     
  4. Закройте тестовый фильм. Теперь мы попробуем использовать проверку "фильм-точка" без shapeFlag, поэтому просто замените имеющийся код из шага 2 следующим кодом.
     movieClipl_mc.onEnterFrame = function() {
      if (this.hitTest(movieClip2_mc._x, movieClip2_mc._y, false)) {
       trace("hit");
      }
     };
     movieClip2_mc.onEnterFrame = function() {
      this._x = _xmouse;
      this._y = _ymouse;
     };
  5. Чтобы было лучше видно, где Flash регистрирует столкновение, удалите заливку из movieClip2, чтобы остался только контур. Теперь проверьте ваш фильм.

     


     

     

    Cтолкновение не регистрируется до тех пор, пока курсор не войдет (хотя он не виден) в граничную рамку вокруг movieClip1.

     
  6. Закройте тестовый фильм. Наконец, попытаемся использовать проверку "фильм-точка", но уже с использованием shapeFlag. Замените весь имеющийся код в кадре 1 следующим кодом.
     movieClip1_mc .onEnterFrame = function () {
      if (this.hitTest(movieClip2_mc._x, movieClip2_mc._y, true)) {
       trace("hit");
      }
     };
     movieClip2_mc.onEnterFrame = function() {
      this._x = _xmouse;
      this._y = _ymouse;
     };
  7. Запустите ваш фильм. Перетаскивайте movieClip2 в разные места мышью и наблюдайте за происходящими столкновениями в окне Output.

     


     

     

    Эксперименты с каждым и этих методов дадут вам представление о работе каждого из них, а также о том, какой именно метод нужно использовать в той или иной ситуации.

     
 

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

Несмотря на то, что мы рассказали все о 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. Запустите фильм. Теперь все это напоминает старый добрый пинг-понг, в который я играл еще ребенком. Ну, раз уж на то пошло, давайте доведем дело до конца.
 

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

  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 вправо.

     

     


     

     
 
  1. Это не слишком годится для достижения преследуемых нами целей, поэтому мы применим _root. Добавьте следующую новую строку в функцию move.
      function move() {
        this._x += this.velX;
        this._y += this.velY;
        if (this._x>right-(this._width/2)) {
        playerBounds = player_mc.getBounds(_root);

    Теперь playerBounds будет содержать четыре параметра, упомянутые ранее. Параметры, которые нас больше всего интересуют - это yMin и yMax. Если ball_mc._y находится между этими двумя значениями после передачи им точки, определенной выражением right-(this._width/2), то он ударяется о ракетку игрока.

     

     


     

     
  2. Добавим другое условное выражение с использованием логического оператора AND (&&). Имейте в виду, что при этом также учитывается ширина шарика, поэтому мы реализуем проверку не только относительно центра шарика. Таким образом, мы получим гораздо более реалистичный удар.
      function move() {
        this._x += this.velX;
        this._y += this.velY;
        if (this._x>right-(this._width/2)) {
          playerBounds = player_mc.getBounds(_root);
          upper = playerBounds.yMin - this._height/2;
          lower = playerBounds.yMax + this._height/2;
          if (this._y>upper && this._y<lower) {
            this.velX *= -1;
            this.velY += Math.random()*20 - 10;
            this._x = right-(this._width/2);
          }
        }
      }
  3. Внутри блока кода мы также добавим некоторую степень случайности фактора velY. В противном случае шарик будет просто отскакивать вперед-назад под одними и теми же углами. Мы также немного увеличим скорость - всего лишь на один процент - чтобы немного усложнить игру. Имейте в виду, что мы должны увеличить как текущую скорость velX, так и baseSpeed, чтобы на следующей "подаче" скорость шарика возрастала.
      if (this._y>upper && this._y<lower) {
        this.velX *= -1;
        this.velY += Math.random()*20-10;
        this._x = right-(this._width/2);
        baseSpeed *= 1.01;
        this.velX *= 1.01;
      }
  4. Теперь мы знаем, что будет, если шарик попадет в ракетку, но нам нужно также решить, что будет, если шарик пройдет мимо нее. Мы будем возвращать шарик на середину экрана, изменять его скорость и направление случайным образом и увеличивать количество очков оппонента. Это реализовано в блоке else.
      function move() {
        this._x += this.velX;
        this._y += this.velY;
        if (this._x>right-(this._width/2)) {
          playerBounds = player_mc.getBounds(_root);
          if (this._y>playerBounds.yMin && this._y<playerBounds.yMax) {
            this.velX *= -1;
            this._x = right-(this._width/2);
        } else {
          this._x = 275;
          this._y = 200;
          this.velX = 0;
          this.velY = 0;
          pcScore++;
          playerServe = true;
        }
      }

    Здесь вы можете реализовать все, что вам придет в голову. Мне хватило и того, что я добавил динамическое текстовое поле слева вверху рабочего места с именем переменной pcScore.

     

     


     

     
  5. Окончательный код игры.
      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;
        Key.addListener(_root);
        _root.onKeyDown = serve;
        pcServe = true;
        baseSpeed = 10;
      }
      function move() {
        this._x += this.velX;
        this._y += this.velY;
        if (this._x>right-(this._width/2)) {
          playerBounds = player_mc.getBounds(_root);
          upper = playerBounds.yMin-this._height/2;
          lower = playerBounds.yMax+this._height/2;
          if (this._y>upper && this._y<lower) {
            this.velX *= -1;
            this.velY += Math.random()*20-10;
            this._x = right-(this._width/2);
            baseSpeed *= 1.01;
            this.velX *= 1.01;
          } else {
            this._x = 275;
            this._y = 200;
            this.velX = 0;
            this.velY = 0;
            pcScore++;
            playerServe = true;
          }
        }
        if (this._x<left+(this._width/2)) {
          pcBounds = pc_mc.getBounds (_root);
          if (this._y>pcBounds.yMin-this._height/2 &&
            Кthis._y<pcBounds.yMax+this._height/2) {
            this.velX *= -1;
            this.velY += Math.random()*20-10;
            this._x = left+(this._width/2);
            baseSpeed *= 1.01;
            this.velX *= 1.01;
          } else {
            this._x = 275;
            this._y = 200;
            this.velX = 0;
            this.velY = 0;
            playerScore++;
            pcServe = true;
          }
        }
        if (this._y>bottom-(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);
        }
      }
      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;
        }
      }
      function serve() {
        if (Key.getCode() == 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. vel Y = Math.random()*20-10;
            pcServe = false;
          }
        }
      }

    Пример 7.3.

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

     

    Можете смело экспериментировать с этой игрой. В коде на диске есть несколько дополнений, однако вы сами можете создать очень много интересного.

     

Обнаружение коллизий по принципу "фильм-фильм" по расстоянию

Это последний метод обнаружения коллизий, который мы рассмотрим. Он полностью подходит для идеально круглых объектов, хотя можно немного схитрить и применить его к тем объектам, которые имеют более-менее округлую форму.

 

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

 

 


 

 

Я пометил стороны буквами x, y и d. Теорема Пифагора гласит.

 
x2 + y2 = d2

Т.е.:

 
x*x + y*y = d*d

Теперь, если провести некоторые элементарные алгебраические преобразования, получим следующее.

 
d = Math.sqrt (x*x + y*y);

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

 

 


 

 

На рисунке показано, что dx - это расстояние по оси x между mc1_mc и mc2_mc. dy - это расстояние по оси y, а dist - это среднее расстояние между ними. Зная все это, можно интерпретировать данные выводы следующим образом с помощью обычного кода.

 
  dx = mc2_mc._x-mc1_mc._x;
  dy = mc2_mc._y-mc1_mc._y;
  dist = Math.sqrt (dx*dx+dy*dy);

Это еще одна шпаргалка для вас. Запишите эти выражения, они вам пригодятся.

 

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

 

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

 

 


 

 

Приведем код для выяснения того, произошло столкновение или нет.

 
  dx=mc2_mc._x-mc1_mc._x;
  dy=mc2_mc._y-mc1_mc._y;
  dist=Math.sqrt(dx*dx+dy*dy);
  if (dist<mc1_mc._width/2 + mc2_mc._width/2){
    // you have a hit!
  }

То, что будет происходить после обнаружения столкновения - уже другая история. Так и хочется создать файл с некоторым количеством сфер, летающих и сталкивающихся друг с другом. Изучив материал до этого момента, становится понятно, что нужно научиться обращать скорости x или y, а это и будет главным "фокусом". К сожалению, все не так просто. Мы рассмотрим некоторые из таких моментов в следующей лекции. А сейчас просто создадим небольшой файл в качестве примера, чтобы вы сами убедились в реальности применения рассмотренного материала.

 

Это будет еще одна небольшая игра, что-то наподобие Atari's Asteroids, однако вы можете превратить эту игру во все, что придет вам в голову.

 

Учет размеров объекта

  1. Откройте новый фильм. Создайте круглый фильм, который и будем использоваться (я создал круг диаметром 100 пикселей). Назовите его ball и отметьте опцию Export for ActionScript в окне Linkage Properties. Введите идентификатор связи ball.
  2. Сохраните копию шарика на рабочем месте и назовите инстанс player_mc.
  3. Теперь создадим в игре ряд препятствий-астероидов. Мы, как обычно, реализуем это в функции init с помощью цикла for. В нем мы присваиваем препятствиям случайные позиции, скорости и размеры, азатем присваиваем управляющий элемент onEnterFrame. Какой продуктивный цикл! Добавим все это в отдельный слой с именем actions.
      init();
      function init() {
        for (i=0; i<10; i++) {
          ball_mc = attachMovie("ball", "b"+i, i);
          ball_mc._x = Math.random 0*550;
          ball_mc._y = Math.random 0*400;
          ball_mc.velX = Math.random 0*10-5;
          ball_mc.velY = Math.random()*10-5;
          ball_mc._xscale = Math.random()*40+10;
          ball_mc._yscale = Math.random()*40+10;
          ball_mc.onEnterFrame = ballMove;
        }
      }
  4. Далее определим функцию ballMove.
      function ballMove() {
        this._x += this.velX;
        this._y += this.velY;
        if (this._x>550) {
          this._x = 0;
        }
        if (this._y<0) {
          this._x = 550;
        }
        if (this._y>400) {
          this._y = 0;
        }
        if (this._y<0> {
          this._y = 400;
        }
      }

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

     
  5. Создадим управляющий элемент player_mc.onEnterFrame. Сначала присвоим его в конце функции init.
    player_mc.onEnterFrame = playerMove;
  6. Теперь определим саму функцию под всем текущим ActionScript. Это будет обычная функция приближения к курсору мыши с довольно сильным трением.
      function playerMove() {
        this._x += (_root._xmouse-this._x)/20;
        this._y += (_root._ymouse-this._y)/20;
      }
  7. Запустив фильм, вы увидите случайный набор медленно двигающихся кругов и большой круг, следующий за курсором мыши. Оживим эту игру, добавив в нее обнаружение коллизий. Это реализуется с помощью точно такого же кода, как и в упражнении с теоремой Пифагора, нужно лишь вставить имена инстансов. Мы добавим этот код в функцию ballMove, прямо в ее конец. Теперь каждый шарик будет проверять сам себя на столкновение с player_mc в каждом кадре.
      dx = player_mc._x-this._x;
      dy = player_mc._y-this._y;
      dist = Math, sqrt (dx*dx+dy*dy);
      if (dist<player_mc._width/2+this._width/2) {
        player_mc._visible = false;
      }

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

     
      player_mc. onMouseDown = function() {
        this._visible = true;
      };
  8. Запустите ваш фильм и попробуйте как можно дольше избежать столкновения с астероидами. Ниже приведен окончательный код игры. Вы можете экспериментировать с этим кодом до тех пор, пока не получите нечто более интересное.
      init();
      function init() {
        for (i=0; i<10; i++) {
          ball_mc = attachMovie("ball", "b"+i, i);
          ball_mc._x = Math.random 0*550;
          ball_mc._y = Math.random 0*400;
          ball_mc.velX = Math.random 0*10-5;
          ball_mc.velY = Math.random 0*10-5;
          ball_mc._xscale = Math.random()*40+10;
          ball_mc._yscale = Math.random()*40+10;
          ball_mc.onEnterFrame = ballMove;
          player_mc.onEnterFrame = playerMove;
          player_mc. onMouseDown = function() {
            this._visible = true;
          };
        }
      }
      function ballMove() {
        this._x += this.velX;
        this._y += this.velY;
        if (this._x>550) {
          this._x = 0;
        }
        if (this._y<0  {
          this._x = 550;
        }
        if (this._y>400) {
          this._y = 0;
        }
        if (this._y<0) {
          this._y = 400;
        }
        dx = player_mc._x-this._x;
        dy = player_mc._y-this._y;
        dist = Math.sqrt(dx*dx+dy*dy);
        if (dist<player_mc._width/2+this._width/2) {
          player_mc._visible = false;
        }
      }
      function playerMove() {
        this._x += (_root._xmouse-this._x)/20;
        this._y += (_root._ymouse-this._y)/20;
      }

    Пример 7.4.

 

Коллизии множества объектов

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

 

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

 

В последнем упражнении мы могли бы "перевернуть" проверку коллизий для объекта player. В нем можно было бы использовать цикл for, как и в космических кораблях, и проверять каждый меньший шарик. Это реализуется в функции playerMove следующим образом.

 
  for (i=0; i<10; i++) {
    dx = this._x-_root["b"+i]._x;
    dy = this._y-_root["b"+i]._y;
    dist = Math.sqrt(dx*dx+dy*dy);
    if (dist<this._width/2+_root["b"+i]._width/2) {
      this._visible = false;
    }
  }

Этот вариант работает отлично, однако мы обеспечиваем лишь проверку одного объекта относительно одного, или одного относительно нескольких объектов. А что делать в случае, если у нас имеется набор движущихся объектов, и каждый из них должен реагировать на столкновение с любым другим объектом? Можно было бы добавить в каждый из них цикл for, как показано выше, чтобы каждый объект был обработан циклом для проверки на столкновение с любым другим объектом, однако это было бы очень неэффективно. Представьте себе следующий сценарий.

 

Имеется три объекта: A, B и C. A проверяет столкновение между собой и B, затем столкновение между собой и C; B проверяет столкновение между собой и A, а также между собой и C; наконец, C осуществляет проверку относительно A и B. Итак, мы имеем:

 
  • A:B
  • A:C
  • B:A
  • B:C
  • C:A
  • C:B
 

Мы получили шесть вариантов, но это вдвое больше, чем нужно. A:B - это то же самое, что и B:A, A:C идентично C:A, а B:C - то же, что и C:B.

 

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

 

Поддержка множества объектов в массиве

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

 
  1. Используйте фильм из последнего упражнения с фильмом ball в Library и сохраните его под другим именем. Удалите все инстансы с рабочего места, а также весь имеющийся код. Начните с добавления в кадр 1 слоя actions этого кода.
      init();
      function init() {
        max = 10;
        balls_array = new Array();
        for (n=0; n<max; n++) {
          balls_array[n] = attachMovie("ball", "b"+n, n) ;
          balls_array[n]._x = Math.random 0*550;
          balls_array[n]._y = Math.random()*400;
          balls_array[n].velX = Math.random()*10-5;
          balls_array[n].velY = Math.random()*10-5;
          balls_array[n]._xscale = balls_array[n]._yscale =
             Math.random()*50+30;
        }
      }

    Здесь мы установили значение max, которое будет определять число создаваемых шариков. Затем создается массив для хранения в нем фильмов. Цикл для присвоения фильмов практически идентичен предыдущему файлу, за исключением того, что он присваивает фильм элементу массива и осуществляет доступ к нему через этот элемент для присвоения параметров. Мы также опустили управляющий элемент onEnterFrame, так как управление фильмами будет осуществляться извне.

     
  2. Вместо этого, мы добавим функцию onEnterFrame в _root. Сначала реализуем присвоение в функции init (под строкой max = 10;):
    _root.onEnterFrame = main;
  3. Теперь мы можем определить функцию main, в которой и будет заключаться весь смысл. Сначала обрабатываем циклом массив для передвижения каждого шарика по отдельности. Здесь все довольно просто.
      function main() {
        for (i=0; i<balls_array.length; i++) {
          balls_array[i] ._x += balls_array[i] .velX;
          balls_array[i] ._y += balls_array[i] .velY;
          if (balls[i]_array._x>550) {
            balls[i]_array._x = 0;
          }
          if (balls[i]_array._x<0) {
            balls[i]_array._x = 550;
          }
          if (balls[i]_array._y>400) {
            balls[i]_array._y = 0;
          }
          if (balls[i]_array._y<0) {
            balls[i]_array._y = 400;
          }
        }
      }

    Выглядит знакомо? Так и должно быть. Это тот же самый код, что и ранее, однако здесь мы осуществляем доступ к фильму извне через элемент массива, в котором он сохранен, вместо внутреннего доступа с использованием this. Запуститe фильм. Вы увидите двадцать кругов, в случайном порядке двигающихся по экрану. Теперь перейдем к обнаружению столкновений:

     
  4. В этом шаге мы будем использовать цикл for. Внешний цикл будет обрабатывать каждый элемент массива (содержащий ссылку на фильм), а внутренний цикл будет использоваться для проверки этого элемента относительно каждого последующего элемента в массиве. Приведем псевдокод, чтобы показать, как это реализуется.
      for (i=0; i<balls_array, length-1; i++) {
        for (j=i+l; j<balls_array. length; j++) {
          // test between balls_array[i] and balls_array[j] here
        }
      }

    Это еще одна ваша шпаргалка. Мы будем использовать код проверки коллизий на основе окружностей/расстояния для проверки столкновения шариков. В случае столкновения оба шарика будут удаляться.

     
  5. Чтобы удалить шарики, нам нужно будет удалить не только фильм, но также его ссылку в массиве. Мы реализуем это с помощью метода array.splice (index, number). Эта команда удаляет число number элементов из массива, начиная с index. Измените функцию main следующим образом.
      function main() {
        for (i=0; i<balls_array.length; i++) {
          balls_array[i]._x += balls_array[i].velX;
          balls_array[i]._y += balls_array[i].velY;
          if (balls_array[i]._x>550) {
            balls_array[i]._x = 0;
          }
          if (balls_array[i]._x<0) {
            balls_array[i]._x = 550;
          }
          if (balls_array[i]._y>400) {
            balls_array[i]._y = 0;
          }
          if (balls_array[i]._y<0) {
            balls_array[i]._y = 400;
          }
        }
        for (i=0; i<balls_array.length-1; i++) {
          for (j=i+1; j<balls_array.length; j++) {
            dx = balls_array[i]._x-balls_array[j]._x;
            dy = balls_array[i],_y-balls_array[j]._y;
            dist = Math.sqrt(dx*dx+dy*dy);
            if (dist<balls_array[i]._width/2+ balls_array [j]._width/2) {
              removeMovieClip(balls_array[j]);
              balls_array.splice(j, 1);
              removeMovieClip(balls_array[i]);
              balls_array. splice(i, 1);
            }
          }
        }
      }

    Пример 7.5.

  6. В конечном итоге все фильмы уничтожат друг друга, поэтому мы сделаем так, чтобы они появлялись заново. Cоздадим управляющий элемент onMouseDown в начале функции init.
    _root.onMouseDown = createBall;
  7. Теперь добавим эту новую функцию под всем имеющимся кодом.
      function createBall() {
        ball_mc = attachMovie("ball", "b"+n, n++);
        ball_mc._x = _root._xmouse;
        ball_mc._y = _root._ymouse;
        ball_mc.velX = Math.random()*10-5;
        ball_mc.velY = Math.random()*10-5;
        ball_mc._xscale = Math.random()*50+30;
        ball_mc._yscale = Math.random()*50+30;
        ball_mc.onEnterFrame = ballMove;
        bal1s_array.push(ball_mc);
      }

    Это похоже на код, использованный в init для создания исходных фильмов ball. Основное отличие заключается в том, что здесь ссылка на фильм записывается во временную переменную, присваиваются все его параметры, и затем используется array.push для добавления его в массив.

     

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

     
  8. Запустите ваш фильм. Для проверки правильности написания кода, приведем полный исходный код программы.
      init();
      function init () {
        max = 10;
        _root.onEnterFrame = main;
        _root.onMousedown = createBall;
        balls_array = new Array();
        for (n=0; n<max; n++) {
          balls_array[n] = attachMovie("ball", "b"+n, n);
          balls_array[n]._x = Math.random()*550;
          balls_array[n]._y = Math.random()*400;
          balls_array[n].velX = Math.random()*10-5;
          balls_array[n].velY = Math.random()*10-5 ;
          balls_array[n]._xscale = balls_array[n]._yscale= Math. random 0*50+30;
        }
      }
      function main() {
        for (i=0; i<balls_array.length; i++) {
          balls_array[i]._x += balls_array[i].velX;
          balls_array[i]._y += balls_array[i].velY;
          if (balls_array[i]._x>550) {
            balls_array[i]._x = 0;
          }
          if (balls_array[i]._x<0) {
            balls_array[i]._x = 550;
          }
          if (balls_array[i]._y>400) {
            bal1s_array[i]._y = 0;
          }
          if (balls_array[i]._y<0) {
            balls_array[i]._y = 400;
          }
        }
        for (i=0; i<balls_array.length-1; i++) {
          for (j=i+1; j<balls_array.length; j++) {
            dx = balls_array[i]._x-balls_array[j]._x;
            dy = balls_array[i]._y-balls_array[j]._y;
            dist = Math.sqrt(dx*dx+dy*dy);
            if (dist<balls_array[i]._width/2+ balls_array[j] ._width/2) {
              removeMovieClip(balls_array[j]);
              balls_array.splice(j, 1);
              removeMovieClip(balls_array[i]);
              balls_array.splice(i, 1);
            }
          }
        }
      }
      function createBall() {
        ball_mc = attachMovie("ball", "b"+n, n++);
        ball_mc._x = _root._xmouse;
        ball_mc._y = _root._ymouse;
        ball_mc.velX = Math.random()*10-5;
        ball_mc.velY = Math.random()*10-5;
        ball_mc._xscale = Math.random()*50+30;
        ball_mc._yscale = Math.random()*50+30;
        ball_mc.onEnterFrame - ballMove;
        balls_array.push(ball_mc);
      }

    Пример 7.6.

  9. Сохраните ваш фильм и закройте его (или поиграйте в игру, если желаете).
 

источник: http://www.INTUIT.ru 


 

13 центов(0,13$) за клик, выплаты через WebMoney каждый вторник +10% с рефералов

Мы выкупаем 100% трафа! $12 за 1000 хостов (РФ), и до $4 за 1000 хостов (зарубежный траф) + 10% с дохода Ваших рефералов!
 Выплаты через
WebMoney

~80-100$ за1000 хостов 2.5$ за 1 смс.
реф. процент - 10 %Выплаты происходят раз в неделю, в четверг на
WebMoney
 
 

 

____________________________

Посмотреть порно видео в онлайне »

_______________________________

 

   
   
Сайт управляется системой uCoz