Monthly Archives: January 2014

Detecting multiple gesture types using Monogame in Windows 8

Gestures in this environment are hard. Ridiculously hard. There is a ReadGesture function, but it doesn’t work. Let’s imagine that you want to detect the following gestures:

Tap
Double Tap
Drag

Not exactly complex. We’ll need to know some basic information about each gesture:

Tap: where have we tapped
Double tap: where have we double tapped (and that the two taps are in the same location)
Drag: the start and end positions of the drag.

Let’s have a look at some code:

     
TouchPanel.EnabledGestures =
GestureType.FreeDrag | GestureType.DragComplete | GestureType.DoubleTap | GestureType.Tap;

while (TouchPanel.IsGestureAvailable)
{
    GestureSample gs = TouchPanel.ReadGesture();
    switch (gs.GestureType)
    {
        case GestureType.FreeDrag:
            System.Diagnostics.Debug.WriteLine(string.Format("FreeDrag: {0}", gs.Position));
            break;

        case GestureType.DragComplete: 
            System.Diagnostics.Debug.WriteLine(string.Format("DragComplete: {0}", gs.Position));

            break;

        case GestureType.DoubleTap:
            System.Diagnostics.Debug.WriteLine("DoubleTap");

            break;

        case GestureType.Tap:
            System.Diagnostics.Debug.WriteLine("Tap");

            break;

    }
}

So, let’s run this and see what we get. We certainly get all the gestures. However, there are the following issues:

    1. The DragComplete doesn’t provide any information at all, other than the fact that the drag isn’t taking place anymore

    2. The drag works in bursts, so you get many drag events for a single drag

    3. The Tap event fires, but a Double Tap doesn’t replace the Tap, so you get both.

There’s a bit of rolling-your-own here. Let’s start with the drag, because it’s actually the easiest problem to solve. We know when the use finishes dragging, so a simple variable to say that they are dragging and where they started will solve most of this problem:

    private Vector2? dragStart = null;

Why is it nullable? Well, this variable stores two separate states: whether the user is dragging, and where they started.

Next, we need to know where they were last (if anyone from Microsoft ever reads this, please feel free to give a detailed description in the comments why this hoop jumping is necessary!):

    private Vector2? lastPosition = null;

