Skip to main content

Using XAML on Monogame for WinRT (Part 2)

Integrating Monogame with XAML Metro UI

If you're coming from the previous section, you now have a metro UI application project with blank page and also have monogame.windows8 library reference to the project. Now Let's fix some source code for the  pages to get XAML working with monogame.

Step01 ( Hacking App.xaml.cs file)

App.xaml.cs delivers the most important start point while rendering a particular page in Metro UI application.

I added gamePage and mainPage as  a public variables as they become accessible from other classes to for page nagivations. Here is the source code for to see what it looks like for the final App.xaml.cs file.


sealed partial class App : Application
    {
        public ContentManager Content { get; set; }
        public GameServiceContainer Services { get; set; }
        public GamePage gamePage;
        public MainPage mainPage;

        public Frame RootFrame { get; set; }

        /// <summary>
        /// Initializes the singleton application object.  This is the first line of authored code
        /// executed, and as such is the logical equivalent of main() or WinMain().
        /// </summary>
        public App()
        {
            this.InitializeComponent();
            this.InitializeXNA();
            this.Suspending += OnSuspending;
        }

        private void InitializeXNA()
        {
            // Create the service provider
            Services = new GameServiceContainer();

            // Add the graphics device  manager.
            Services.AddService(typeof(IGraphicsDeviceService), new SharedGraphicsDeviceManager());

            // Create the ContentManager so the application can load precompiled assets
            Content = new ContentManager(Services, "GameAssets");
            Content.RootDirectory = "Content";
        }

        /// <summary>
        /// Invoked when the application is launched normally by the end user.  Other entry points
        /// will be used when the application is launched to open a specific file, to display
        /// search results, and so forth.
        /// </summary>
        /// <param name="args">Details about the launch request and process.</param>
        protected override void OnLaunched(LaunchActivatedEventArgs args)
        {
            // Do not repeat app initialization when already running, just ensure that
            // the window is active
            if (args.PreviousExecutionState == ApplicationExecutionState.Running)
            {
                Window.Current.Activate();
                return;
            }

            if (args.PreviousExecutionState == ApplicationExecutionState.Terminated)
            {
                //TODO: Load state from previously suspended application
            }

            // Create a Frame to act navigation context and navigate to the first page
            var rootFrame = new Frame();
            if (!rootFrame.Navigate(typeof(MainPage)))
            {
                throw new Exception("Failed to create initial page");
            }

            //Create a new game page
            gamePage = new GamePage();

            // Place the frame in the current Window and ensure that it is active
            Window.Current.Content = rootFrame;
            Window.Current.Activate();
        }

        /// <summary>
        /// Invoked when application execution is being suspended.  Application state is saved
        /// without knowing whether the application will be terminated or resumed with the contents
        /// of memory still intact.
        /// </summary>
        /// <param name="sender">The source of the suspend request.</param>
        /// <param name="e">Details about the suspend request.</param>
        private void OnSuspending(object sender, SuspendingEventArgs e)
        {
            var deferral = e.SuspendingOperation.GetDeferral();
            //Data.UlozData();

            //TODO: Save application state and stop any background activity
            deferral.Complete();
        }
    }



Step02 ( Modifying MainPage.xaml.cs)

I added a new button inside MainPage.xaml using Editor and named it btnStartGame. The following code illustrate how to store mainPage reference so it can be accessed from the game page too. It also implements the navigation to actual game page which actuall doesn't use page frame as it's base method.


public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            //Store reference of this page for the app
            ((App)App.Current).mainPage = this;

            this.Loaded += MainPage_Loaded;
            this.InitializeComponent();
        }

        void MainPage_Loaded(object sender, RoutedEventArgs e)
        {
        }

        /// <summary>
        /// Invoked when this page is about to be displayed in a Frame.
        /// </summary>
        /// <param name="e">Event data that describes how this page was reached.  The Parameter
        /// property is typically used to configure the page.</param>
        protected override void OnNavigatedTo(NavigationEventArgs e)
        {

        }

        private void btnStartGame_Click(object sender, RoutedEventArgs e)
        {
             //Navigate to Game Page
            var gamePage = ((App)App.Current).gamePage;

            Window.Current.Content = gamePage;
            Window.Current.Activate();
        }
    }

