Jump to content
  • 0

Подскажите алгоритм


psywalker
 Share

Question

Всем привет!

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

Условия:

Допустим подводим мышку к самому верхнему прямоугольнику, номер 1. Жмём и не отпуская мышь, ведём прямоугольник чётко вниз (движение вверх пока не пашет), не сворачивая)). Если делать это медленно, то во-время прохождения нашего прямоугольника над нижними, они как и должны поднимаются вверх, как бы освобождая пространство для нашего перетаскиваемого объекта. Это мне удалось.

Но проблема в следующем. Когда делаешь это быстро (опускаешь мышь, держа "номер 1"), то некоторые прямоугольники не расходятся, потому что видимо тупо не успевают сообразить, что к чему (т.к. походу интервал ещё не успел запустить один, а мы уже около другого), и алгоритм даёт сбои.

Алгоритм:

На данный момент остановился на самом лучшем, который смог придумать. В общем у каждого кирпича есть свойство kirpich.top = 52, где 52 - это его верхний отступ от верхнего края самого контейнера с кирпичами.

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

			var top = 0;
for(var i = 0; i < bricks.length; i++){
if(elementActiveTop - wrapTop > bricks[i].brick.top && !bricks[i].brick.flugOuter){

var el = bricks[i].brick;
top = el.top;


}
}

if(top+35 >= elementActiveTop - wrapTop && top < elementActiveTop - wrapTop){

var x = el.top;
var y = el.top - brickH - brickMargin;
el.top = el.top - brickH - brickMargin;
el.left = 0;
bricks[0].line(0,x,0,y,el,-1);

}

Задача:

Нужно придумать чёткий, качественный алгоритм, который позволит задаче выполнить свои условия на 100% и при быстром перетаскивании не будет тупить.

Перепробовал уже многое, как только не придумывал, но все идеи приходилось сворачивать и бросать в урну. :facepalmxd:

Ссылка на пример

p.s. Пока интересует движение только вниз. Вверх я хочу потом сделать по аналогии. И остальной код к делу не относится, он чисто для перетаскивания и функцией для передвижения кирпичей, которой пофиг на всё, она просто ждёт кирпич в качестве аргумента.

Link to comment
Share on other sites

10 answers to this question

Recommended Posts

  • 0

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

http://jqueryui.com/demos/sortable/#placeholder

Ну, а алгоритм, я вижу такой. У каждого блока есть высота (он занимает какую-то область) если блок который двигается заходит в область соседнего блока(скажем на 80%) то сосед должен освободится место, а блок который освобождает место должен перейти на на место соседа(которое пустует)... Таким образом получается что нам нужно следить за областями блоков (двигаемся мы лишь по оси y так что работа упрощается).

Касательно переноса объектов вот не плохой пример http://javascript.ru/ui/draganddrop#indikaciya-perenosa-nad-obektom

Edited by stars
Link to comment
Share on other sites

  • 0

stars,

Спасибо, но это не то.

1) Там блоки не передвигаются плавно, а просто меняются местами. Это важно!

2) Это джиквери, а мне нужно на чистом ЖС.

3) А вообще делаю это задание для само-образования и опыта. Так что тут дело принципа.

Link to comment
Share on other sites

  • 0

Ну вот как бы сделал я. Положим, имеем N кирпичей с айдишниками (классами, чем угодно, лишь бы уникальные идентификаторы были). Пусть они зовутся от br1, br2, ..., brN. Нам надо их таскать туда-сюда.

1. Создаём массив a[1..N], каждому элементу в соответствие проставлен номер кирпича. Для начала пусть они стоят по порядку. То есть будет массив вида array(1=>1, 2=>2, ..., N=>N)

2. Высота кирпича будет равна M.

3. Берём какой-нибудь кирпич. Пусть первый. Тогда a[1]=0.

4. пусть y=координата от верхней точки. Соответственно, если берём не первый кирпич, то не a[1], а a[floor(y/M)]=0

5. Тащим кирпич. if (a[floor(y/M)]!=0), то проверяем элементы сверху и снизу. В зависимости от того где у нас ноль, туда и двигаем элемент. То есть, по сути, получается, что, если верхняя граница двигаемого кирпича налезла на какой-нибудь кирпич, то этот кирпич сдвигается на свободное место.

Тут получается, что мы избавлены от цикла (идёт прямое обращение по ключу) ну и алгоритму пофиг куда двигается кирпич — вверх или вниз.

Link to comment
Share on other sites

  • 0

Veseloff,

Вот это уже интереснее дружище.

1) Только не понял кое что. Допустим высота кирпичей 50px, координата первого от верха (y) - 0px; Если мы берём первый кирпич и тянем вниз, то что происходит?

2) a[floor(y/M)]=0 - а вот это почему равно 0?

3)

Тащим кирпич. if (a[floor(y/M)]!=0),

Т.е. тащим и во время движения проверяем сверху вниз и без цикла?

4)

В зависимости от того где у нас ноль, туда и двигаем элемент.

В смысле?

