Программируем на Monogame. Часть 2. Настройка проекта. Content Pipeline

Напомню, что Monogame в текущей версии не умеет самостоятельно работать с Content Pipeline. То есть можно использовать готовые, скомпилированные xnb файлы, но сам процесс работы с контентом в monogame пока нельзя назвать удобным.

В этой статье мы посмотрим, как можно настроить проект таким образом, чтобы работа с контентом была более удобной.

Создаем проект, например, обычный Windows Store проект.

Вот, что вы должны увидеть в Solution Explorer.

Сразу видно, что в решении нет проекта с контентом, который мы привыкли видеть в XNA.

Как я уже написал выше, monogame умеет работать со скоспилированными xnb файлами, именно этим мы и воспользуемся.

Но для начала скомпилируем и запустим проект, мы должны будем увидеть вполне ожидаемый синий экран. Это означает, что все пока идет хорошо. На этом этапе мы уже видим особенности Monogame для Windows Store. Еще до синего экрана вы должны были увидеть splash screen, который присутствует во всех приложениях Windows Store.

В проекте мы также увидим файлы, которые необходимы приложению для работы с Windows Store, главным образом это файл Package.appxmanifest, в котором мы будем настраивать различные параметры приложения: название, описание, картинки для тайлов, разрешения и т.д.

Но теперь приступим к загруке контента.

Для этого создадим в проекте папку Content, дабавим в нее нужные нам xnb файлы и установим для них нужные настройки:

Build Action -> Content

Copy to Output Directory -> Copy if newer (или Copy always).

Теперь загрузим картинку (а нащ xnb файл на самом деле является картинкой) и нарисуем ее.

Если взглянуть на код в Game1.cs, то не трудно заметить, что он практически повторяет код, к которому мы привыкли по XNA.

public class Game1 : Game
    {
        GraphicsDeviceManager _graphics;
        SpriteBatch _spriteBatch;

        Texture2D tex;

        public Game1()
        {
            _graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            // TODO: Add your initialization logic here

            base.Initialize();
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            _spriteBatch = new SpriteBatch(GraphicsDevice);

            // TODO: use this.Content to load your game content here
            tex = Content.Load<Texture2D>("walls");
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            // TODO: Add your update logic here

            base.Update(gameTime);
        }

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            // TODO: Add your drawing code here
            _spriteBatch.Begin();
            _spriteBatch.Draw(tex, Vector2.Zero, Color.White);
            _spriteBatch.End();

            base.Draw(gameTime);
        }
    }

Теперь на экране будет такая картина:

Отлично, теперь мы убедились, что Monogame умеет работать с xnb файлами, созданными в XNA Content Project. В принципе, можно просто добавлять все xnb файлы в проект описанным выше способом, но, пожалуй, это не слишком удобно.

Дабивим в решение новый проект

На самом деле добавятся сразу два проекта. Content проект, и обычный XNA проект, который будет компилировать содержимое Content проекта.

В свойствах получившихся проектов лучше поставить нужную конфигурацию. Поставим Windows8.

Теперь будем добавлять содержимое в Content проект.

Обратите внимание на то, что мы снова можем управлять всеми свойствами Content Processor`ов, что очень хорошо. Если скомпилировать проект, который у меня называется GameName1, то в папку bin попадут xnb файлы, которые мы можем вручную добавить в основной проект, как это описано выше.

Но это снова неудобно. Так что перейдем к свойствам проекта GameName1 и сделаем следующие настройки:

Впишем в Post-build event command line следующую строку:

xcopy /q /y «$(ProjectDir)$(OutDir)Content» «$(SolutionDir)ContentTest\Content»

Теперь все скопмилированные файлы будут копироваться в наш основной проект ContentTest. На картинке видно, что xnb файлы попали в папку Content.

Внимание. Данная команда работает только с файлами размещенными в корне контент проекта. Чтобы учитывались и подпапки ее придется изменить. (можно просто добавить по новой строчке для каждой подпапки)

Теперь мы можем присоединить полученные xnb файлы в проект, но может сделать это и автоматически.

Для этого откроем файл ContentTest.csproj и напишем в нем следующие строки в нужный ItemGroup:

<Content Include=»Content\*»>

<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>

</Content>

Получится вот так:

<ItemGroup>

<AppxManifest Include=»Package.appxmanifest»>

<SubType>Designer</SubType>

</AppxManifest>

<None Include=»ContentTest_TemporaryKey.pfx» />

<Content Include=»Content\*»>

<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>

</Content>

</ItemGroup>

Все, теперь содержимое папки Content будет подключаться к проекту автоматически.

Убедимся, что все работает

public class Game1 : Game
    {
        GraphicsDeviceManager _graphics;
        SpriteBatch _spriteBatch;

        Texture2D texLeft;
        Texture2D texRight;

        public Game1()
        {
            _graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            // TODO: Add your initialization logic here

            base.Initialize();
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            _spriteBatch = new SpriteBatch(GraphicsDevice);

            // TODO: use this.Content to load your game content here
            texLeft = Content.Load<Texture2D>("handleft");
            texRight = Content.Load<Texture2D>("handright");
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            // TODO: Add your update logic here

            base.Update(gameTime);
        }

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            // TODO: Add your drawing code here
            _spriteBatch.Begin();
            _spriteBatch.Draw(texLeft, Vector2.Zero, Color.White);
            _spriteBatch.Draw(texRight, new Vector2(200,0), Color.White);
            _spriteBatch.End();

            base.Draw(gameTime);
        }
    }

Будем надеяться, что в следующей версии Monogame будет более простой способ работы с контентом, ну а пока можно использовать метод, который я описал в этой статье.

Реклама
Запись опубликована в рубрике Компьютерная графика с метками , , , , , . Добавьте в закладки постоянную ссылку.

Добавить комментарий

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход / Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход / Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход / Изменить )

Google+ photo

Для комментария используется ваша учётная запись Google+. Выход / Изменить )

Connecting to %s