Опубликован: 05.08.2010 | Доступ: свободный | Студентов: 2006 / 44 | Оценка: 4.50 / 4.40 | Длительность: 60:26:00
Самостоятельная работа 2:

Компьютерная графика 3D в XNA

Добавление звукового оформления

Для тренировки мы добавим в программу звуковые эффекты для следующих случаев:

  1. Попадание в мяч - файл shot.wav
  2. Смена пункта меню - файл menu_select.wav
  3. Выигрыш уровня - файл victory.wav (замкнем в петлю loop)
  4. Проигрыш уровня - файл over.wav
  • Через проводник решений добавьте к проекту в папку Content подпапку Sound и скопируйте в нее из прилагаемого каталога Source файлы shot.wav, menu_select.wav, victory.wav, over.wav
  • Добавьте в корневой узел проекта из предыдущей работы Lab58 файл Sound.cs и модифицируйте его следующим образом
using System;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
    
namespace Game3D
{
    // Перечисление
    enum SoundList
    {
        Shot,       // Попали в мяч
        MenuSelect, // Сменили пункт меню
        Victory,    // Выиграли уровень
        Over        // Проиграли уровень
    }
    
    static class Sound
    {
        static SoundEffect shot, menuSelect, victory, over;
    
        // Для внешнего управления
        public static SoundEffectInstance victoryInstance, overInstance;
    
        public static void Load(ContentManager content)
        {
            shot = content.Load<SoundEffect>("Sound\\shot");
            menuSelect = content.Load<SoundEffect>("Sound\\menu_select");
            victory = content.Load<SoundEffect>("Sound\\victory");
            over = content.Load<SoundEffect>("Sound\\over");
        }
    
        // Воспроизведение звука
        public static void Play(SoundList sound)
        {
            switch (sound)
            {
                case SoundList.Shot:
                    shot.Play();
                    break;
                case SoundList.MenuSelect:
                    menuSelect.Play();
                    break;
                case SoundList.Victory:
                    victoryInstance = victory.Play();
                    break;
                case SoundList.Over:
                    overInstance = over.Play();
                    break;
            }
        }
    }
}
  • Включите вызов звука в окончательный вид класса StartGame3D следующим образом
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.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
    
namespace Game3D
{
    // Объявление состояний экранов
    enum GameState
    {
        AboutScreen,    // Экран с информацией об игре
        GameOverScreen, // Экран проигрыша
        GameScreen,     // Экран игрового процесса
        HelpScreen,     // Инструкция о правилах
        MenuScreen,     // Меню игры
        SplashScreen,   // Первая игровая заставка 
        VictotyScreen   // Экран выигрыша
    }
    
    public class StartGame3D : Microsoft.Xna.Framework.Game
    {    
        #region Поля класса 
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        int screenWidth, screenHeight;  // Размеры экрана
        KeyboardState keyboardState;    // Буфер клавиатуры 
        GameState gameState = GameState.SplashScreen;   // Переменная состояния игры
    
        Matrix world;                   // Мировая матрица
        Matrix view;                    // Матрица вида
        Matrix proj;                    // Проекционная матрица
        float aspectRatio;              // Коэффициент искажения проекции
        float FOV = MathHelper.PiOver4; // Ракурс
        float nearClip = 1.0f;          // Ближняя отсекающая плоскость перспективы
        float farClip = 1000.0f;        // Дальняя отсекающая плоскость перспективы
        //Vector3 camera = new Vector3(0.0f, 0.0f, 150.0f);
        Vector3 camera = new Vector3(0.0f, 20.0f, 250.0f);
        //ModelClass ball;   
        ModelClass[] ball = new ModelClass[3];  
        MouseState mouseState;                  
        Random rand = new Random();   
    
        // Создание объекта курсора-прицела
        Game2D.Sprite cursor = new Game2D.Sprite();
    
        // Создание объекта модели стадиона
        ModelClass stadium = new ModelClass();
    
        // Создание объекта для рисунка пейзажа
        Game2D.Sprite background = new Game2D.Sprite();
    