Step03 ( Fixing the GamePage.xaml file)

Now let's create a new blank page called GamePage.xaml and in the .xaml source file add the following SwapChainBackgroundPanel to its source file


<SwapChainBackgroundPanel  x:Class="MonoGameAndXAML.GamePage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:MonoGameAndXAML"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"  >
    <Button x:Name="btnBack" Content="Go Back" HorizontalAlignment="Left" Margin="562,326,0,0" VerticalAlignment="Top" Click="btnBack_Click"/>
</SwapChainBackgroundPanel>

Step04 ( Finalising the GamePage.xaml.cs file)

GamePage.xaml.cs takes place the rendering stuffs for the monogame framework. If you're familiar with XNA framework, it won't be difficult at all to port your XNA game for WinRT platform. Here is the final source of rendering the background image using monogame framework and a button using actual WinRT Metro UI. You can request the complete source code and project folder via facebook message @
https://www.facebook.com/pages/Game-Development-Resources/147251618745857



public sealed partial class GamePage : SwapChainBackgroundPanel
    {
        GameTimer gameTimer;
        SharedGraphicsDeviceManager manager;
        Vector2 screenSizePixel;
        ContentManager content;
        bool loaded = false;
        SpriteBatch spriteBatch;

        Texture2D Back_Menu;

        public GamePage()
        {
            this.Loaded += MainPage_Loaded;
            this.Unloaded += GamePage_Unloaded;

            this.InitializeComponent();
        }

        void GamePage_Unloaded(object sender, RoutedEventArgs e)
        {
            UnloadContent();
        }

        void MainPage_Loaded(object sender, RoutedEventArgs e)
        {
            if (!loaded)
            {
                manager = SharedGraphicsDeviceManager.Current;
                manager.PreferredBackBufferWidth = (int)this.ActualWidth;
                manager.PreferredBackBufferHeight = (int)this.ActualHeight;
                manager.SwapChainPanel = this;
                manager.ApplyChanges();

                gameTimer = new GameTimer();
                gameTimer.UpdateInterval = TimeSpan.FromTicks(166666); // Variable frame rate

                gameTimer.Update += OnUpdate;
                gameTimer.Draw += OnDraw;

                this.SizeChanged += GamePage_SizeChanged;
                this.LostFocus += GamePage_LostFocus;
                this.GotFocus += GamePage_GotFocus;

                screenSizePixel = new Vector2((int)this.ActualWidth, (int)this.ActualHeight);
                LoadContent();

                loaded = true;
            }
        }

        private void LoadContent()
        {
            spriteBatch = new SpriteBatch(SharedGraphicsDeviceManager.Current.GraphicsDevice);
            content = ((App)App.Current).Content;

            Back_Menu = content.Load<Texture2D>(@"Backgrounds/Back_Game");
            gameTimer.Start();
        }

        private void UnloadContent()
        {
            Debug.WriteLine("Unloading contents");
            gameTimer.Stop();
        }


        void GamePage_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            screenSizePixel = new Vector2((int)this.ActualWidth, (int)this.ActualHeight);

            manager.PreferredBackBufferWidth = (int)screenSizePixel.X;
            manager.PreferredBackBufferHeight = (int)screenSizePixel.Y;
            manager.ApplyChanges();
        }

        void GamePage_LostFocus(object sender, RoutedEventArgs e)
        {
        }

        void GamePage_GotFocus(object sender, RoutedEventArgs e)
        {
        }

        //Game Draw
        private void OnDraw(object sender, GameTimerEventArgs e)
        {
            SharedGraphicsDeviceManager.Current.GraphicsDevice.Clear(Color.Gray);

            //Render the background
            spriteBatch.Begin();
                spriteBatch.Draw(Back_Menu, new Vector2(0, 0), Color.White);
            spriteBatch.End();
        }

        //Game Update
        private void OnUpdate(object sender, GameTimerEventArgs e)
        {
        }

        //Goback to main page when the back button is pressed
        private void btnBack_Click(object sender, RoutedEventArgs e)
        {
            var mainPage = ((App)App.Current).mainPage;

            Window.Current.Content = mainPage;
            Window.Current.Activate();
        }
    }



