Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WP7: Suppressing XNA touch input when handled by Silverlight?

I've got an XNA + Silverlight game in Mango: Mostly XNA with some Silverlight UI on top. The problem I'm having is that when you hit a button or interact with a Silverlight control, the touch information is still passed along to the XNA game loop. How do you suppress this?

like image 611
RandomEngy Avatar asked Jul 28 '11 16:07

RandomEngy


1 Answers

Wrote up a class to do the tracking for me. After your page loads (in the Loaded handler), create this and give it the root element (so it can attach to the LayoutUpdated event). Register any controls that might overlay the game surface during play. Then just call TouchesControl and pass in the touch position to find out if you should ignore that point or not. It caches the regions of the controls and updates them when there's a layout update.

Should work for rectangular elements moving, changing size or collapsing/expanding.

public class ControlTouchTracker
{
    private List<FrameworkElement> controls = new List<FrameworkElement>();
    private Dictionary<FrameworkElement, ControlRegion> controlBounds = new Dictionary<FrameworkElement, ControlRegion>();

    public ControlTouchTracker(FrameworkElement rootElement)
    {
        rootElement.LayoutUpdated += this.OnLayoutUpdated;
    }

    public void RegisterControl(FrameworkElement control)
    {
        controls.Add(control);
    }

    public void RemoveControl(FrameworkElement control)
    {
        controls.Remove(control);
        controlBounds.Remove(control);
    }

    private void OnLayoutUpdated(object sender, EventArgs e)
    {
        foreach (Control control in this.controls)
        {
            this.RefreshControlBounds(control);
        }
    }

    private void RefreshControlBounds(FrameworkElement control)
    {
        if (this.ControlIsVisible(control))
        {
            try
            {
                GeneralTransform controlTransform = control.TransformToVisual(Application.Current.RootVisual);
                Point offset = controlTransform.Transform(new Point(0, 0));

                this.controlBounds[control] = new ControlRegion
                {
                    Left = (float)offset.X,
                    Right = (float)(offset.X + control.ActualWidth),
                    Top = (float)offset.Y,
                    Bottom = (float)(offset.Y + control.ActualHeight)
                };
            }
            catch (ArgumentException)
            {
            }
        }
        else
        {
            if (this.controlBounds.ContainsKey(control))
            {
                this.controlBounds.Remove(control);
            }
        }
    }

    private bool ControlIsVisible(FrameworkElement control)
    {
        // End case
        if (control == null)
        {
            return true;
        }

        if (control.Visibility == Visibility.Collapsed)
        {
            return false;
        }

        return this.ControlIsVisible(control.Parent as FrameworkElement);
    }

    public bool TouchesControl(Vector2 touchPosition)
    {
        foreach (ControlRegion region in this.controlBounds.Values)
        {
            if (touchPosition.X >= region.Left && touchPosition.X <= region.Right &&
                touchPosition.Y >= region.Top && touchPosition.Y <= region.Bottom)
            {
                return true;
            }
        }

        return false;
    }

    public class ControlRegion
    {
        public float Left { get; set; }
        public float Right { get; set; }
        public float Top { get; set; }
        public float Bottom { get; set; }
    }
}

(edit) Updated example to work with parent elements changing Visibility.

like image 122
RandomEngy Avatar answered Sep 30 '22 12:09

RandomEngy