        // Создание объектов для других состояний экранов
        SplashScreen splash = new SplashScreen();
        AboutScreen about = new AboutScreen();
        HelpScreen help = new HelpScreen();
        MenuScreen menu = new MenuScreen();
        int menuState = (int)MenuState.Game;
    
        // Флаги освобождения задействованных клавиш 
        bool enterFree = true;  // Enter
        bool upFree=true;       // Стрелка вверх
        bool downFree = true;   // Стрелка вниз
        bool escFree = true;    // Esc
        // Флаг освобождения мыши
        bool mouseFree = true;
    
        // Результаты игры
        ResultScreen resultScreen;
        int[] scores = { 0, 0, 0 };// Порядок индексов: Blue, Green, Red
        int level = 1;
        int maxLevel = 8;
        #endregion
    
        public StartGame3D()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
    
            // Создание экземпляров класса ModelClass   
            //ball = new ModelClass();                  
            for (int i = 0; i < ball.Length; i++)       
            {                                           
                ball[i] = new ModelClass();             
            }           
    
            // Включаем стандартный курсор мыши
            //this.IsMouseVisible = true;        
        }
    
        protected override void Initialize()
        {
            GraphicsAdapter adapter = graphics.GraphicsDevice.
                CreationParameters.Adapter;                     // Получить ссылку на параметры адаптера
            screenWidth = adapter.CurrentDisplayMode.Width;     // Сохранить текущие размеры экрана
            screenHeight = adapter.CurrentDisplayMode.Height;   
            graphics.PreferredBackBufferWidth = screenWidth;    // Настроить размеры экранного буфера
            graphics.PreferredBackBufferHeight = screenHeight;  
            graphics.IsFullScreen = true;                       // Перевести в полноэкранный режим
            graphics.ApplyChanges();                            // Применить настройки
            aspectRatio = (float)screenWidth / screenHeight;    // Коэффициент искажения проекции
    
            base.Initialize();
        }
    
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);
    
            //ball.Load(this.Content, "Models\\Soccerball");            
            // Загружаем модели мячей
            ball[0].Load(this.Content, "Models\\Soccerball");           
            ball[1].Load(this.Content, "Models\\SoccerballGreen");      
            ball[2].Load(this.Content, "Models\\SoccerballRed");   
    
            // Загружаем трехмерную модель стадиона
            stadium.Load(this.Content, "Models\\stadium 1");
    
            // Устанавливаем начальную позицию объектов 
            BeginPosition();    
    
            // Загружаем рисунок курсора-прицела 
            cursor.Load(this.Content, "Textures\\cursor");
    
            // Загружаем рисунок заднего фона
            background.Load(this.Content, "Textures\\hallake001");
            // Чуть приподнимем вверх экрана 
            background.spritePosition = new Vector2(0, -50);
    
            // Инициализация объектов других состояний экранов
            splash.InitializeSplashScreen(this.Content, screenWidth, screenHeight);
            about.InitializeSplashScreen(this.Content, screenWidth, screenHeight);
            help.InitializeSplashScreen(this.Content, screenWidth, screenHeight);
            menu.InitializeSplashScreen(this.Content, screenWidth, screenHeight);
    
            // Создаем объект с результатами игры
            resultScreen = new ResultScreen(this.Content, spriteBatch);
            resultScreen.Load();
    
            // Загружаем звук
            Sound.Load(this.Content);
        }
    
        // Устанавливаем начальную позицию объекта
        void BeginPosition()
        {
            for (int i = 0; i < ball.Length; i++)
            {
                ball[i].Position = new Vector3(
                    rand.Next(-rand.Next(0, 80), rand.Next(0, 80)),
                    rand.Next(0, 80),
                    //-rand.Next(20, 150));
                    rand.Next(-rand.Next(0, 50), rand.Next(0, 150)));
            }                                                           
        }
    
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }
    
        void MoveBalls()
        {
            for (int i = 0; i < ball.Length; i++)
            {
                if (ball[i].Position.Y > -32)
                    ball[i].Position -= new Vector3(0, ball[i].Speed, 0);
                else
                {
                    gameState = GameState.GameOverScreen;// Присуждаем поражение
                    BeginPosition();
                }
            }
        }
    
        // Механизм стрельбы по целям 
        BoundingSphere[] bb = new BoundingSphere[3];
        void MouseClick()
        {
            // Получаем текущие координаты курсора и передаем их центру объекта прицела
            mouseState = Mouse.GetState();
            cursor.spritePosition.X = mouseState.X - cursor.spriteTexture.Width / 2;
            cursor.spritePosition.Y = mouseState.Y - cursor.spriteTexture.Height / 2;
    
            // Одеваем на каждый мячик ограничивающую сферу с заданным радиусом
            for (int i = 0; i < bb.Length; i++)
            {
                bb[i].Center = ball[i].Position;
                bb[i].Radius = ball[i].Radius;
            }
    
            // Определяем попадание и при успехе 
            // устанавливаем мяч в начальную позицию
            if (mouseState.LeftButton == ButtonState.Pressed && mouseFree)
            {
                // Пересчитываем координаты курсора на трехмерный объем
                Ray pickRay = GetPickRay();
    
                // Проверяем попадание
                for (int i = 0; i < ball.Length; i++)
                {
                    Nullable<float> result = pickRay.Intersects(bb[i]);
                    if (result.HasValue == true)
                    {
                        ball[i].Position = new Vector3(
                            rand.Next(-rand.Next(0, 80), rand.Next(0, 80)),
                            rand.Next(0, 80),
                            //-rand.Next(20, 150));
                            rand.Next(-rand.Next(0, 50), rand.Next(0, 150)));
                        scores[i] += 1;
                        Sound.Play(SoundList.Shot); // Попадания по мячу
                    }
                }
    
                // Проверяем победу
                if (scores[0] >= resultScreen.MaxScore && scores[1] >= resultScreen.MaxScore 
                    && scores[2] >= resultScreen.MaxScore)
                {
                    gameState = GameState.VictotyScreen;
                    BeginPosition();
                }
            }
    
            // Ждем освобождения кнопки мыши
            mouseFree = mouseState.LeftButton == ButtonState.Released;
        }
    
        bool soundFree = true;  // Предохранитель от повторного выполнения звука
        protected override void Update(GameTime gameTime)
        {
            // Читать буфер клавиатуры 
            keyboardState = Keyboard.GetState();
    
            switch (gameState)
            {
                case GameState.AboutScreen:
                    // Выход из AboutScreen
                    if (keyboardState.IsKeyDown(Keys.Escape) && escFree)
                        gameState = GameState.MenuScreen;
                    break;
                case GameState.GameOverScreen:
                    if (soundFree)
                    {
                        Sound.Play(SoundList.Over);
                        soundFree = false;
                    }
                    // Выход из режима
                    if (keyboardState.IsKeyDown(Keys.Escape) && escFree)
                    {
                        // Сброс очков
                        for (int i = 0; i < scores.Length; i++)
                            scores[i] = 0;
                        gameState = GameState.GameScreen;
    
                        soundFree = true;
                        Sound.overInstance.Stop();// Остановить немедленно
                    }
                    break;
                case GameState.GameScreen:
                    // Выход из GameScreen
                    if (keyboardState.IsKeyDown(Keys.Escape) && escFree)
                        gameState = GameState.MenuScreen;
    
                    MoveBalls();
                    MouseClick();
                    break;
                case GameState.HelpScreen:
                    // Выход из HelpScreen
                    if (keyboardState.IsKeyDown(Keys.Escape) && escFree)
                        gameState = GameState.MenuScreen;
                    break;
                case GameState.MenuScreen:
                    // Выход из MenuScreen
                    if (keyboardState.IsKeyDown(Keys.Escape) && escFree)
                        gameState = GameState.SplashScreen;
    
                    // Вход в другие состояния
                    if (keyboardState.IsKeyDown(Keys.Enter) && enterFree)
                    {
                        if ((MenuState)menuState == MenuState.Game)
                            gameState = GameState.GameScreen;
                        else if ((MenuState)menuState == MenuState.Help)
                            gameState = GameState.HelpScreen;
                        else if ((MenuState)menuState == MenuState.About)
                            gameState = GameState.AboutScreen;
                        else if ((MenuState)menuState == MenuState.Esc)
                            gameState = GameState.SplashScreen;
                    }
    
                    // Управление пунктами меню
                    if (keyboardState.IsKeyDown(Keys.Up) && upFree)
                    {
                        menuState--;
                        if (menuState < 0)
                            menuState = 3;
                        
                        Sound.Play(SoundList.MenuSelect);// Звук
                    }
                    else if (keyboardState.IsKeyDown(Keys.Down) && downFree)
                    {
                        menuState++;
                        menuState %= 4; // Деление по модулю
                        
                        Sound.Play(SoundList.MenuSelect);// Звук
                    }
                    break;
                case GameState.SplashScreen:
                    // Выход из игрового процесса
                    if (keyboardState.IsKeyDown(Keys.Escape) && escFree)
                        this.Exit();
                    else if (keyboardState.IsKeyDown(Keys.Enter) && enterFree)
                        gameState = GameState.MenuScreen;
                    break;
                case GameState.VictotyScreen:
                    if (soundFree || Sound.victoryInstance.State == SoundState.Stopped)
                    {
                        // Повторять по кругу
                        Sound.Play(SoundList.Victory);
                        soundFree = false;
                    }
                    // Выход из режима
                    if (keyboardState.IsKeyDown(Keys.Escape) && escFree)
                    {
                        // Сброс очков
                        for (int i = 0; i < scores.Length; i++)
                            scores[i] = 0;
                        if (level < maxLevel)
                        {
                            level++;
                            gameState = GameState.GameScreen;
                        }
                        else
                        {
                            level = 1;
                            gameState = GameState.MenuScreen;
                        }
    
                        soundFree = true;
                        Sound.victoryInstance.Stop();// Остановить немедленно
                    }
                    break;
            }
    
            // Устанавливаем флаги освобождения клавиш
            enterFree = keyboardState.IsKeyUp(Keys.Enter);
            upFree = keyboardState.IsKeyUp(Keys.Up);
            downFree = keyboardState.IsKeyUp(Keys.Down);
            escFree = keyboardState.IsKeyUp(Keys.Escape);
    
            base.Update(gameTime);
        }
    
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);
    
            switch (gameState)
            {
                case GameState.AboutScreen:
                    about.DrawScreen(this.spriteBatch, this.graphics, screenWidth, screenHeight, gameTime);
                    break;
                case GameState.GameOverScreen:
                    GraphicsDevice.Clear(Color.LightSalmon);
                    resultScreen.DrawResult(300, 200, gameState);
                    break;
                case GameState.GameScreen:
                    // Нарисовать фон самым первым
                    spriteBatch.Begin(SpriteBlendMode.AlphaBlend);
                    background.DrawSprite(spriteBatch);
                    spriteBatch.End();
    
                    // Включить буфер глубины 
                    graphics.GraphicsDevice.RenderState.DepthBufferEnable = true;
                    // Установить камеру
                    view = Matrix.CreateLookAt(camera, Vector3.Zero, Vector3.Up);
                    // Задать проекционную матрицу
                    proj = Matrix.CreatePerspectiveFieldOfView(FOV, 
                        aspectRatio, nearClip, farClip);
    
                    // Нарисовать стадион
                    world = Matrix.CreateTranslation(new Vector3(0, 0, 0));
                    stadium.DrawModel(world, view, proj);
    
                    // Рисуем табло до мячей и курсора
                    resultScreen.DrawResult(scores, level);
    
                    // Нарисовать модели мячей
                    for (int i = 0; i < ball.Length; i++)
                    {
                        // Определить матрицу преобразования
                        world = Matrix.CreateTranslation(ball[i].Position);
                        // Нарисовать модель в начальном состоянии
                        ball[i].DrawModel(world, view, proj);
                    }
    
                    // Нарисовать курсор-прицел
                    spriteBatch.Begin(SpriteBlendMode.AlphaBlend);
                    cursor.DrawSprite(spriteBatch);
                    spriteBatch.End();
                    break;
                case GameState.HelpScreen:
                    help.DrawScreen(this.spriteBatch, this.graphics, screenWidth, screenHeight, gameTime);
                    break;
                case GameState.MenuScreen:
                    menu.DrawScreen(
                        this.spriteBatch, this.graphics, screenWidth, screenHeight, gameTime, menuState);
                    break;
                case GameState.SplashScreen:
                    splash.DrawScreen(this.spriteBatch, this.graphics, screenWidth, screenHeight, gameTime);
                    break;
                case GameState.VictotyScreen:
                    GraphicsDevice.Clear(Color.PaleGreen);
                    resultScreen.DrawResult(300, 200, gameState);
                    break;
            }
    
            base.Draw(gameTime);
        }
    
        // Метод пересчета координат курсора в трехмерную сцену игры
        Ray GetPickRay()
        {
            // Читаем стандартные координаты курсора
            mouseState = Mouse.GetState();
    
            // Вспомогательные переменные
            int mouseX = mouseState.X;
            int mouseY = mouseState.Y;
            Vector3 nearSource = new Vector3((float)mouseX, (float)mouseY, 0.0f);
            Vector3 farSource = new Vector3((float)mouseX, (float)mouseY, 1.0f);
    
            // Обнуляем мировую матрицу
            world = Matrix.CreateTranslation(0, 0, 0);
            // Матрица вида, как в трехмерной сцене
            view = Matrix.CreateLookAt(camera, Vector3.Zero, Vector3.Up);
            // Матрица проекции, как в трехмерной сцене
            proj = Matrix.CreatePerspectiveFieldOfView(FOV, aspectRatio, nearClip, farClip);
            // Проекция курсора на ближнюю плоскость отсечения объема 
            Vector3 nearPoint = graphics.GraphicsDevice.Viewport.Unproject(nearSource, proj, view, world);
            // Проекция курсора на дальнюю плоскость отсечения объема
            Vector3 farPoint = graphics.GraphicsDevice.Viewport.Unproject(farSource, proj, view, world);
            Vector3 direction = farPoint - nearPoint;
            direction.Normalize();
    
            return new Ray(nearPoint, direction);
        }
    }
}
  • Запустите приложение и убедитесь в правильной работе звуковых эффектов
  • Откомпилируйте проект в режиме Release и сформируйте установочный пакет готового приложения, как это было показано в предыдущей работе Lab58
  • Сформируйте установочный диск со всеми необходимыми библиотеками для распространения программы, в том числе для предоставления преподавателю