Then we need to store and check these variables; here’s the new section of the switch statement:

    case GestureType.FreeDrag:
                                System.Diagnostics.Debug.WriteLine(string.Format("FreeDrag: {0}", gs.Position));
                        
        if (!dragStart.HasValue)
        {
            dragStart = gs.Position;
        }
        
        lastPosition = gs.Position;
            break;

       case GestureType.DragComplete:                    

           System.Diagnostics.Debug.WriteLine(string.Format("DragComplete: {0}", gs.Position));
                       
           if (dragStart.HasValue)
           {
               var gsDragDelta = lastPosition - dragStart.Value;
               if (gsDragDelta.Value.LengthSquared() > DRAG_TOLERANCE)
               {
                   if (gsDragDelta.Value.X != 0 || gsDragDelta.Value.Y != 0)
                   {
                       dragStart = null;
                       // Do stuff on drag complete
                       break;

That handles the drag. Next, the tap. Handling the Tap is easy, but what if, as I did, you want to handle Tap to do one thing, and Double Tap to do another? This fried my brain for a while; then something occurred to me. What if you delay the action:

    
    case GestureType.DoubleTap:    
        dblTap = true;
        // Do stuff on Double tap                  
        System.Diagnostics.Debug.WriteLine("DoubleTap");
        Task.Delay(100).ContinueWith((args) => { dblTap = false; });
        break;

    case GestureType.Tap:
        Task.Delay(100).ContinueWith((args) =>
        {
            if (!dblTap)
            {
                // DO stuff on Tap                
                System.Diagnostics.Debug.WriteLine("Tap");
            }
        });
        break;

I imagine the delay needs to be experimented with. 100ms seems to work for me.

As usual, if you have any suggestions, comments, or ways to do this better then please leave a comment.

List Workspaces with no outstanding pending changes

This question originally came up as a StackOverflow Question. Basically, the problem was, how can I tell which of my workspaces are now unused. If you work in a single workspace then this may not be an issue; however, if you have an automated tool that interacts with TFS, you may find it’s constantly creating new workspaces and not cleaning up after itself.

The code for a simple console app is below:


    class Program
    {
        static private TfsTeamProjectCollection _tfs;

        static void Main( string[] args)
        {
            _tfs = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(new Uri("https://myUri.com" ));

            var service = _tfs.GetService< VersionControlServer>();
            Workspace[] ws = service.QueryWorkspaces( null, null, null);

            foreach( Workspace s in ws)
            {
                var pend = s.GetPendingChanges();
                if (pend.Count() == 0)
                {
                    Console.WriteLine( "Workspace {0} has no pending changes" , s.Name);
                    // s.Delete()
                    continue;
                }
            }

        }
    }

Obviously change the URI. I’ve commented out the Delete() command, and I strongly recommend that you check what it intends to delete before you let it go.

My intention is to make this into a Codeplex project at some point, and I’ll update this post if I do so. Please feel free to make recommendations for other TFS functions that you might like to see in such a project.

UPDATE:

I did manage to create that project; it’s here:

https://tfsutilities.codeplex.com/

Beware: asynchrony with monogame

The async / await keywords allow asynchrony extremely easily in comparison to previous implementations; however, this blog post is a word of caution for those working with monogame or XNA in general.

Imagine the following update method:

                try
                {
                    spriteBatch.Begin( SpriteSortMode.Deferred, BlendState.AlphaBlend);                   
                    await UpdateMySprites(spriteBatch);
                    await HandleInput();
                }
                finally
                {
                    spriteBatch.End();
                }

Okay, so this is spot on: where `UpdateMySprites` takes some time, it won’t stall execution… except that it will.

Why?

Because of the way `async` works. What the await function actually does is create a continuation block, which includes:

    spriteBatch.End();

As a result, the screen is not drawn until the slow function finishes (whether the function should be that slow at this part of the code is another matter).

So, how to fix? Well, one option is to simply not await the functions. You can prevent yourself from doing that by not making the Update function `async`. You can still call asynchronous functions from a non-async method, but you can’t await them. The compiler will give you a warning and, to be honest, it’s probably not the best practice (you pay in your ability to work out exactly what state your program is in).

Another option is to make this method synchronous; and, where it needs to be asynchronous, use a background worker.

Conclusion

Although it seems straightforward (at least it does if you understand async), this did take me a while to work out. Hopefully it’ll save you that time.

Games are not the same as apps and utilities. Although many things may occur at the same time, you really need to know what all of those things are and exactly what position or state they are in; maybe using asynchrony in game development in a bad idea.

Add a settings file from another project (VB.NET)

I recently asked this question on Stack Overflow and, although the answer I got was correct, I thought I would write it up so that a clearer explanation was available for when I forget that I asked in the first place.

Here’s the link to the SO question (as I certainly wouldn’t want to claim credit for the solution): http://stackoverflow.com/questions/20427328/sharing-settings-file-between-projects-in-vs2013

I believe that the process for C# is different, and will try to cover that in a future post.

Disclaimer

If you do read the question, you’ll see that it was suggested to create the settings file in a single library and then expose that through a public method. I do agree that this would be the best way to do things. I’m not even saying that the way here is a good way to do things. However, I was in a position where it was the only feasible way to do things, given time constraints and project architecture. I intend, in the future, the refactor, and to have just such a library of settings. If you have time do do this now, or if you haven’t yet created your settings file then I would strongly suggest you go down this route and NOT read on.

Otherwise, read on

Okay, if you’re still reading then you’re either in the same position I was, or you didn’t read the disclaimer.

Adding a Settings file as a link

In the project that you wish to add the settings file, first, delete any existing settings files from inside (or outside) the “My Project” folder. Note that by default, “Show All Files” is turned off, and this can hide the “My Project Folder”, so make sure it’s on:

ShowAllFiles

MySettings

Now that’s deleted, selected the project and select “Add Existing Item”, and in the dialog that appears, find your settings file; then, and this is the important part, select “Ass as Link”:

AddAsLink

Okay, now you have a settings file from another project. Now you need to set the namespace and the custom tool. They should look like this:

SettingsSettings

Finally, you need to manually tell the settings file to generate itself by right-clicking, and selecting “Run Custom Tool”.

Conclusion and Caveat

One of the reasons that this is a bad idea is the last step. Although you are linking to the settings file, you need to manually generate each time.

So, it’s not a good way to do things, but if you need it, it does work.