Спонсор: Microsoft
Опубликован: 10.04.2009 | Уровень: специалист | Доступ: свободно
Самостоятельная работа 7:

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

При загрузке аудиокомпонентов мы должны создать новую переменную типа 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);
        }
    }
}
Листинг 11.2. Код компонента spriteComp

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

Alina Lasskaja
Alina Lasskaja

Быть может кто-то из Вас знает игру Sims, к какому жанру она относиться? Жизненная симуляция, ролевая игра, там можно и дома строить.....