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

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

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

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

Социальные закладки:
Комментарии:
Комментатор
Комментарий добавил(а): edapskov
Дата добавления: 2015-11-13
Сергей, вы внимательно читали урок? Смысл урока: не надо для каждого объекта отдельно код писать! Надо механизм взаимодействия объектов описать в ассоциативном массиве (obj), а потом в цикле обработать этот массив. Вот в этом весь смысл! А если у вас будет 1000 объектов, то вы и для каждого объекта из 1000 отдельный код писать будете? Это глупо, согласитесь. Ещё раз вчитайтесь в урок, пожалуйста.

Контейнер, в данном случае, это просто мувиклип, внутри которого сложены все другие объекты-мывиклипы. Этот мувиклип-контейнер имеет имя container. Вроде, логично.
Комментатор
Комментарий добавил(а): Сергей
Дата добавления: 2015-11-13
Простите не сумел вставить код полностью!:((((
У меня не получается сделать так, что бы конкретный мувиклип можно перетащить в определенную область.Я создал 5 мувиков(red_mc, blue_mc, yellow_mc, green_mc, pink_mc) и 5 пустых (hit_mc_1, hit_mc_2, hit_mc_3, hit_mc_4,hit_mc_5). Мне нужно, что бы red_mc можно перетащить было только на hit_mc_3 и т.п. И как создается контейнер? Буду рад Вашему ответу. Спасибо!

[code]red_mc.addEventListener(MouseEvent.MOUSE_DOWN, fl_ClickToDrag);
function fl_ClickToDrag(event:MouseEvent):void
{
red_mc.startDrag();
}
stage.addEventListener(MouseEvent.MOUSE_UP, fl_ReleaseToDrop);
function fl_ReleaseToDrop(event:MouseEvent):void
{
red_mc.stopDrag();
}
blue_mc.addEventListener(MouseEvent.MOUSE_DOWN, fl_ClickToDrag2);
function fl_ClickToDrag2(event:MouseEvent):void
{
blue_mc.startDrag();
}
stage.addEventListener(MouseEvent.MOUSE_UP, fl_ReleaseToDrop2);
function fl_ReleaseToDrop2(event:MouseEvent):void
{
blue_mc.stopDrag();
}
pink_mc.addEventListener(MouseEvent.MOUSE_DOWN, fl_ClickToDrag3);
function fl_ClickToDrag3(event:MouseEvent):void
{
pink_mc.startDrag();
}
stage.addEventListener(MouseEvent.MOUSE_UP, fl_ReleaseToDrop3);
function fl_ReleaseToDrop3(event:MouseEvent):void
{
pink_mc.stopDrag();
}
yellow_mc.addEventListener(MouseEvent.MOUSE_DOWN, fl_ClickToDrag4);
function fl_ClickToDrag4(event:MouseEvent):void
{
yellow_mc.startDrag();
}
stage.addEventListener(MouseEvent.MOUSE_UP, fl_ReleaseToDrop4);
function fl_ReleaseToDrop4(event:MouseEvent):void
{
yellow_mc.stopDrag();
}
green_mc.addEventListener(MouseEvent.MOUSE_DOWN, fl_ClickToDrag5);
function fl_ClickToDrag5(event:MouseEvent):void
{
green_mc.startDrag();
Комментатор
Комментарий добавил(а): edapskov
Дата добавления: 2015-11-13
Сергей, а зачем вы пишите код для каждого объекта в отдельности? Я же показал в примере: вся информация хранится в ассоциативном массиве; проходимся по этому массиву в цикле и ... всё.
Комментатор
Комментарий добавил(а): Сергей
Дата добавления: 2015-11-13
Здравствуйте! Огромное спасибо Вам за сайт! Очень интересно! Но мне как новичку в скриптах пока очень многое не понятно. Если можно - помогите в моем вопросе.У меня не получается сделать так, что бы конкретный мувиклип можно перетащить в определенную область.Я создал 5 мувиков(red_mc, blue_mc, yellow_mc, green_mc, pink_mc) и 5 пустых (hit_mc_1, hit_mc_2, hit_mc_3, hit_mc_4,hit_mc_5). Мне нужно, что бы red_mc можно перетащить было только на hit_mc_3 и т.п.

Что нужно изменить в коде:
red_mc.addEventListener(MouseEvent.MOUSE_DOWN, fl_ClickToDrag);

function fl_ClickToDrag(event:MouseEvent):void
{
red_mc.startDrag();
}

stage.addEventListener(MouseEvent.MOUSE_UP, fl_ReleaseToDrop);

function fl_ReleaseToDrop(event:MouseEvent):void
{
red_mc.stopDrag();
}

blue_mc.addEventListener(MouseEvent.MOUSE_DOWN, fl_ClickToDrag2);

function fl_ClickToDrag2(event:MouseEvent):void
{
blue_mc.startDrag();
}

stage.addEventListener(MouseEvent.MOUSE_UP, fl_ReleaseToDrop2);

function fl_ReleaseToDrop2(event:MouseEvent):void
{
blue_mc.stopDrag();
}

pink_mc.addEventListener(MouseEvent.MOUSE_DOWN, fl_ClickToDrag3);

function fl_ClickToDrag3(event:MouseEvent):void
{
pink_mc.startDrag();
}

stage.addEventListener(MouseEvent.MOUSE_UP, fl_ReleaseToDrop3);

function fl_ReleaseToDrop3(event:MouseEvent):void
{
pink_mc.stopDrag();
}
yellow_mc.addEventListener(MouseEvent.MOUSE_DOWN, fl_ClickToDrag4);

function fl_ClickToDrag4(event:MouseEvent):void
{
yellow_mc.startDrag();
}

stage.addEventListener(MouseEvent.MOUSE_UP, fl_ReleaseToDrop4);

function fl_ReleaseToDrop4(event:MouseEvent):void
{
yellow_mc.stopDrag()
Комментатор
Комментарий добавил(а): edapskov
Дата добавления: 2014-01-28
В obj описано какой объект с каким взаимодействуют:

1.) красный квадрат и пятиугольник реагируют только на серый круг;

2.) красный круг реагирует только на серый квадрат.

Если требуется другое поведение, то изменяем obj.
Комментатор
Комментарий добавил(а): Xme1ez
Дата добавления: 2014-01-28
Подскажите, я все сделал в новом документе, ошибок не выдает - работает, но есть одно но, почему красный объект при перемещении его на серый контейнер он в него не помещается, а возвращается на прежнее место?
Комментатор
Комментарий добавил(а): edapskov
Дата добавления: 2014-01-28
Контейнером , в данном примере, является MovieClip, созданный вручную на сцене флеш-ролика. А контейнером называется потому, что внутри него располагаются все другие MovieClip-ы, используемые в данном примере.
Комментатор
Комментарий добавил(а): Xme1ez
Дата добавления: 2014-01-28
Подскажите, что такое контейнер и как его добавить?
Комментатор
Комментарий добавил(а): edapskov
Дата добавления: 2013-12-15
Причина, скорее всего, другая: если между курсором и перетаскиваемым объектом лежит ещё какой-то объект, то функция onMouseUpFunc может и не сработать. Чтобы этого не случалось стоит все перетаскиваемые объекты помещать на самый верхний уровень (см.: http://edapskov.ru/pages.php?id=245 ).
Комментатор
Комментарий добавил(а): Алексей
Дата добавления: 2013-12-15
Видимо какая то разница есть. Если у меня целевой объект закрыт другим объектом, то отпускание кнопки мыши на нем просто не срабатывает. Объект не прилипает при отпускании и остается прилипшим к курсору.
Добавить комментарий:







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

Идиот-тест

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

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