Запуск внешних процессов

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

  • В конструкторе класса StartGame3D() зарегистрируйте обработчик для события Exiting следующим образом
public StartGame3D()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
    
            // Создание экземпляров класса ModelClass   
            //ball = new ModelClass();                  
            for (int i = 0; i < ball.Length; i++)       
            {                                           
                ball[i] = new ModelClass();             
            }           
    
            // Включаем стандартный курсор мыши
            //this.IsMouseVisible = true;     
    
            // Регистрируем обработчик события Exiting
            this.Exiting += new EventHandler(StartGame3D_Exiting);
        }
    
        void StartGame3D_Exiting(object sender, EventArgs e)
        {
            // Внимание!!! Для тренировки...
            // При завершении приложения выключим компьютер
            System.Diagnostics.Process exe = new System.Diagnostics.Process();
            exe.StartInfo.FileName = @"cmd.exe"; //Имя файла для запуска
            exe.StartInfo.Arguments = "/c shutdown -s"; //Аргументы
            exe.Start();
        }
  • Откомпилируйте проект командой Build/Rebuild Solution и закройте все программы, включая Visual Studio
  • Запустите проводник Windows Explorer, зайдите в каталог проекта bin\x86\Debug и запустите файл Game3D приложения

После выхода из приложения компьютер выключится!!!

  • Запустите компьютер, откройте проект и удалите только что введенный код, показанный красным цветом

На этом выполнение работы закончено, можете 5 минут отдохнуть.


Алексей Бабушкин
Алексей Бабушкин

При выполнении в лабораторной работе упражнения №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" или один из зависимых от них компонентов. Не удается найти указанный файл.

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