Contribute on GitHub

Generating and Loading UI Sprite Sheets

Introduction

Sprites are two-dimensional images that are mostly used in the user interface of a game. Sprite sheets are the collection of such images. In other words, sprites are packed together to form a sprite sheet. This documentation will go through the following steps:

Prerequisites

Adding Sprites

Generating Sprite Sheets

In order to generate sprite sheets, run the TaleWorlds.TwoDimension.SpriteSheetGenerator.exe executable file located at INSTALLATION_PATH\Mount & Blade II Bannerlord\bin\Win64_Shipping_wEditor. If you have followed the steps above, after running SpriteSheetGenerator.exe, you should see the following window:

SpriteSheetGenerator.exe will create two folders named Assets and AssetSources under Modules\YOUR_MODULE_NAME. It will also create a SpriteData.xml file (with a prefix of your module name) under Modules\YOUR_MODULE_NAME\GUI.

Importing Created Sprite Sheets

In order to use the sprites in your sprite sheets, you should also import them from the resource browser. Follow these steps to import a sprite sheet:

This should open the resource browser:

Collapse the folder named Native on the left of the resource browser to see your module easily. Then, select your module.

Open the GauntletUI folder in your module. Then, press the “Scan new asset files” button which is pointed with a red arrow below (arrow on the right).

This should open a new window:

Make sure your category is selected (in the example, it is ui_mycategory) then press the Import button. Then, you should see something similar to this:

Close the resource browser and the game. You should now see a new file named ui_{YOUR_CATEGORY_NAME}_1_tex.tpac under Modules\YOUR_MODULE_NAME\Assets\GauntletUI.

Using Sprites In UI XML Files

You may now use the sprites in the sprite sheets that you have created (you also need to load the corresponding category which is explained below, in the Loading & Unloading Sprite Categories section). Sprites are used in UI XML files. You may refer to your sprites with their names. You can find the names of your sprites in the SpriteData.xml file (with a prefix of your module name) which is located at Modules\YOUR_MODULE_NAME\GUI. To give an example, we will create a new UI XML file. To do that, go back to the folder named GUI under Modules\YOUR_MODULE_NAME\ and create a new folder named Prefabs. Create a new file named MyXml.xml under the Prefabs folder. You may now refer to your sprites in this file as Sprite=“mysprite”. For example, the content of the MyXml.xml file could be:

<Prefab>
    <Window>
        <Widget DoNotAcceptEvents="true" DoNotPassEventsToChildren="true" WidthSizePolicy="StretchToParent" HeightSizePolicy="StretchToParent">
            <Children>
                <ImageWidget WidthSizePolicy="Fixed" HeightSizePolicy="Fixed" SuggestedWidth="128" SuggestedHeight="128" HorizontalAlignment="Center" VerticalAlignment="Center" Sprite="mysprite"/>
            </Children>
        </Widget>
    </Window>
</Prefab>

Loading & Unloading Sprite Categories

In order to use the sprites that you have added, you need to load them. In the example below, we override the OnGameStart and OnGameEnd methods of MBSubModuleBase class to add and remove the MyScreen global layer respectively. Notice that the constructor of MyScreen loads the sprite category and the UI XML that we have created in previous sections. We also unload the sprite category inside the OnFinalize method.

If you are going to copy the below code, do not forget to change the namespace and name of the Main function. They should match with the fields in your SubModule.xml. In other words, you should change SpritesheetDocumentation (namespace) to YOUR_MODULE_NAME and Main (name of the Main function) to YOUR_MAIN_FUNCTION_NAME in this field of the SubModule.xml:

<SubModuleClassType value="YOUR_MODULE_NAME.YOUR_MAIN_FUNCTION_NAME"/>

Otherwise, they won’t be recognized and the game will crash while launching.

using TaleWorlds.Core;
using TaleWorlds.MountAndBlade;
using TaleWorlds.Engine.Screens;
using TaleWorlds.Engine.GauntletUI;
using TaleWorlds.GauntletUI.Data;
using TaleWorlds.TwoDimension;

namespace SpritesheetDocumentation
{
    public class Main : MBSubModuleBase
    {
        private MyScreen _myScreen;

        protected override void OnSubModuleLoad()
        {

        }

        protected override void OnGameStart(Game game, IGameStarter gameStarterObject)
        {
            base.OnGameStart(game, gameStarterObject);
            _myScreen = new MyScreen();
            ScreenManager.AddGlobalLayer(_myScreen, true); // add MyScreen on game start
        }

        public override void OnGameEnd(Game game)
        {
            base.OnGameEnd(game);
            _myScreen.OnFinalize();
            ScreenManager.RemoveGlobalLayer(_myScreen); // remove MyScreen on game end
        }
    }

    public class MyScreen : GlobalLayer
    {
        private GauntletLayer _gauntletLayer;
        private IGauntletMovie _gauntletMovie;
        private SpriteCategory _category;

        public MyScreen()
        {
            var spriteData = UIResourceManager.SpriteData;
            var resourceContext = UIResourceManager.ResourceContext;
            var resourceDepot = UIResourceManager.UIResourceDepot;

            _category = spriteData.SpriteCategories["ui_mycategory"]; // select which category to load, put your category name here
            _category.Load(resourceContext, resourceDepot); // load the selected category

            _gauntletLayer = new GauntletLayer(2);
            Layer = (ScreenLayer)_gauntletLayer;

            _gauntletMovie = _gauntletLayer.LoadMovie("MyXml", null); // load the ui xml in Prefabs folder
        }

        public void OnFinalize()
        {
            // unload ui xml, sprite category, layer, etc.
            _gauntletMovie = null;
            _category.Unload();
            _gauntletLayer = null;
        }
    }
}

Conclusion