А не мог бы ты рассказать обо всём поподробнее плиз :rolleyes:

Link to comment
Share on other sites

  • 0

Где-то читал, что часто в играх на JS используют вместо setInterval два setTimeout, т.к. setInterval может начать следующую итерацию до того как закончится предыдущая, а setTimeout начнёт следующую только после того как закончена предыдущая..

Надеюсь это поможет..

Link to comment
Share on other sites

  • 0

1) Только не понял кое что. Допустим высота кирпичей 50px, координата первого от верха (y) - 0px; Если мы берём первый кирпич и тянем вниз, то что происходит?

2) a[floor(y/M)]=0 - а вот это почему равно 0?

3)

Тащим кирпич. if (a[floor(y/M)]!=0),

Т.е. тащим и во время движения проверяем сверху вниз и без цикла?

4)

В зависимости от того где у нас ноль, туда и двигаем элемент.

В смысле?

Ну вот давай на более живом примере. Вот есть у нас 4 кирпича по 50 пикселей высотой. Стоят они по порядку: 1, 2, 3, 4.


t=0 // это временная переменная, заполним только на время перетаскивания
N=4 // Количество кирпичей
M=50 // Высота кирпича
a=array(1=>1, 2=>2, 3=>3, 4=>4) // Массив, в котором храним информацию о расположении кирпичей

Допустим, мы потянем третий кирпич наверх. Берём кирпич — пока ещё никуда не переместили, просто кликнули. Его координата y=150. floor(y/M)=floor(150/50)=3. То есть, исходя из координат, мы выясняем, что тянем мы именно третий элемент. В переменную t запишем то, что у нас хранится в a[3], то есть «3», а в a[3] запишем «0», так как сейчас это место у нас пустует. Тянем его наверх. Он переместился на 1 пиксель вверх, наступило событие, чтобы вызвать функцию проверки кирпичей. Сейчас координата иаскаемого кирпича = 149. Выясним над каким же кирпичом у нас сейчас занесён таскаемый. floor(y/M)=floor(149/50)=2, то есть на вторым. Проверим что у нас там на втором месте. a[2] имеет значение «2», то есть там второй кирпич. Значит, надо его куда-то подвинуть. Смотрим наверх. a[1]==1, то есть там есть кирпич, значит, не получится туда подвинуть. a[3]==0, то есть нам надо туда перекинуть второй кирпич. a[3]=a[2], a[2]=0. Снова двигаем кирпич на 1 пиксель вверх. Он имеет координаты 148. Снова вычисляем, что это второй элемент, но a[2]==0, так что никуда нчиего двигать не будем. И тут мы его и бросим. a[2]=t. В итоге имеем такой массив a=array(1=>1, 2=>3, 3=>2, 4=>4). Ну и по анаглогии также можно двигать вверх. Само собой, добавляем проверку, чтобы не проверять элементы, если y>=M*N или y<=0.

  • Like 1
Link to comment
Share on other sites

  • 0

Veseloff, Дружище, спасибо. А я теперь попробую сказать, а ты меня поправь, если что.

У нас есть переменные:


var t = сюда мы будем записывать номер кирпича, который мы тащим?


var a = [];
a[0] = кирпич 1
a[1] = кирпич 2
a[2] = кирпич 3
a[3] = кирпич 4

- Отчёт начинается ведь с 0, да?

- А что мы храним в каждом номере массива?

Допустим мы просто пока взяли кирпич 3, и держим на месте. Проверяем значит, y=150. floor(y/M)=floor(150/50)=3.

- Т.е. y - это расстояние начинается от верхней границы кирпича, да?

- И в этот момент мы узнали, что взяли именно кирпич 3. Записываем это число в переменную t, и теперь t=3, да?

а в a[3] запишем «0»

А запишем куда? В какое то свойство просто?

Он переместился на 1 пиксель вверх, наступило событие, чтобы вызвать функцию проверки кирпичей. Сейчас координата таскаемого кирпича = 149. Выясним над каким же кирпичом у нас сейчас занесён таскаемый. floor(y/M)=floor(149/50)=2, то есть на вторым.

А почему 2? Ведь по сути таскаемый кирпич занесён над своим же пустым полем ещё? 149?

Смотрим наверх. a[1]==1, то есть там есть кирпич, значит, не получится туда подвинуть. a[3]==0,

- Т.е. мы узнаём, у какого кирпича спец. свойство == 0?

то есть нам надо туда перекинуть второй кирпич. a[3]=a[2], a[2]=0.

- Ааа, т.е. мы меняем местами массивы, да?

Link to comment
Share on other sites

  • 0

В массиве a хранятся номера кирпичей с первого по последний. Вот так:

a[1] = 1
a[2] = 2
a[3] = 3
a[4] = 4

Ключ массива — номер позиции по порядку. Элемент массива — номер кирпича. Соответственно, если мы поменяем второй и третий кирпичи местами, то массив будет иметь такой вид:

a[1] = 1
a[2] = 3
a[3] = 2
a[4] = 4

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Answer this question...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue. See more about our Guidelines and Privacy Policy