You can request the source code project for this tutorial using facebook message. More tutorials will coming through for monogame WinRT and also Unity 3D game engine.

Play battle tank game online free @http://www.tankrivals.com/
Check out more organised blog posts @ http://gamesdevtutors.com/

Comments

  1. Any idea why I am getting this error:
    An exception of type 'System.IO.FileNotFoundException' occurred in MonoGameAndXAML.exe but was not handled in user code

    ReplyDelete
  2. which version of Visual Studio do you use to build the project? It should be on VS 2012 over Windows 8 Release Preview. And How do u actually try to run it? Did u try to run inside the VS project or actual .exe file?

    ReplyDelete
  3. Vs2012 in windows 8
    runing inside vs in simulater

    ReplyDelete
  4. oops.. that's weird.. I haven't face down this kind of problems before. Can you try installing the visual studio from the scratch as it may cause because of missing files.

    ReplyDelete
  5. following the instructions I'm getting a 'xamlMG.GamePage does not contain a definition of InitializeComponent. Any ideas?

    ReplyDelete
    Replies
    1. This comment has been removed by the author.

      Delete
    2. in GamePage.xaml
      you have to set
      x:Class="MonoGameAndXAML.GamePage"
      to
      x:Class="(your_project_namespace).GamePage"

      Delete
  6. Have you tried using the example full-source project?

    ReplyDelete
  7. Awesome. Thanks for the tutorial. Very easy to follow!

    ReplyDelete

Post a Comment

Popular posts from this blog

Optimising Unity new UI System

UI/Sprite textures aren't packed into a texture atlas by default. A tag is needed to group them. Read the documentation / tutorial on the sprite packer.Overlapping text/graphic boundaries with another text/graphic will create additional draw calls, even if the actual visual graphics do not overlap.Grids (other layouts too I presume) need minimum 1 pixel spacing between items, else items are considered overlapping and will create additional draw calls.Images with alpha 0 are still rendered. They are rendered with alpha 0 even though they are not seen.Unity currently does not support non-rectangle shapes as Sprites, so using the TightSpitePacker policy will cause image artifacts.When UI objects are offscreen, they are still batched (rendered as well?). Possible solutions:Change parent to non-UI parent, as UI Camera will no longer detect itChange layer of panel so UI Camera will no longer detect itDisable gameobject when off-screenScrollRect performance tuningScrollRect will rebuild …

Steps to add IAP for Unity iOS and publishing steps

Adding IAP
Create a new app ID and create a new app using that ID on apple connectAdd IAP and make sure that screenshots are provided to get the IAP in Ready to Submit state.To test IAP on test account, you need to wait between 12-24 hours to make the product available to test.
App installation failed, Could not write to the device
Restart your iphone and xcode.Sometimes restart Mac or build 3-4 timesIf you have another device such as iPad, build and run for that device and then run it back with previous device again
Building to device
Export XCode project from Unity as usual.Create new development certificate for building into the deviceMark automatic code signing if you're in development and testing the appSelect your team in the provision profile

Note : If you're using onesignal, make sure you also select your team in targets in onesignal project as well.

Publishing to appstore
Create distribution profile for app and download itUncheck automatic code signing and use the downloa…

Modifying apk file manifest file using apk tool

https://www.technologywindow.com/edit-android-applications-using-apktool/ Step 01 - Install frameworkd for apk file apktool if appname.apk Step 02 - Decompile apk file apktool d appname.apk Step 03 - Fixed androidmanifest.xml file if needed Step 04 - Build apk file from the folder and your new apk file is at appname/dist folder apktool b appname Step 05 - Sign apk file with keystore jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore MREEnglish.keystore mre_english.apk mre-english Step 06 - Align apk file to be able to upload to playstore again cd C:\Program Files (x86)\Android\android-sdk\build-tools\28.0.3\ zipalign -f -v 4 mre_english_64bit-signed.apk "D:\mre_english_64bit-signed-aligned.apk"