tags:

views:

188

answers:

3

Hello, I am working on a program for the mapping and playing of the popular tabletop game D&D :D Right now I am working on getting the basic functionality like dragging UI elements around, snapping to the grid and checking for collisions.

Right now every object when released from the mouse immediately snaps to the nearest grid point. This causes an issue when something like a player object snaps to a grid point that has a wall -or other- adjacent. So essentially when the player is dropped they wind up with some of the wall covering them. This is fine and working as intended, however the problem is that now my collision detection is tripped whenever you try to move this player because its sitting underneath a wall and because of this you cant drag the player anymore.

Here is the relevant code:

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);
                }
            }
        }

Essentially I am looking for a simple way to modify the existing code to allow the movement of a UI element that has another one sitting on top of it. Thanks!

A: 

Why not include the cases in which you would like to still be able to move the objects in your collision detection code. I am thinking of simple if statements in the collision detection code. I can't tell you mroe without seeing the collision detection code.

Also, what sets/changes "blocked"?

sbenderli
VisualTreeHelper.HitTest(o, null, new HitTestResultCallback(MyHitTestResultCallback), ghtp);Is the collision detection code, the MyHitTestResultCallback method sets "blocked" if a collision is found.
FlyingStreudel
So why not add the conditions there in MyHitTestResultCallback?
sbenderli
I am hoping for a more elegant solution than hardcoding the edge cases. Also, how are you envisioning these 'simple if statements'? You would need to keep track of if the obj was in some sort of initial move state and if so collect the objects it was currently colliding with and ignore them in future collision detection until it had moved outside the bounds of the objects geometry. Then you would have to dump those objects from the collection of objects to ignore. However if one of my characters is snapped to a gridpoint also containing a wall, they would now be able to move through this wall.
FlyingStreudel
A: 

If a wall tile overlaps an adjacent cell and this causes a collision to trigger, then you should use smaller collision shapes, which don't overlap.

Ideally the collision shapes should be exactly the size of the occupied grid cell(s), independent of the visual appearance, right?

Staffan E
A: 

I'd just like to take a moment to propose an alternate solution...
Use an existing well-tested implementation: MapTool!

Of course, this solution is useless if you particularly need or want to implement it yourself (definitely a fun personal project), but I figure it should be mentioned. 8 )

Task
Unfortunately work has prevented me from making any more progress on my project for the time being :( But this tool looks perfectly suited for me needs, thanks!
FlyingStreudel
I assure you, it IS perfectly suited to the task at hand! I've, uh, 'tested it' many times myself! Perhaps its best feature is that it handles remote play really well.
Task