Основы разработки компьютерных игр в XNA Game Studio

Озвучивание игр

Разбить на страницы
Показывать лекцию целиком

Примеры к лабораторной работе

Задачи работы

  • Освоить основные операции по работе с WAV-файлами
  • Освоить инструменты XACT для создания XAP-проектов
  • Научиться проигрывать фоновую музыку в играх
  • Научиться проигрывать звуки, соответствующие различным игровым событиям
  • Этапы озвучивания игры

    Для того, чтобы озвучить игру, нужно проделать следующие шаги:

  • Подготовить WAV-файлы. Звуковое оформление игры состоит из двух частей. Во-первых – это фоновая музыка, которая может меняться в зависимости от отображаемого игрового экрана или игрового уровня, и звуки, соответствующие игровым событиям.
  • Создать новый XNA-проект (можно озвучивать и уже созданные игры, в которых звуковое оформление не применялось)
  • Создать в папке Content отдельную папку для хранения звуковых файлов, например, назвав ее Audio, скопировать в эту папку подготовленные файлы
  • Создать новый XACT-проект и сохранить его в папке Audio игрового проекта.
  • Добавить WAV-файлы в проект, сформировать WaveBank и SoundBank
  • Загрузить XACT-проект в игру
  • Включить воспроизведение фоновой музыки, которая обычно зацикливается
  • Включать воспроизведение нужных звуковых фрагментов при возникновении соответствующих событий.
  • Озвучивание игры

    Создадим новый стандартный игровой проект P7_1. С помощью Solution Explorer создадим папку Audio в разделе Content. Найдем его папку в файловой системе компьютера, пройдем в директорию . Файлы в библиотеке представлены в формате MP3, мы конвертировали их в формат WAV с помощью аудиоредактора GoldWave.

    Выполним команду меню Пуск $$\Rightarrow$$ Все программы $$\Rightarrow$$ Microsoft XNA Game Studio 2.0 $$\Rightarrow$$ Tools $$\Rightarrow$$ XACT auditioning utility. Этой командой мы запустили Auditioning-сервер, который нужен для проигрывания музыки в XACT. Теперь запустим XACT командой Пуск $$\Rightarrow$$ Все программы $$\Rightarrow$$ Microsoft XNA Game Studio 2.0 $$\Rightarrow$$ Tools $$\Rightarrow$$ Microsoft Cross Platform Audio Creation Tool (XACT). На рис. 11.1. вы можете видеть стартовое окно XACT.

    (рис 11.1) f XACT

    Командой File $$\Rightarrow$$ New Project создадим новый XACT-проект, назовем его xP7_1 и сохраним в папке Audio нашего игрового проекта.

    Щелкнем правой кнопкой мыши по миниатюре Wave Banks, которая находится в левой части окна программы и в появившемся меню щелкнем пункт New Wave Bank, дадим новому банку Wave-файлов имя Sounds. Wave-банки предназначены для хранения Wave-файлов, которые мы планируем включить в игру. Теперь щелкнем правой кнопкой мыши по пункту Sound Banks, выберем в появившемся меню пункт New Sound Bank, назовем новый звуковой банк SoundBank. Расположим окна двух банков в окне программы. Вот как должен выглядеть экран программы после этих действий (рис. 11.2.).

    (рис 11.2) Окно программы после добавления звуковых банков

    В Wave-банк мы должны добавить файлы, которые подготовлены ранее. Для этого нужно щелкнуть правой кнопкой мыши в поле окна Sounds (Wave Bank) и в появившемся меню выбрать пункт Insert Wave Files. В появившемся окне (автоматически будет открыта папка Audio нашего проекта) выберем нужные файлы и нажмем кнопку Открыть. Файлы появятся в окне Wave-банка. Теперь выделим значки файлов в этом окне и перетащим их в окно SoundBank (Sound Bank), в его поле Cue Name. Автоматически будут созданы закладки, которые мы будем использовать в игре для проигрывания соответствующих звуков. Звуки s1.wav и s2.wav будут соответствовать некоторым игровым событиям. Они будут проигрываться при наступлении определенного события в игре. А звук music.wav – фоновая музыка – будет проигрываться все время, пока игра запущена. Для того, чтобы он проигрывался циклически, нам нужно настроить его свойства. Выделим его в поле Sound Name и в панели свойств звука (она расположена в левой нижней части окна программы) установим флажок Infinite в группе параметров Looping. На данный момент это все, что нам нужно сделать в XACT. Сохраним проект и закроем окно редактора и XACT Auditioning Utility. Вернемся к игровому проекту P7_1. В окне Solution Explorer добавим XACT-проект в игру. Для того, чтобы воспользоваться звуками, нам нужно загрузить звуковые ресурсы.

    Используем в данном проекте игровой компонент spriteComp из проекта P4_3, модифицировав его таким образом, чтобы при столкновении объекта, созданного на его основе, со стенами, воспроизводился звук s1.wav, и чтобы при щелчке мышью по этому объекту воспроизводился звук s2.wav. Так же добавим в нашу игру возможность приостанавливать и возобновлять проигрывание фоновой музыки по нажатию клавиш A и S соответственно.

    В листинге 11.1. приведен код класса Game1.

    using System;
    using System.Collections.Generic;
    using Microsoft.Xna.Framework;
    using Microsoft.Xna.Framework.Audio;
    using Microsoft.Xna.Framework.Content;
    using Microsoft.Xna.Framework.GamerServices;
    using Microsoft.Xna.Framework.Graphics;
    using Microsoft.Xna.Framework.Input;
    using Microsoft.Xna.Framework.Net;
    using Microsoft.Xna.Framework.Storage;
    
    namespace P7_1
    {
        public class Game1 : Microsoft.Xna.Framework.Game
        {
            GraphicsDeviceManager graphics;
            SpriteBatch spriteBatch;
            //Переменная для работы с аудиоустройством
            AudioEngine audioEngine;
            //Переменная для работы с Wave-банком
            WaveBank waveBank;
            //Переменная для работы с Sound-банком
            SoundBank soundBank;
            //Переменная для работы с фоновой музыкой игры
            Cue musicCue;
            Texture2D texture;
            public Game1()
            {
                graphics = new GraphicsDeviceManager(this);
                Content.RootDirectory = "Content";
            }
    
            protected override void Initialize()
            {
                //Загружаем аудиоресурсы для игры
                audioEngine = new AudioEngine("Content\\Audio\\xP7_1.xgs");
                waveBank = new WaveBank(audioEngine, "Content\\Audio\\Sounds.xwb");
                soundBank = new SoundBank(audioEngine, "Content\\Audio\\SoundBank.xsb");
                //Присваиваем переменной ссылку на закладку с именем Music
                musicCue = soundBank.GetCue("Music");
                //Включаем проигрывание фоновой музыки
                musicCue.Play();
                this.IsMouseVisible = true;
                base.Initialize();
            }
    
            protected override void LoadContent()
            {
                // Create a new SpriteBatch, which can be used to draw textures.
                spriteBatch = new SpriteBatch(GraphicsDevice);
                Services.AddService(typeof(SpriteBatch), spriteBatch);
                texture = Content.Load<Texture2D>("BallandBats");
                // Создаем игровые объекты
                for (int i=1;i<5;i++)
                {
                    Components.Add(new spriteComp(this, ref texture,
                        new Rectangle(16, 203, 17, 17), i, this, soundBank));
                }
            }
    
            protected override void UnloadContent()
            {
                // TODO: Unload any non ContentManager content here
            }
    
            
            protected override void Update(GameTime gameTime)
            {
                //Блок управления проигрыванием по нажатию клавиш
                //При нажатии клавиши A приостанавливаем проигрывание
                KeyboardState kbState = Keyboard.GetState();
                if (kbState.IsKeyDown(Keys.A))
                {
                  musicCue.Pause();
                }
                //При нажатии клавиши S продолжаем проигрывание музыки
                if (kbState.IsKeyDown(Keys.S))
                {
                    musicCue.Resume();
                }
    
                audioEngine.Update();
                base.Update(gameTime);
            }
    
            protected override void Draw(GameTime gameTime)
            {
                graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
    
                // TODO: Add your drawing code here
                spriteBatch.Begin();
                base.Draw(gameTime);
                spriteBatch.End();
            }
        }
    }

    При загрузке аудиокомпонентов мы должны создать новую переменную типа AudioEngine, которая используется для управления аудиоустройством. При создании этой переменной мы указываем в качестве компонента для загрузки Content\\Audio\\xP7_1.xgs. XGS – это расширение файлов, хранящих глобальные настройки XACT-проекта. Обратите внимание на то, что в папке Audio нет файла с расширением .XGS, однако мы должны инициализировать переменную типа AudioEngine именно указанным способом. Имя XGS-ресурса совпадает с именем XACT-проекта. Похоже осуществляется загрузка переменных типа WaveBank и SoundBank. А именно, при загрузке переменной типа WaveBank мы указываем имя Wave-банка, созданного в XACT-проекте с расширением .XWB (Content\\Audio\\Sounds.xwb), при загрузке переменной типа SoundBank мы используем имя Sound-банка в XACT-проекте с расширением .XSB (Content\\Audio\\SoundBank.xsb).

    Для работы с фоновой музыкой нашей игры мы используем переменную типа Cue. Она хранит ссылку на соответствующий звуковой файл. С помощью метода Play() этой переменной мы включаем проигрывание музыки. Так как в XACT-проекте мы указали, что данный звуковой фрагмент должен проигрываться циклически, он будет звучать до тех пор, пока игра не будет остановлена или до тех пор, пока мы явно не приостановим его воспроизведение. Для приостановки воспроизведения этого фрагмента мы используем метод Pause(), для возобновления – метод Resume(). Эти методы исполняются при нажатии на клавиши A и S.

    Теперь рассмотрим код компонента spriteComp (листинг 11.2.).

    using System;
    using System.Collections.Generic;
    using Microsoft.Xna.Framework;
    using Microsoft.Xna.Framework.Audio;
    using Microsoft.Xna.Framework.GamerServices;
    using Microsoft.Xna.Framework.Graphics;
    using Microsoft.Xna.Framework.Input;
    using Microsoft.Xna.Framework.Storage;
    using Microsoft.Xna.Framework.Content;
    
    namespace P7_1
    {
        /// <summary>
        /// This is a game component that implements IUpdateable.
        /// </summary>
        public class spriteComp : Microsoft.Xna.Framework.DrawableGameComponent
        {
            protected Texture2D sprTexture;
            protected Rectangle sprRectangle;
            protected Vector2 sprPosition;
            protected Rectangle scrBounds;
            //Для генерирования случайных чисел
            protected Random randNum;
            //Объект для доступа к основному игровому объекту
            protected Game1 myGame;
            //Цвет спрайта
            protected Color sprColor;
            //Скорость перемещения
            public Vector2 speed;
            //Состояние мыши
            MouseState mouse;
            //Звуки
            SoundBank sound;
    
            public spriteComp(Game game, ref Texture2D newTexture,
                Rectangle newRectangle, int Seed, Game1 game1, SoundBank newSound)
                : base(game)
            {
                sprTexture = newTexture;
                sprRectangle = newRectangle;
                //Инициализируем счетчик
                randNum = new Random(Seed);
                myGame = game1;
                scrBounds = new Rectangle(0, 0,
                    game.Window.ClientBounds.Width,
                    game.Window.ClientBounds.Height);
                //Устанавливаем стартовую позицию спрайта
                setSpriteToStart();
                //Если спрайт сталкивается с каким-нибудь спрайтом - изменим его позицию
                while (howManyCollides() > 0)
                {
                    setSpriteToStart();
                }
                //Зададим случайный цвет для придания изображению
                //соответствующего оттенка
                sprColor = new Color((byte)randNum.Next(0, 255), (byte)randNum.Next(0, 255), (byte)randNum.Next(0, 255));
                //Переменная для хранения скорости пока пуста
                speed = new Vector2((float)randNum.Next(-5, 5), (float)randNum.Next(-5, 5));
               
                sound = newSound ;
            }
            //Проверка, не установлены ли спрайты в позиции с перекрытием других спрайтов
            int howManyCollides()
            {
                int howMany = 0;
                foreach (spriteComp spr in myGame.Components)
                {
                    if (this != spr)
                    {
                        if (this.sprCollide(spr))
                        {
                            howMany++;
                        }
                    }
    
                }
                return howMany;
    
            }
            //Установка спрайта в случайную стартовую позицию
            void setSpriteToStart()
            {
                sprPosition.X = (float)randNum.NextDouble() * (scrBounds.Width - sprRectangle.Width);
                sprPosition.Y = (float)randNum.NextDouble() * (scrBounds.Height - sprRectangle.Height);
    
            }
    
            
            public override void Initialize()
            {
                // TODO: Add your initialization code here
    
                base.Initialize();
            }
            //Перемещение спрайта
            public virtual void Move()
            {
                sprPosition += speed;
            }
            //Проверка допустимости перемещения
            void Check()
            {
                if (sprPosition.X < scrBounds.Left)
                {
                    sound.PlayCue("s1");
                    sprPosition.X = scrBounds.Left;
                    speed.X *= -1;
                }
                if (sprPosition.X > scrBounds.Width - sprRectangle.Width)
                {
                    sound.PlayCue("s1");
                    sprPosition.X = scrBounds.Width - sprRectangle.Width;
                    speed.X *= -1;
                }
                if (sprPosition.Y < scrBounds.Top)
                {
                    sound.PlayCue("s1");
                    sprPosition.Y = scrBounds.Top;
                    speed.Y *= -1;
                }
                if (sprPosition.Y > scrBounds.Height - sprRectangle.Height)
                {
                    sound.PlayCue("s1");
                    sprPosition.Y = scrBounds.Height - sprRectangle.Height;
                    speed.Y *= -1;
                }
            }
    
            public bool sprCollide(spriteComp spr)
            {
                return (this.sprPosition.X + this.sprRectangle.Width > spr.sprPosition.X 
                        this.sprPosition.X < spr.sprPosition.X + spr.sprRectangle.Width 
                        this.sprPosition.Y + this.sprRectangle.Height > spr.sprPosition.Y 
                        this.sprPosition.Y < spr.sprPosition.Y + spr.sprRectangle.Height);
            }
            
            //Функция возвращает true если указатель мыши находился в пределах
            //текущего объекта при щелчке мышью
            bool MouseCollide()
            {
                return (this.sprPosition.X + this.sprRectangle.Width > mouse.X 
                    this.sprPosition.X < mouse.X 
                    this.sprPosition.Y + this.sprRectangle.Height > mouse.Y 
                    this.sprPosition.Y < mouse.Y);
    
            }
            public override void Update(GameTime gameTime)
            {
                mouse = Mouse.GetState();
                if (mouse.LeftButton == ButtonState.Pressed)
                {
                    //Если при щелчке мышью указатель находился в пределах текущего объекта
                    //увеличиваем количество набранных очков и уничтожаем объект.
                    if (MouseCollide())
                    {
                        sound.PlayCue("s2");
                        this.Dispose();
                    }
                }
    
                // TODO: Add your update code here
                //Вызов метода для перемещения спрайта
                Move();
                //Проверка на столкновение с границами экрана
                Check();
                //Вызов проверки на столкновение с другими спрайтами
                IsSpriteCollide();
                //Возможно, при коррекции спрайта относительно другого спрайта,
                //произошло перекрытие с другим спрайтом или спрайтами
                //это приводит к "зависанию" спрайтов - они остаются на одном 
                //месте в "сцепленном" состоянии. Для того, чтобы этого избежать,
                //мы корректируем позиции спрайтов до тех пор, пока каждый из них
                //гарантированно не окажется вне других спрайтов
                while (howManyCollides() > 0)
                {
                    IsSpriteCollide();
                }
    
                base.Update(gameTime);
            }
            //Если спрайт перекрыл другой спрайт - изменить его скорость и
            //применить изменения к позиции спрайта
            void IsSpriteCollide()
            {
                foreach (spriteComp spr in myGame.Components)
                {
                    if (spr != this)
                    {
                        if (this.sprCollide(spr))
                        {
                            sound.PlayCue("s1");
                            this.speed *= -1;
                            this.sprPosition += this.speed;
                        }
                    }
                }
            }
            public override void Draw(GameTime gameTime)
            {
                SpriteBatch sprBatch =
                    (SpriteBatch)Game.Services.GetService(typeof(SpriteBatch));
                sprBatch.Draw(sprTexture, sprPosition, sprRectangle, sprColor);
                base.Draw(gameTime);
            }
        }
    }

    При создании компонентов класса spriteComp мы, кроме прочего, передаем им объект, содержащий закладки звуков, которые должны проигрываться в игре. Здесь мы используем два звука. Один из них (s1) проигрывается при столкновении объектов со стенами или друг с другом. Другой (s2) проигрывается перед уничтожением объекта после того, как пользователь попал по нему мышью.

    Страницы:

    Примеры к лабораторной работе

    Задачи работы

  • Освоить основные операции по работе с WAV-файлами
  • Освоить инструменты XACT для создания XAP-проектов
  • Научиться проигрывать фоновую музыку в играх
  • Научиться проигрывать звуки, соответствующие различным игровым событиям
  • Этапы озвучивания игры

    Для того, чтобы озвучить игру, нужно проделать следующие шаги:

  • Подготовить WAV-файлы. Звуковое оформление игры состоит из двух частей. Во-первых – это фоновая музыка, которая может меняться в зависимости от отображаемого игрового экрана или игрового уровня, и звуки, соответствующие игровым событиям.
  • Создать новый XNA-проект (можно озвучивать и уже созданные игры, в которых звуковое оформление не применялось)
  • Создать в папке Content отдельную папку для хранения звуковых файлов, например, назвав ее Audio, скопировать в эту папку подготовленные файлы
  • Создать новый XACT-проект и сохранить его в папке Audio игрового проекта.
  • Добавить WAV-файлы в проект, сформировать WaveBank и SoundBank
  • Загрузить XACT-проект в игру
  • Включить воспроизведение фоновой музыки, которая обычно зацикливается
  • Включать воспроизведение нужных звуковых фрагментов при возникновении соответствующих событий.
  • Озвучивание игры

    Создадим новый стандартный игровой проект P7_1. С помощью Solution Explorer создадим папку Audio в разделе Content. Найдем его папку в файловой системе компьютера, пройдем в директорию . Файлы в библиотеке представлены в формате MP3, мы конвертировали их в формат WAV с помощью аудиоредактора GoldWave.

    Выполним команду меню Пуск $$\Rightarrow$$ Все программы $$\Rightarrow$$ Microsoft XNA Game Studio 2.0 $$\Rightarrow$$ Tools $$\Rightarrow$$ XACT auditioning utility. Этой командой мы запустили Auditioning-сервер, который нужен для проигрывания музыки в XACT. Теперь запустим XACT командой Пуск $$\Rightarrow$$ Все программы $$\Rightarrow$$ Microsoft XNA Game Studio 2.0 $$\Rightarrow$$ Tools $$\Rightarrow$$ Microsoft Cross Platform Audio Creation Tool (XACT). На рис. 11.1. вы можете видеть стартовое окно XACT.

    (рис 11.1) f XACT

    Командой File $$\Rightarrow$$ New Project создадим новый XACT-проект, назовем его xP7_1 и сохраним в папке Audio нашего игрового проекта.

    Щелкнем правой кнопкой мыши по миниатюре Wave Banks, которая находится в левой части окна программы и в появившемся меню щелкнем пункт New Wave Bank, дадим новому банку Wave-файлов имя Sounds. Wave-банки предназначены для хранения Wave-файлов, которые мы планируем включить в игру. Теперь щелкнем правой кнопкой мыши по пункту Sound Banks, выберем в появившемся меню пункт New Sound Bank, назовем новый звуковой банк SoundBank. Расположим окна двух банков в окне программы. Вот как должен выглядеть экран программы после этих действий (рис. 11.2.).

    (рис 11.2) Окно программы после добавления звуковых банков

    В Wave-банк мы должны добавить файлы, которые подготовлены ранее. Для этого нужно щелкнуть правой кнопкой мыши в поле окна Sounds (Wave Bank) и в появившемся меню выбрать пункт Insert Wave Files. В появившемся окне (автоматически будет открыта папка Audio нашего проекта) выберем нужные файлы и нажмем кнопку Открыть. Файлы появятся в окне Wave-банка. Теперь выделим значки файлов в этом окне и перетащим их в окно SoundBank (Sound Bank), в его поле Cue Name. Автоматически будут созданы закладки, которые мы будем использовать в игре для проигрывания соответствующих звуков. Звуки s1.wav и s2.wav будут соответствовать некоторым игровым событиям. Они будут проигрываться при наступлении определенного события в игре. А звук music.wav – фоновая музыка – будет проигрываться все время, пока игра запущена. Для того, чтобы он проигрывался циклически, нам нужно настроить его свойства. Выделим его в поле Sound Name и в панели свойств звука (она расположена в левой нижней части окна программы) установим флажок Infinite в группе параметров Looping. На данный момент это все, что нам нужно сделать в XACT. Сохраним проект и закроем окно редактора и XACT Auditioning Utility. Вернемся к игровому проекту P7_1. В окне Solution Explorer добавим XACT-проект в игру. Для того, чтобы воспользоваться звуками, нам нужно загрузить звуковые ресурсы.

    Используем в данном проекте игровой компонент spriteComp из проекта P4_3, модифицировав его таким образом, чтобы при столкновении объекта, созданного на его основе, со стенами, воспроизводился звук s1.wav, и чтобы при щелчке мышью по этому объекту воспроизводился звук s2.wav. Так же добавим в нашу игру возможность приостанавливать и возобновлять проигрывание фоновой музыки по нажатию клавиш A и S соответственно.

    В листинге 11.1. приведен код класса Game1.

    using System;
    using System.Collections.Generic;
    using Microsoft.Xna.Framework;
    using Microsoft.Xna.Framework.Audio;
    using Microsoft.Xna.Framework.Content;
    using Microsoft.Xna.Framework.GamerServices;
    using Microsoft.Xna.Framework.Graphics;
    using Microsoft.Xna.Framework.Input;
    using Microsoft.Xna.Framework.Net;
    using Microsoft.Xna.Framework.Storage;
    
    namespace P7_1
    {
        public class Game1 : Microsoft.Xna.Framework.Game
        {
            GraphicsDeviceManager graphics;
            SpriteBatch spriteBatch;
            //Переменная для работы с аудиоустройством
            AudioEngine audioEngine;
            //Переменная для работы с Wave-банком
            WaveBank waveBank;
            //Переменная для работы с Sound-банком
            SoundBank soundBank;
            //Переменная для работы с фоновой музыкой игры
            Cue musicCue;
            Texture2D texture;
            public Game1()
            {
                graphics = new GraphicsDeviceManager(this);
                Content.RootDirectory = "Content";
            }
    
            protected override void Initialize()
            {
                //Загружаем аудиоресурсы для игры
                audioEngine = new AudioEngine("Content\\Audio\\xP7_1.xgs");
                waveBank = new WaveBank(audioEngine, "Content\\Audio\\Sounds.xwb");
                soundBank = new SoundBank(audioEngine, "Content\\Audio\\SoundBank.xsb");
                //Присваиваем переменной ссылку на закладку с именем Music
                musicCue = soundBank.GetCue("Music");
                //Включаем проигрывание фоновой музыки
                musicCue.Play();
                this.IsMouseVisible = true;
                base.Initialize();
            }
    
            protected override void LoadContent()
            {
                // Create a new SpriteBatch, which can be used to draw textures.
                spriteBatch = new SpriteBatch(GraphicsDevice);
                Services.AddService(typeof(SpriteBatch), spriteBatch);
                texture = Content.Load<Texture2D>("BallandBats");
                // Создаем игровые объекты
                for (int i=1;i<5;i++)
                {
                    Components.Add(new spriteComp(this, ref texture,
                        new Rectangle(16, 203, 17, 17), i, this, soundBank));
                }
            }
    
            protected override void UnloadContent()
            {
                // TODO: Unload any non ContentManager content here
            }
    
            
            protected override void Update(GameTime gameTime)
            {
                //Блок управления проигрыванием по нажатию клавиш
                //При нажатии клавиши A приостанавливаем проигрывание
                KeyboardState kbState = Keyboard.GetState();
                if (kbState.IsKeyDown(Keys.A))
                {
                  musicCue.Pause();
                }
                //При нажатии клавиши S продолжаем проигрывание музыки
                if (kbState.IsKeyDown(Keys.S))
                {
                    musicCue.Resume();
                }
    
                audioEngine.Update();
                base.Update(gameTime);
            }
    
            protected override void Draw(GameTime gameTime)
            {
                graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
    
                // TODO: Add your drawing code here
                spriteBatch.Begin();
                base.Draw(gameTime);
                spriteBatch.End();
            }
        }
    }

    При загрузке аудиокомпонентов мы должны создать новую переменную типа AudioEngine, которая используется для управления аудиоустройством. При создании этой переменной мы указываем в качестве компонента для загрузки Content\\Audio\\xP7_1.xgs. XGS – это расширение файлов, хранящих глобальные настройки XACT-проекта. Обратите внимание на то, что в папке Audio нет файла с расширением .XGS, однако мы должны инициализировать переменную типа AudioEngine именно указанным способом. Имя XGS-ресурса совпадает с именем XACT-проекта. Похоже осуществляется загрузка переменных типа WaveBank и SoundBank. А именно, при загрузке переменной типа WaveBank мы указываем имя Wave-банка, созданного в XACT-проекте с расширением .XWB (Content\\Audio\\Sounds.xwb), при загрузке переменной типа SoundBank мы используем имя Sound-банка в XACT-проекте с расширением .XSB (Content\\Audio\\SoundBank.xsb).

    Для работы с фоновой музыкой нашей игры мы используем переменную типа Cue. Она хранит ссылку на соответствующий звуковой файл. С помощью метода Play() этой переменной мы включаем проигрывание музыки. Так как в XACT-проекте мы указали, что данный звуковой фрагмент должен проигрываться циклически, он будет звучать до тех пор, пока игра не будет остановлена или до тех пор, пока мы явно не приостановим его воспроизведение. Для приостановки воспроизведения этого фрагмента мы используем метод Pause(), для возобновления – метод Resume(). Эти методы исполняются при нажатии на клавиши A и S.

    Теперь рассмотрим код компонента spriteComp (листинг 11.2.).

    using System;
    using System.Collections.Generic;
    using Microsoft.Xna.Framework;
    using Microsoft.Xna.Framework.Audio;
    using Microsoft.Xna.Framework.GamerServices;
    using Microsoft.Xna.Framework.Graphics;
    using Microsoft.Xna.Framework.Input;
    using Microsoft.Xna.Framework.Storage;
    using Microsoft.Xna.Framework.Content;
    
    namespace P7_1
    {
        /// <summary>
        /// This is a game component that implements IUpdateable.
        /// </summary>
        public class spriteComp : Microsoft.Xna.Framework.DrawableGameComponent
        {
            protected Texture2D sprTexture;
            protected Rectangle sprRectangle;
            protected Vector2 sprPosition;
            protected Rectangle scrBounds;
            //Для генерирования случайных чисел
            protected Random randNum;
            //Объект для доступа к основному игровому объекту
            protected Game1 myGame;
            //Цвет спрайта
            protected Color sprColor;
            //Скорость перемещения
            public Vector2 speed;
            //Состояние мыши
            MouseState mouse;
            //Звуки
            SoundBank sound;
    
            public spriteComp(Game game, ref Texture2D newTexture,
                Rectangle newRectangle, int Seed, Game1 game1, SoundBank newSound)
                : base(game)
            {
                sprTexture = newTexture;
                sprRectangle = newRectangle;
                //Инициализируем счетчик
                randNum = new Random(Seed);
                myGame = game1;
                scrBounds = new Rectangle(0, 0,
                    game.Window.ClientBounds.Width,
                    game.Window.ClientBounds.Height);
                //Устанавливаем стартовую позицию спрайта
                setSpriteToStart();
                //Если спрайт сталкивается с каким-нибудь спрайтом - изменим его позицию
                while (howManyCollides() > 0)
                {
                    setSpriteToStart();
                }
                //Зададим случайный цвет для придания изображению
                //соответствующего оттенка
                sprColor = new Color((byte)randNum.Next(0, 255), (byte)randNum.Next(0, 255), (byte)randNum.Next(0, 255));
                //Переменная для хранения скорости пока пуста
                speed = new Vector2((float)randNum.Next(-5, 5), (float)randNum.Next(-5, 5));
               
                sound = newSound ;
            }
            //Проверка, не установлены ли спрайты в позиции с перекрытием других спрайтов
            int howManyCollides()
            {
                int howMany = 0;
                foreach (spriteComp spr in myGame.Components)
                {
                    if (this != spr)
                    {
                        if (this.sprCollide(spr))
                        {
                            howMany++;
                        }
                    }
    
                }
                return howMany;
    
            }
            //Установка спрайта в случайную стартовую позицию
            void setSpriteToStart()
            {
                sprPosition.X = (float)randNum.NextDouble() * (scrBounds.Width - sprRectangle.Width);
                sprPosition.Y = (float)randNum.NextDouble() * (scrBounds.Height - sprRectangle.Height);
    
            }
    
            
            public override void Initialize()
            {
                // TODO: Add your initialization code here
    
                base.Initialize();
            }
            //Перемещение спрайта
            public virtual void Move()
            {
                sprPosition += speed;
            }
            //Проверка допустимости перемещения
            void Check()
            {
                if (sprPosition.X < scrBounds.Left)
                {
                    sound.PlayCue("s1");
                    sprPosition.X = scrBounds.Left;
                    speed.X *= -1;
                }
                if (sprPosition.X > scrBounds.Width - sprRectangle.Width)
                {
                    sound.PlayCue("s1");
                    sprPosition.X = scrBounds.Width - sprRectangle.Width;
                    speed.X *= -1;
                }
                if (sprPosition.Y < scrBounds.Top)
                {
                    sound.PlayCue("s1");
                    sprPosition.Y = scrBounds.Top;
                    speed.Y *= -1;
                }
                if (sprPosition.Y > scrBounds.Height - sprRectangle.Height)
                {
                    sound.PlayCue("s1");
                    sprPosition.Y = scrBounds.Height - sprRectangle.Height;
                    speed.Y *= -1;
                }
            }
    
            public bool sprCollide(spriteComp spr)
            {
                return (this.sprPosition.X + this.sprRectangle.Width > spr.sprPosition.X 
                        this.sprPosition.X < spr.sprPosition.X + spr.sprRectangle.Width 
                        this.sprPosition.Y + this.sprRectangle.Height > spr.sprPosition.Y 
                        this.sprPosition.Y < spr.sprPosition.Y + spr.sprRectangle.Height);
            }
            
            //Функция возвращает true если указатель мыши находился в пределах
            //текущего объекта при щелчке мышью
            bool MouseCollide()
            {
                return (this.sprPosition.X + this.sprRectangle.Width > mouse.X 
                    this.sprPosition.X < mouse.X 
                    this.sprPosition.Y + this.sprRectangle.Height > mouse.Y 
                    this.sprPosition.Y < mouse.Y);
    
            }
            public override void Update(GameTime gameTime)
            {
                mouse = Mouse.GetState();
                if (mouse.LeftButton == ButtonState.Pressed)
                {
                    //Если при щелчке мышью указатель находился в пределах текущего объекта
                    //увеличиваем количество набранных очков и уничтожаем объект.
                    if (MouseCollide())
                    {
                        sound.PlayCue("s2");
                        this.Dispose();
                    }
                }
    
                // TODO: Add your update code here
                //Вызов метода для перемещения спрайта
                Move();
                //Проверка на столкновение с границами экрана
                Check();
                //Вызов проверки на столкновение с другими спрайтами
                IsSpriteCollide();
                //Возможно, при коррекции спрайта относительно другого спрайта,
                //произошло перекрытие с другим спрайтом или спрайтами
                //это приводит к "зависанию" спрайтов - они остаются на одном 
                //месте в "сцепленном" состоянии. Для того, чтобы этого избежать,
                //мы корректируем позиции спрайтов до тех пор, пока каждый из них
                //гарантированно не окажется вне других спрайтов
                while (howManyCollides() > 0)
                {
                    IsSpriteCollide();
                }
    
                base.Update(gameTime);
            }
            //Если спрайт перекрыл другой спрайт - изменить его скорость и
            //применить изменения к позиции спрайта
            void IsSpriteCollide()
            {
                foreach (spriteComp spr in myGame.Components)
                {
                    if (spr != this)
                    {
                        if (this.sprCollide(spr))
                        {
                            sound.PlayCue("s1");
                            this.speed *= -1;
                            this.sprPosition += this.speed;
                        }
                    }
                }
            }
            public override void Draw(GameTime gameTime)
            {
                SpriteBatch sprBatch =
                    (SpriteBatch)Game.Services.GetService(typeof(SpriteBatch));
                sprBatch.Draw(sprTexture, sprPosition, sprRectangle, sprColor);
                base.Draw(gameTime);
            }
        }
    }

    При создании компонентов класса spriteComp мы, кроме прочего, передаем им объект, содержащий закладки звуков, которые должны проигрываться в игре. Здесь мы используем два звука. Один из них (s1) проигрывается при столкновении объектов со стенами или друг с другом. Другой (s2) проигрывается перед уничтожением объекта после того, как пользователь попал по нему мышью.

    Вернуться к учебному плану