Beware of Class/Namespace Duplication in Unity Windows Games

I recently had some trouble building the Windows Store version of my upcoming game, Clowntraptions. I was getting the bizarre error below:

Image

‘Window’ is a standard class in WinRT (Windows.UI.Xaml.Window), and this error was troubling! I couldn’t build the project let alone deploy and test it. What was wrong?

I had a script in my Unity project called ‘Window’ holding a class called, of course, ‘Window’. This conflicted with the Visual Studio code that referenced a different ‘Window’ class.

So I renamed the class in my Unity project to something else and those errors went away. The class in question was actually a part of a plugin, so I wasn’t really to blame, and the plugin creator can’t be blamed for inadvertently using the same name as a Windows RT class.

Relieved, I rebuilt from Unity, opened up my game in Visual Studio, and hit the debug button to have a play test…and instead of my awesome circus game I got this before the game even managed to get past the splash screen:

Image

Sigh. The web build was working fine, and more notably the Windows Phone 8 build was working fine…so what was causing this issue in the Windows Store build (and it was an untouched, fresh build with no extra code or plugins added in – straight from Unity). Was it a problem with the recent Unity 4.5 update? I tried everything…and was on the verge of filing a bug report…but then I had another look at my code and realised I’d made the exact same mistake I’d only just repaired. I’d created my own script a few days prior, and called it ‘Notifications’, which Visual Studio got confused with ‘Windows.UI.Notifications’. I renamed my script and class to something different and, Hey Presto! My build was then successful.

So if you come across weird errors like above in Unity projects that work on other platforms, make sure you don’t have any poorly named classes that clash with existing Windows classes.

To avoid these mistakes:

  • Keep your scripts organised in folders (and subfolder if required) so they are easy to browse through.
  • Give your scripts/classes descriptive names (avoid single words).
  • Make good use of namespaces in your project.

Detecting when the On-screen Keyboard is Active

When your Windows 8/8.1 app is running on a tablet and accepting keyboard input there is a fair chance that the software on-screen keyboard is being used. This is all well and good, except that the on-screen keyboard can take up a huge amount of screen real estate, especially in landscape mode (around 50% of the screen!).

So to make sure your app still works well with half of the screen taken up by a keyboard you should detect the on-screen keyboard just as you would check for other ways your app’s size on screen could change (e.g. snapping, switching between portrait and landscape, etc.).

It’s very easy to do. You just add handlers to detect when the keyboard goes up and down:


AddHandler InputPane.GetForCurrentView.Showing, AddressOf KeyboardUp
AddHandler InputPane.GetForCurrentView.Hiding, AddressOf KeyboardDown

Now when the keyboard is raised the KeyboardUp method will be called, and when the keyboard goes down your KeyboardDown method will be called. In these methods you can make any necessary changes to the UI to suit the different screen layout, e.g.:


Private Sub KeyboardUp()
 ' make the main grid row shorter
 LayoutRoot.MainGridRow.Height = New GridLength(100)
End Sub

Private Sub KeyboardDown()
 ' return the main grid row to full height
 LayoutRoot.MainGridRow.Height = New Gridlength(300)
End Sub

And if you make full use of view states you can of course trigger a completely different view for when the keyboard is up!

Adjust your Windows 8.1 App’s Layout when the Screen Size Changes

Windows 8.1 has a new model for how much screen real estate apps can use. In Windows 8.0 your app could be in one of four states (landscape full screen, landscape ‘filled’, landscape snapped, and portrait full screen).

In Windows 8.1, app size can be changed to any size the user chooses (though the developer can set the minimum size), so your apps need to cope with unexpectedly having their size (specifically width) changed at any time.

Detecting a Screen Layout Change

All you need to be able to do to manage your app’s layout is detect whenever your app’s on-screen width changes, and then adjust the layout in whatever ways you need to in order to fit your app into its new size.

To detect when your app’s on-screen size changes you need to add a handler to notify your app. But this isn’t enough, because if you change the screen size and then navigate to a new page the new page will not detect the change in width because it happened while you were on the previous page. So you also need to check the screen size when your app navigates to a page.
So the things we need to add to our pages are:
  • A way to detect the current screen width
  • A method to alter the page UI layout to suit the current width
  • A way to detect when the screen width changes.

Detect the Current Screen Width

currentScreenWidth = Me.Frame.ActualWidth

Me.Frame.ActualWidth gives you the current width of your app on the screen. It’s that easy!

Alter the Page Layout to Suit the Current Width

Once you have the current screen width you can make any needed adjustments to your UI based on that information. The specific changes depend on your app, but a method like the following is what you need:

Private Sub ChangeScreenLayout(newWidth As Integer)
    If (newWidth <= 600) Then
        LeftMargin.Width = New GridLength(25)
        RightMargin.Width = New GridLength(25)
    Else
        LeftMargin.Width = New GridLength(120)
        RightMargin.Width = New GridLength(120)
    End If
End Sub

The above code is just the tip of the iceberg – you can of course run all kinds of modifications on your UI to suit the new screen size, and you can have as many different layouts as your app needs. In this example we will just change the margins in the app page so that when the app is less than 600 pixels wide the margins get a bit slimmer to ensure enough content fits on the page.

Detect when the Screen Width Changes

Your pages need to know when to adjust their layout to match the screen width. You need to use two different approaches:

  • Detect the screen size when a page is first navigated to
  • Detect when the current page size changes.

As you may have figured out from the code already mentioned, the first approach simply calls the ChangeScreenLayout method using the current screen width as the newWidth value. Just place the following method into your page to run the ChangeScreenSize method whenever the page is loaded:

Public Sub Page_Loaded() Handles Me.Loaded
    ChangeScreenLayout(Me.Frame.ActualWidth)
End Sub

The other approach is to detect when the screen width changes.  To achieve this add an event handler to detect the Window.Current.SizeChanged event, and within the event handler run the ChangeScreenLayout method. Add the following code to the OnNavigatedTo method:

AddHandler Window.Current.SizeChanged, AddressOf Current_SizeChanged

then add a method to call when the event is detected:

Private Sub Current_SizeChanged(sender As Object, e As Windows.UI.Core.WindowSizeChangedEventArgs)
    ChangeScreenLayout(e.Size.Width)
End Sub

One More Thing

Because you added a handler (to detect the screen size change) when the page is navigated to, you need to remove that handler when the page is navigated from. Add the following method to your page:

Protected Overrides Sub OnNavigatedFrom(e As NavigationEventArgs)
    MyBase.OnNavigatedFrom(e)
    RemoveHandler Window.Current.SizeChanged, AddressOf Current_SizeChanged
End Sub

That’s everything. Add the above code to your page(s), then customise the code for rearranging your own UI.