ActionScript: перетаскивание множества визуальных объектов с проверкой пересечения

Итак, перед нами стоит задача, а точнее две:

1.) Перетаскивание большого количества (от нескольких штук до нескольких десятков или даже сотен) визуальных объектов (как правило, это MovieClip-ы и Sprite-ы) по сцене флеш-ролика.

2.) Проверка пересечения перетаскиваемых объектов с другими объектами на сцене флеш-ролика. При этом, если пересечение состоялось, то запускается одно действие (например, перетаскиваемый объект встаёт в координаты области пересечения), а если нет - другое (например, перетаскиваемый объект возвращается в первоначальные координаты).

В моём примере перетаскиваться будут три мувиклипа (да, я ленивый сукин сын). Эти MovieClip-ы будут называться весьма незатейливо: mc_1, mc_2 и mc_3 (да, у меня ещё и с фантазией очень плохо).

Для проверки пересечения создадим ещё два мувика: hit_mc_1 и hit_mc_2.

Всё это добро (пять мувиков) лежит внутри мувиклипа-контейнера по имени ... ТА-ДАМ! ... container.

Результат:

Переходим к коду. А код у нас будет следующим...

Код ActionScript 2.0:

var obj:Object = {mc_1:{startX:0, startY:0, hitAreaMc:"hit_mc_1"}, mc_2:{startX:0, startY:0, hitAreaMc:"hit_mc_1"}, mc_3:{startX:0, startY:0, hitAreaMc:"hit_mc_2"}}; var mc:MovieClip; for (var prop in obj) { mc = MovieClip(container[prop]); obj[prop].startX = mc._x; obj[prop].startY = mc._y; mc.onPress = onPressFunc; mc.onRelease = onReleaseFunc; } function onPressFunc() { this.startDrag(true); } function onReleaseFunc() { var mc:MovieClip = MovieClip(this); var mc_hit:MovieClip = MovieClip(container[obj[mc._name].hitAreaMc]); mc.stopDrag(); if (mc_hit.hitTest(mc._x,mc._y,true)) { mc._x = mc_hit._x; mc._y = mc_hit._y; } else { mc._x = obj[mc._name].startX; mc._y = obj[mc._name].startY; } }

Код ActionScript 3.0:

var obj:Object = { mc_1:{startX:0, startY:0, hitAreaMc:"hit_mc_1"}, mc_2:{startX:0, startY:0, hitAreaMc:"hit_mc_1"}, mc_3:{startX:0, startY:0, hitAreaMc:"hit_mc_2"} }; var mc:MovieClip; for (var prop in obj) { mc = container.getChildByName(prop) as MovieClip; obj[prop].startX = mc.x; obj[prop].startY = mc.y; mc.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDownFunc); mc.addEventListener(MouseEvent.MOUSE_UP, onMouseUpFunc); } function onMouseDownFunc(event:MouseEvent):void { var mc:MovieClip = event.target as MovieClip; mc.startDrag(true, new Rectangle(0,0,550,400)); } function onMouseUpFunc(event:MouseEvent):void { var mc:MovieClip = event.target as MovieClip; var mc_hit:MovieClip = container.getChildByName(obj[mc.name].hitAreaMc) as MovieClip; mc.stopDrag(); if (mc_hit.hitTestPoint(mc.x,mc.y,true)) { mc.x = mc_hit.x; mc.y = mc_hit.y; } else { mc.x = obj[mc.name].startX; mc.y = obj[mc.name].startY; } }

Результат:

Вся соль в том, что все важные данные мы храним в ассоциативном массиве obj. И, вместо того, чтобы нудно прописывать код для каждого перетаскиваемого объекта, мы просто вносим необходимые данные в массив obj. Код получается более компактным и понятным. При этом, код в любой момент можно модифицировать под любые ваши задачи. Кстати, именно поэтому я и использую ассоциативный массив: его можно безболезненно изменить и в нём удобно хранить данные любого типа.

В нашем примере массив obj состоит из трёх элементов. Каждый элемент содержит набор свойств, описывающих поведение отдельного перетаскиваемого объекта. Например, следующий фрагмент:

mc_1:{startX:0, startY:0, hitAreaMc:"hit_mc_1"}

переводится примерно так:

мувиклип_mc_1:{координаты_по_оси_x:0, координаты_по_оси_y:0, целевой_мувиклип:"hit_mc_1"}

