Опубликован: 05.08.2010 | Уровень: специалист | Доступ: платный
Самостоятельная работа 1:

Компьютерная 2D-графика в Microsoft XNA Game Studio 3.0

Самостоятельная работа 1: 12345678910 || Самостоятельная работа 2 >

Добавление звуковых эффектов

Звуковое сопровождение игры является ее неотъемлемым элементом и украшает игру. Прежде всего нужно приготовить все звуковые файлы. Потом загрузить их как объекты в проект игры и далее управлять средствами библиотеки XNA этими звуковыми объектами.

Для нашей игры мы добавим два звуковых эффекта. Один звук будет проигрываться в момент касания платформы и падающего объекта, второй звук запустится, когда объект упадет "в никуда".

  • В проводнике решений выделите узел Content проекта и добавьте к нему командой меню Project/New Folder новую папку с именем Sound
  • В проводнике решений выделите папку Sound и скопируйте в нее командой меню Project/Add Existing Item из прилагаемого к работе каталога Source файлы platform.wav и boom.wav

  • Через проводник решений Solution Explorer выделите в папке Sound скопированные в проект звуковые файлы и в панели Properties установите для них атрибуты компилятора оболочки, как показано на рисунке


Код управления звуком упакуем в отдельный класс.

  • В проводнике решений выделите корневой узел проекта Game2d и добавьте в проект командой Project/Add New Item меню оболочки новый класс C# с именем Sound

Поскольку звук в системе только один, то для управления им (и для тренировки) создадим статический класс. В соответствии с теорией языка C# статическом классе все поля данных и методы должны быть статическими и используется только конструктор по умолчанию.

  • Заполните статический класс Sound следующим кодом
using System;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
    
namespace Game2D
{
    // Перечисление
    enum SoundList
    {
        Platform,   // Поймали
        Boom        // Промазали
    }
    
    static class Sound
    {
        static SoundEffect boom;
        static SoundEffect platform;
    
        public static void Load(ContentManager content)
        {
            boom = content.Load<SoundEffect>("Sound\\boom");
            platform = content.Load<SoundEffect>("Sound\\platform");
        }
    
        // Воспроизведение звука
        public static void Play(SoundList sound)
        {
            switch (sound)
            {
                case SoundList.Boom:
                    boom.Play();
                    break;
                case SoundList.Platform:
                    platform.Play();
                    break;
            }
        }
    }
}
  • Вставьте использование класса Sound в соответствующие методы основного класса игры StartGame
public class StartGame : Microsoft.Xna.Framework.Game
    {
        ............................................
    
        protected override void LoadContent()
        {
            ........................................
    
            // Загружаем звук 
            Sound.Load(this.Content);
        }
       
        // Функция перемещения сверху вниз на величину speedSprite
        void MoveSprite()
        {
            for (int i = 0; i < sprite.Length; i++)
            {
                sprite[i].spritePosition += sprite[i].speedSprite;
                if (sprite[i].spritePosition.Y > this.Window.ClientBounds.Height)
                {
                    // Сброс координат следующего прохода в начальную точку
                    ...............................................
    
                    // Звукнуть плохо
                    Sound.Play(SoundList.Boom);
                }
            }
        }
        
        void Collisions()
        {
            ...............................................
    
            // Проверка пересечений ограничивающих прямоугольников
            // летящих объектов с каймой платформы и реакция на них
            for (int i = 0; i < bbSprite.Length; i++)
            {
                if (bbPlatform.Intersects(bbSprite[i]))
                {
                    // Сброс координат следующего прохода в начальную точку.
                    // То же, что в методе MoveSprite(), только по другой причине
                    int minValue = 10;
                    int maxValue = this.Window.ClientBounds.Width - 300
                         - sprite[i].spriteTexture.Width / 12;
                    sprite[i].spritePosition = new Vector2(
                        rand.Next(minValue, maxValue), -300);
    
                    // Подсчет очков по сумме столкновений с объектами
                    scores[i]++;
    
                    // Звукнуть хорошо
                    Sound.Play(SoundList.Platform);
                }
            }
        }
    }
  • Перекомпилируйте проект командой Rebuild и испытайте добавленный в игру звук

Добавление суммы очков

Добавим на табло общее количество очков, набранных игроком в текущей игре.

  • Добавьте в класс StartGame поле целого типа totalScores, а в метод Collisions() подсчет суммы очков
