Алгоритм перетаскивания объектов на фиксированную сетку - PullRequest
3 голосов
/ 17 июня 2010

Я работаю над программой для картирования и игры популярной настольной игры D & D: D Сейчас я работаю над получением базовой функциональности, такой как перетаскивание элементов пользовательского интерфейса, привязка к сетке и проверка на столкновения.

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

Вот соответствующий код:

void UIObj_MouseMove(object sender, MouseEventArgs e)  
{  
            blocked = false;  
            if (dragging)  
            {  
                foreach (UIElement o in ((Floor)Parent).Children)  
                {  
                    if (o.GetType() != GetType() && o.GetType().BaseType == typeof(UIObj) &&  
                        Math.Sqrt(Math.Pow(((UIObj)o).cX - cX, 2) + Math.Pow(((UIObj)o).cY - cY, 2)) <  
                        Math.Max(r.Height + ((UIObj)o).r.Height, r.Width + ((UIObj)o).r.Width))  
                    {  
                        double Y = e.GetPosition((Floor)Parent).Y;  
                        double X = e.GetPosition((Floor)Parent).X;  
                        Geometry newRect = new RectangleGeometry(new Rect(Margin.Left + (X - prevX),  
                        Margin.Top + (Y - prevY), Margin.Right + (X - prevX), Margin.Bottom + (Y - prevY)));  
                        GeometryHitTestParameters ghtp = new GeometryHitTestParameters(newRect);  
                        VisualTreeHelper.HitTest(o, null, new HitTestResultCallback(MyHitTestResultCallback), ghtp);  
                    }  
                }  
                if (!blocked)  
                {  
                    Margin = new Thickness(Margin.Left + (e.GetPosition((Floor)Parent).X - prevX),  
                        Margin.Top + (e.GetPosition((Floor)Parent).Y - prevY),  
                        Margin.Right + (e.GetPosition((Floor)Parent).X - prevX),  
                        Margin.Bottom + (e.GetPosition((Floor)Parent).Y - prevY));  
                    InvalidateVisual();  
                }
                prevX = e.GetPosition((Floor)Parent).X;  
                prevY = e.GetPosition((Floor)Parent).Y;  
                cX = Margin.Left + r.Width / 2;  
                cY = Margin.Top + r.Height / 2;  
            }  
        }  

internal virtual void SnapToGrid()  
        {  
            double xPos = Margin.Left;  
            double yPos = Margin.Top;  
            double xMarg =  xPos % ((Floor)Parent).cellDim;  
            double yMarg =  yPos % ((Floor)Parent).cellDim;  
            if (xMarg < ((Floor)Parent).cellDim / 2)  
            {  
                if (yMarg < ((Floor)Parent).cellDim / 2)  
                {  
                    Margin = new Thickness(xPos - xMarg, yPos - yMarg, xPos - xMarg + r.Width, yPos - yMarg + r.Height);
                    }  
                else  
                {  
                    Margin = new Thickness(xPos - xMarg, yPos - yMarg + ((Floor)Parent).cellDim, xPos - xMarg + r.Width,

                        yPos - yMarg + ((Floor)Parent).cellDim + r.Height);  
                }  
            }  
            else  
            {
                if (yMarg < ((Floor)Parent).cellDim / 2)
                {
                    Margin = new Thickness(xPos - xMarg + ((Floor)Parent).cellDim, yPos - yMarg,
                        xPos - xMarg + ((Floor)Parent).cellDim + r.Width, yPos - yMarg + r.Height);
                }
                else
                {
                    Margin = new Thickness(xPos - xMarg + ((Floor)Parent).cellDim, yPos - yMarg + ((Floor)Parent).cellDim,
                        xPos - xMarg + ((Floor)Parent).cellDim + r.Width, yPos - yMarg + ((Floor)Parent).cellDim + r.Height);
                }
            }
        }

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

Ответы [ 3 ]

0 голосов
/ 05 июля 2010

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

В идеале формы столкновений должны точно соответствовать размеру занятых ячеек сетки, независимо от внешнего вида, верно?

0 голосов
/ 06 июля 2010

Я просто хотел бы воспользоваться моментом, чтобы предложить альтернативное решение ...
Используйте существующую хорошо протестированную реализацию: MapTool!

Конечно, это решение бесполезно, если вам особенно нужно или вы хотите реализовать его самостоятельно (безусловно, интересный личный проект), но я полагаю, что его стоит упомянуть. 8)

0 голосов
/ 30 июня 2010

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

Кроме того, что устанавливает / изменяет «заблокировано»?

...