Естественно, если перед вами стоят иные задачи, то и список свойств будет иной. Моей же задачей было показать только принцип работы. Надеюсь, я справился :-)

Скачать исходники к данному уроку можно по следующей ссылке - скачать исходники (под Adobe Flash CS5).

Дополнение № 1. Добавляем плавности.

Знаю, некоторым в моём примере не хватает плавности при перемещении объектов в назначенные им координаты. Но это не проблема. Особенно, если морально-этические соображения позволяют вам использовать библиотеку TweenLite от GreenSock. Изменения в коде будут незначительными:

Код ActionScript 2.0:

import com.greensock.*; var obj:Object = {mc_1:{startX:0, startY:0, hitAreaMc:"hit_mc_1"}, mc_2:{startX:0, startY:0, hitAreaMc:"hit_mc_1"}, mc_3:{startX:0, startY:0, hitAreaMc:"hit_mc_2"}}; var mc:MovieClip; for (var prop in obj) { mc = MovieClip(container[prop]); obj[prop].startX = mc._x; obj[prop].startY = mc._y; mc.onPress = onPressFunc; mc.onRelease = onReleaseFunc; } function onPressFunc() { this.startDrag(true); } function onReleaseFunc() { var mc:MovieClip = MovieClip(this); var mc_hit:MovieClip = MovieClip(container[obj[mc._name].hitAreaMc]); mc.stopDrag(); if (mc_hit.hitTest(mc._x,mc._y,true)) { TweenLite.to(mc, 0.4, {_x:mc_hit._x, _y:mc_hit._y}); } else { TweenLite.to(mc, 0.4, {_x:obj[mc._name].startX, _y:obj[mc._name].startY}); } }

Код ActionScript 3.0:

import com.greensock.*; var obj:Object = { mc_1:{startX:0,startY:0,hitAreaMc:"hit_mc_1"}, mc_2:{startX:0,startY:0,hitAreaMc:"hit_mc_1"}, mc_3:{startX:0,startY:0,hitAreaMc:"hit_mc_2"} }; var mc:MovieClip; for (var prop in obj) { mc = container.getChildByName(prop) as MovieClip; obj[prop].startX = mc.x; obj[prop].startY = mc.y; mc.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDownFunc); mc.addEventListener(MouseEvent.MOUSE_UP, onMouseUpFunc); } function onMouseDownFunc(event:MouseEvent):void { var mc:MovieClip = event.target as MovieClip; mc.startDrag(true, new Rectangle(0,0,550,400)); } function onMouseUpFunc(event:MouseEvent):void { var mc:MovieClip = event.target as MovieClip; var mc_hit:MovieClip = container.getChildByName(obj[mc.name].hitAreaMc) as MovieClip; mc.stopDrag(); if (mc_hit.hitTestPoint(mc.x,mc.y,true)) { TweenLite.to(mc, 0.4, {x:mc_hit.x, y:mc_hit.y}); } else { TweenLite.to(mc, 0.4, {x:obj[mc.name].startX, y:obj[mc.name].startY}); } }

Результат:

Как-то так.

Автор: admin

Дата добавления: 2013-11-06

Просмотров: 6660

Рейтинг поста: +13-

Правила перепечатки

Социальные закладки:
Комментарии:
Комментатор
Комментарий добавил(а): edapskov
Дата добавления: 2013-12-15
Алексей, а какая разница на каком уровне лежит целевой объект, если используется hitTestPoint? Если перетаскиваемый и целевой объекты лежат внутри одного и того же объекта-контейнера, то разницы нет.
Комментатор
Комментарий добавил(а): Алексей
Дата добавления: 2013-12-15
А если целевые ролики (hit) пересекаются, т.е. один лежит поверх другого, как сделать чтобы нижний тоже реагировал на приближение объекта? Или здесь только программно отслеживать координаты?
Добавить комментарий:







[ + ] помощь по форматирование текста

Идиот-тест

Если все обязательные поля (отмечены * ) заполнены необходимой информацией, то нажимаем кнопку Добавить комментарий.

Страница 2 из 2: 12
Меню
Подписка
Рубрики
Метки
Последние комментарии
Рейтинг постов
Реклама
Друзья
География гостей
Статистика
Яндекс.Метрика