int totalScores;
        void Collisions()
        {
            .................................................
    
            // Проверка пересечений ограничивающих прямоугольников
            // летящих объектов с каймой платформы и реакция на них
            for (int i = 0; i < bbSprite.Length; i++)
            {
                if (bbPlatform.Intersects(bbSprite[i]))
                {
                    ....................................................
    
                    // Подсчет очков по сумме столкновений с объектами
                    scores[i]++;
                    totalScores++;
    
                    // Звукнуть хорошо
                    Sound.Play(SoundList.Platform);
                }
            }
        }
  • Добавьте в метод NewGame() сброс суммы очков
// Новая игра
        void NewGame()
        {
            // Сброс очков
            for (int i = 0; i < scores.Length; i++)
                scores[i] = 0;
            totalScores = 0;
    
            // Начальные позиции объектов
            this.Initialize();
        }
  • В методе Draw() вставьте код печати суммы очков на экране
protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);
    
            // Рисуем меню
            if (menuState)
            {
                spriteBatch.Begin(SpriteBlendMode.AlphaBlend);
                menu.DrawMenu(spriteBatch, buttonState);
                mouse.DrawSprite(spriteBatch);
                spriteBatch.End();
            }       
            else    ////////////// else ////////////////
            {
                spriteBatch.Begin(SpriteBlendMode.AlphaBlend);
                spriteBatch.Draw(background1, new Vector2(0, 0), Color.White);
                for (int i = 0; i < sprite.Length; i++)
                    sprite[i].DrawAnimationSprite(spriteBatch);
                spriteBatch.Draw(background2, new Vector2(0, 0), Color.White);
                platform.DrawSprite(spriteBatch);// В верхний слой над тросом 
                // Вывод текста
                if (paused)
                {
                    spriteBatch.DrawString(font2,
                        "Пауза в игре!",
                        new Vector2(350, 100),
                        Color.Red);
                }
                int shift = 248;
                for (int i = 0; i < 5; i++)
                {
                    spriteBatch.DrawString(font1,
                        scores[i].ToString(),
                        new Vector2(this.Window.ClientBounds.Width - 95, shift),
                        Color.White);
                    shift += 35;
                }
                // Печать суммы очков
                spriteBatch.DrawString(font1,
                    "Итого: " + totalScores,
                    new Vector2(this.Window.ClientBounds.Width - 150, shift),
                    Color.White);
    
                spriteBatch.End();
            }   /////////////////// end else ///////////////////
    
            base.Draw(gameTime);
        }

Сохранение рекорда

Для сохранения результата победителя воспользуемся встроенными средствами Visual Studio 2008.

  • Откройте окно свойств текущего проекта командой Project/Game2D Properties
  • Выберите вкладку Settings и откройте таблицу параметров
  • Заполните поля первой записи таблицы следующим образом
Name Type Scope Value
victoryScores int User 0

  • Добавьте к функции UnloadContent() следующий код
// Для сохранения очков победителя
        Properties.Settings settings = new Properties.Settings();
        int victoryScores = 0;
        protected override void UnloadContent()
        {
            // Запомнить рекорд
            if (victoryScores > settings.victoryScores)
            {
                settings.victoryScores = victoryScores;
                settings.Save(); 
            }
        }
  • Добавьте в конец конструктора класса игры код чтения рекорда
public StartGame()
        {
            .................................................
    
            // Чтение рекорда
            victoryScores = settings.victoryScores;
        }
  • Добавьте в функцию Collisions() код распознавания рекорда
void Collisions()
        {
            .........................................................
    
            // Проверка пересечений ограничивающих прямоугольников
            // летящих объектов с каймой платформы и реакция на них
            for (int i = 0; i < bbSprite.Length; i++)
            {
                if (bbPlatform.Intersects(bbSprite[i]))
                {
                    ......................................................
    
                    // Подсчет очков по сумме столкновений с объектами
                    scores[i]++;
                    totalScores++;
    
                    // Обновление рекорда
                    if (totalScores > victoryScores)
                        victoryScores = totalScores;
    
                    // Звукнуть хорошо
                    Sound.Play(SoundList.Platform);
                }
            }
        }
  • Добавьте в метод Draw() класса StartGame код вывода рекорда на экран монитора
protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);
    
            // Рисуем меню
            if (menuState)
            {
                spriteBatch.Begin(SpriteBlendMode.AlphaBlend);
                menu.DrawMenu(spriteBatch, buttonState);
                mouse.DrawSprite(spriteBatch);
                spriteBatch.End();
            }       
            else    ////////////// else ////////////////
            {
                ........................................................
					
                // Печать суммы очков
                spriteBatch.DrawString(font1,
                    "Итого: " + totalScores,
                    new Vector2(this.Window.ClientBounds.Width - 150, shift),
                    Color.White);

                // Печать очков победителя
                spriteBatch.DrawString(font1, "Рекорд: " + victoryScores,
                    new Vector2(this.Window.ClientBounds.Width - 175, 225),
                    Color.White);
    
                spriteBatch.End();
            }   /////////////////// end else ///////////////////
    
            base.Draw(gameTime);
        }
  • Откомпилируйте проект командой Rebuild и убедитесь в работе механизма сохранения очков победителя

Конечно, планировать игру нужно с самого начала, чтобы не пришлось на ходу перестраивать код как в известном анекдоте: "-Ты что программируешь? -А вот сейчас откомпилирую и узнаю!" Но мы шли от простого к сложному, постепенно наращивая код, и нам была важнее - практика программирования, а не планирование (и даже не сама игра).

Мы познакомились с основными этапами построения игрового приложения и дальнейшее усложнение игры становится рутинной работой. Поэтому остановимся на этом и рассмотрим завершающий этап - формирование инсталляционного пакета, чтобы можно было профессионально распространять наш продукт.

Самостоятельная работа 1: 12345678910 || Самостоятельная работа 2 >
Алексей Бабушкин
Алексей Бабушкин

При выполнении в лабораторной работе упражнения №1 , а именно при выполнении нижеследующего кода:

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Text;

using System.Windows.Forms;

using Microsoft.Xna.Framework.Graphics;

   

namespace Application1

{

    public partial class MainForm : Form

    {

        // Объявим поле графического устройства для видимости в методах

        GraphicsDevice device;

   

        public MainForm()

        {

            InitializeComponent();

   

            // Подпишемся на событие Load формы

            this.Load += new EventHandler(MainForm_Load);

   

            // Попишемся на событие FormClosed формы

            this.FormClosed += new FormClosedEventHandler(MainForm_FormClosed);

        }

   

        void MainForm_FormClosed(object sender, FormClosedEventArgs e)

        {

            //  Удаляем (освобождаем) устройство

            device.Dispose();

            // На всякий случай присваиваем ссылке на устройство значение null

            device = null;       

        }

   

        void MainForm_Load(object sender, EventArgs e)

        {

            // Создаем объект представления для настройки графического устройства

            PresentationParameters presentParams = new PresentationParameters();

            // Настраиваем объект представления через его свойства

            presentParams.IsFullScreen = false; // Включаем оконный режим

            presentParams.BackBufferCount = 1;  // Включаем задний буфер

                                                // для двойной буферизации

            // Переключение переднего и заднего буферов

            // должно осуществляться с максимальной эффективностью

            presentParams.SwapEffect = SwapEffect.Discard;

            // Устанавливаем размеры заднего буфера по клиентской области окна формы

            presentParams.BackBufferWidth = this.ClientSize.Width;

            presentParams.BackBufferHeight = this.ClientSize.Height;

   

            // Создадим графическое устройство с заданными настройками

            device = new GraphicsDevice(GraphicsAdapter.DefaultAdapter, DeviceType.Hardware,

                this.Handle, presentParams);

        }

   

        protected override void OnPaint(PaintEventArgs e)

        {

            device.Clear(Microsoft.Xna.Framework.Graphics.Color.CornflowerBlue);

   

            base.OnPaint(e);

        }

    }

}

Выбрасывается исключение:

Невозможно загрузить файл или сборку "Microsoft.Xna.Framework, Version=3.0.0.0, Culture=neutral, PublicKeyToken=6d5c3888ef60e27d" или один из зависимых от них компонентов. Не удается найти указанный файл.

Делаю все пунктуально. В чем может быть проблема?

Dmitriy Ivanchenko
Dmitriy Ivanchenko
Украина, Кировоград, Виктория-П, 2011
Татьяна Ковалюк
Татьяна Ковалюк
Украина, Киев, Киевский политехнический институт, 1974