Monthly Archives: December 2015

Working with the threading system in Unity

Unity seems to have a multi-threaded system, but I could find no way of accessing the dispatcher. Consequently, it’s necessary to create some kind of self-rolled task queue. The specific problem that I faced was with using the timer; here’s the code for the timer:

public class MasterScript : MonoBehaviour
{
    private Timer _timer;

    void Start ()
    {
        _timer = new Timer();
        _timer.Interval = 1000;
        _timer.Elapsed += _timer_Elapsed;
        _timer.Start();
    }

    private void _timer_Elapsed(object sender, ElapsedEventArgs e)
    {
        SpawnNewObject();
    }
}

The idea being that every second, and new object would appear on the screen. However, as soon as you run this, it crashes (or as close as Unity comes to crashing):

FindGameObjectWithTag can only be called from the main thread

The solution that I came up with was as follows:

public class MasterScript : MonoBehaviour
{
    public static Queue<Action> TaskQueue;

    private void _timer_Elapsed(object sender, ElapsedEventArgs e)
    {
        SpawnNewObject();
    }

    private void SpawnNewObject()
    {
        TaskQueue.Enqueue(() =>
        {
            var newObj = Instantiate<GameObject>(MyObject);

Then, simply change the Update function to run them:

    void Update ()
    {
        if (TaskQueue.Count > 0)
        {
            TaskQueue.Dequeue().Invoke();
        }
    }

I’ve used the idea of a “Master Script” to deal with the queue, and this can be queued to from somewhere else in the game, which makes it more flexible.

Advancing to the next Level in Unity

I’m quite new to Unity, and so thought I would start blogging useful things that I’ve discovered. Obviously, there is the which is basically where all this information comes from, and also an excellent tutorial on YouTube. I found this after trying a Pluralsight course on Unity, but rapidly losing the will to live while watching it.

In my particular example, I have a game, whereby touching a specific object progresses to the next level. Here’s the code (against the target object):

    void OnCollisionEnter()
    {
        if (Application.loadedLevel < Application.levelCount)
            Application.LoadLevel(Application.loadedLevel + 1);
        
    }

I admit, it’s not exactly rocket science, but it took me a while to work this out. I spent some time trying to parse the level name, and other workarounds, before I spotted that it’s all in the Application object.

Deleting Files in a Storage Folder Using UWP

Just a little helper method that I used in a recent project to delete files, given a particular name, and excluding a provided list of files:

        internal static async Task DeleteTempFiles(ObservableCollection<StorageFile> exceptionFiles, StorageFolder folder, string fileNameStartsWith)
        {
            var files = (await folder.GetFilesAsync())
                .Where(p => p.DisplayName.StartsWith(fileNameStartsWith)
                && !exceptionFiles.Any(e => e.DisplayName == p.DisplayName));            

            foreach(var file in files)
            {
                await file.DeleteAsync(StorageDeleteOption.Default);                
            }
        }

You can call it like this:

	await FileHelper.DeleteTempFiles(Files, KnownFolders.PicturesLibrary, "_tmpFile");

It will delete all files in the Pictures folder starting with _tmpFile, and exclude anything in the Files collection.

InkCanvas

Pointlessly Long Introduction (feel free to skip)

Some time ago, in a previous job, I was asked to add spell checking to a WPF textbox. I did some research as to how to do that, and came to the conclusion that the only way was using MS Word automation. I must have spent a good three or four hours writing code that interrogated Word and performed spell checking. It wasn’t until I got to auto correct that one of my searches threw up a property on the text box: “SpellCheck.IsEnabled”.

(At the time of writing) I recently attended a developer conference, and at it, I was shown a control called InkCanvas! Having recently spent a considerable amount of time trying to use a Canvas for drawing, I felt like I’d just found the SpellCheck.IsEnabled property again.

Using the InkCanvas Control

In comparison to the Canvas, the InkCanvas basically works out of the box. If you use the InkToolbar with it, you’ll get some errors, but they aren’t actually errors; for example:

1>C:\Program Files (x86)\MSBuild\14.0\bin\Microsoft.Common.CurrentVersion.targets(2048,5): warning MSB3781: The SDK “InkToolbarControl, Version=0.3.2” depends on the following SDK(s) “Microsoft.VCLibs, version=14.0”, which have not been added to the project or were not found. Please ensure that you add these dependencies to your project or you may experience runtime issues. You can add dependencies to your project through the Reference Manager.

Here’s the XAML that I used to get it working. Don’t be phased by the fact that x:Bind doesn’t seem to resolve.

            <InkCanvas x:Name="drawInkCanvas">                    
            </InkCanvas>
            <inkTools:InkToolbar TargetInkCanvas="{x:Bind drawInkCanvas}" 
                                PenColor="#FFE61021" 
                                VerticalAlignment="Top" HorizontalAlignment="Right"/>

Enabling Input

I found only one thing that caused confusion, and it took a while to solve. Basically, the above XAML doesn’t allow you to actually draw anything; you need this:

        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            base.OnNavigatedTo(e);

            drawInkCanvas.InkPresenter.InputDeviceTypes =
                Windows.UI.Core.CoreInputDeviceTypes.Mouse |
                Windows.UI.Core.CoreInputDeviceTypes.Pen |
                Windows.UI.Core.CoreInputDeviceTypes.Touch;

        }

Saving the Image

To save what you’ve drawn, you can use something similar to this code:

            if (canvas != null && canvas.InkPresenter.StrokeContainer.GetStrokes().Count > 0)
            {
                if (file != null)
                {
                    using (IRandomAccessStream stream = await file.OpenAsync(FileAccessMode.ReadWrite))
                    {
                        await canvas.InkPresenter.StrokeContainer.SaveAsync(stream);
                    }
                }
                Clear(canvas);
            }

Generating a Temporary Filename in Windows 10 Universal App

It appears that the functionality to create a temporary file was omitted from Windows 8 / 10

If anyone knows this to not be the case then please add a comment to that effect.

Consequently, I decided to create a little helper method:

        public static async Task<StorageFile> CreateTempFile(
                 StorageFolder folder, string extension)
        {
            string fileName = string.Empty;

            while (true)
            {
                // Get a random filename
                fileName = string.Format("{0}.{1}", 
                     Guid.NewGuid().ToString(), extension);

                // Check if it already exists
                IReadOnlyList<StorageFile> fileList =
                    await folder.GetFilesAsync();

                // If it does then loop until we have a unique one
                if (!fileList.Any(f => f.DisplayName == fileName)) break;
            }

            var newFile = await folder.CreateFileAsync(fileName);
            return newFile;
        }

WPF Drawing Application

The following is a XAML page that allows the user to draw on it. This was written and tested under a Windows 10 desktop application, but should work for WPF. Here’s the XAML:

        <Grid>
            <Border>
                <Canvas PointerPressed="Canvas_PointerPressed" PointerMoved="Canvas_PointerMoved"
                        PointerReleased="Canvas_PointerReleased"
                        Background="Orange" Name="Canvas" />
            </Border>
        </Grid>

The background is a different colour to identify the canvas.

There’s the code to allow drawing:

        
        Path _currentPath;

        private void Canvas_PointerPressed(object sender, Windows.UI.Xaml.Input.PointerRoutedEventArgs e)
        {            
            _currentPath = new Path
            {
                Data = new PathGeometry
                {
                    Figures = { new PathFigure
                    {
                        StartPoint = e.GetCurrentPoint((UIElement)sender).Position,
                        Segments = { new PolyLineSegment() }
                    }}
                },
                Stroke = new SolidColorBrush(Colors.Black),
                StrokeThickness = 5
            };

            Canvas.Children.Add(_currentPath);
        }

        private void Canvas_PointerMoved(object sender, PointerRoutedEventArgs e)
        {
            if (_currentPath == null) return;

            var pls = (PolyLineSegment)((PathGeometry)_currentPath.Data).Figures.Last().Segments.Last();
            pls.Points.Add(e.GetCurrentPoint((UIElement)sender).Position);
            
        }

        private void Canvas_PointerReleased(object sender, PointerRoutedEventArgs e)
        {
            _currentPath = null;
        }

As you can see, it doesn’t do anything for my drawing ability:

drawing

It’s all the code behind and, while I typically shy away from this, it seems to fit well for an application such as this (as the drawing relates more to the view than to anything else).