Volver al Inicio Microsoft Student Tech Club: Universidad Libre

Tutorial de XNA: Sonidos en el juego

Hasta ahora nuestro juego es mudo. Es momento de añadirle mas emoción y realismo, y el camino para eso es agregándole sonidos. Estos son los pasos:

Paso 1: Buscar en Internet sonidos o generar sus propios sonidos y guardarlos en archivos con extensión .wav

Paso 2: Ejecutar el Microsoft Cross-Platform Audio Creation Tool 3 (XACT3) y crear un nuevo proyecto

Paso 3: Se crea un nuevo "Wave Bank"

Paso 4: Arrastre los archivos .wav a la ventana de Wave Bank

Paso 5: Creamos un nuevo "Sound Bank"

Paso 6: Arrastramos de "Wave Bank" a "Sound Bank"

Paso 7: Y arrastramos de "Sound Bank" a "Cue Name" y grabamos el proyecto.

Paso 8: Esto es lo que se obtiene

Paso 9: En "Content" damos Agregar "Nueva carpeta" y la llamamos "Audio"

Paso 10: Vamos a la carpeta donde tenemos nuestro proyecto de Visual C# y navegamos por las carpetas hasta llegar a la de Content, allí debe estar la de Audio vacía

Paso 11: Arrastramos del escritorio todo el proyecto de sonido (junto con los sonidos) a esa carpeta de Audio

Paso 12: A la carpeta de Audio le agregamos "Elemento existente..."

Paso 13: Y escogemos a SonidosJuego.xap

Paso 14: Ya queda en nuestro proyecto, ahora veamos las propiedades de SonidosJuego.xap

Paso 15: Cambiamos la propiedad "Content Processor" por Sound Effect - XNA Framework

Paso 16: Agregar el código requerido para el manejo de sonidos. Atributos de la clase Game1.cs

//Audio
AudioEngine MotorAudio;
SoundBank BancoSonido;
WaveBank BancoAudio;

Cargando los sonidos en LoadContent()

//Cargar el sonido (ojo con la extension .xgs)
MotorAudio = new AudioEngine("Content\\Audio\\SonidosJuego.xgs"); //xna game studio
BancoSonido = new SoundBank(MotorAudio, "Content\\Audio\\Sound Bank.xsb"); //xna sound bank
BancoAudio = new WaveBank(MotorAudio, "Content\\Audio\\Wave Bank.xwb"); //xna wave bank

Ejecutando los sonidos cuando se dispara o cuando hay una colisión.

//Sonido de la explosión
BancoSonido.PlayCue("Explosion");

y

//Sonido del cohete
BancoSonido.PlayCue("disparo");

Este es el código completo

using System;
using System.Collections.Generic;
using System.Linq;
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 PrimerJuego
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch; //Contenedor de los sprite
        Texture2D Fondo; //Variable de tipo textura que tendrá el fondo
        Rectangle rectFondo; //Un rectángulo donde estará la textura del fondo
        ObjetosJuego lanzador; //El lanzador
        ObjetosJuego baselanzador; //Base del lanzador
        //Almacena el estado anterior del ratón
        MouseState anteriorRaton;
        //Almacena el estado anterior del teclado
        KeyboardState anteriorTeclado;
        //Cohetes
        ObjetosJuego[] cohetes;
        const int MAXCOHETES = 7;
        //Enemigos
        ObjetosJuego[] enemigos;
        const int MAXENEMIGOS = 6;
        const float alturaMax = 0.1f; //No pegado del techo
        const float alturaMin = 0.5f; //La mitad de la pantalla
        const float velocidadMax = 5.0f;  //Máxima velocidad
        const float velocidadMin = 1.0f; //Mínima velocidad
        Random aleatorio = new Random();
        //Puntaje
        int Puntaje = 0; //Lleva cuantos enemigos han sido destruidos
        SpriteFont fuente; //Variable tipo de letra para mostrar el puntaje
        //Sonidos del Juego
        AudioEngine MotorAudio;
        SoundBank BancoSonido;
        WaveBank BancoAudio;
        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
            //Utiliza genéricos <> por eso el uso de <> En C++ se llaman plantillas. Content carga el contenido binario.
            Fondo = Content.Load<Texture2D>("Imagenes\\FondoJuego");
            //El rectángulo en el que estará contenido el fondo
            rectFondo = new Rectangle(0, 0, graphics.GraphicsDevice.Viewport.Width, graphics.GraphicsDevice.Viewport.Height);
            //Cargar e inicializar el Lanzador
            lanzador = new ObjetosJuego(Content.Load<Texture2D>("Imagenes\\Lanzador")); //No es necesaria la extension .tga
            lanzador.posicion = new Vector2(160, 530); //Posicion del lanzador
            //Cargar e inicializar la base
            baselanzador = new ObjetosJuego(Content.Load<Texture2D>("Imagenes\\Base")); //No es necesaria la extension .tga
            baselanzador.posicion = new Vector2(70, 560); //Posicion de la base del lanzador
            //Cargar e inicializar los cohetes
            cohetes = new ObjetosJuego[MAXCOHETES];
            for (int Cont = 0; Cont < MAXCOHETES; Cont++)
                cohetes[Cont] = new ObjetosJuego(Content.Load<Texture2D>("Imagenes\\Cohete"));
            //Cargar e inicializar los enemigos
            enemigos = new ObjetosJuego[MAXENEMIGOS];
            for (int Cont = 0; Cont < MAXENEMIGOS; Cont++)
                enemigos[Cont] = new ObjetosJuego(Content.Load<Texture2D>("Imagenes\\Chatarra"));
            //Cargar la fuente
            fuente = Content.Load<SpriteFont>("Fuentes\\TipoLetraJuego");
            //Cargar el sonido (ojo con la extension .xgs)
            MotorAudio = new AudioEngine("Content\\Audio\\SonidosJuego.xgs"); //xna game studio
            BancoSonido = new SoundBank(MotorAudio, "Content\\Audio\\Sound Bank.xsb"); //xna sound bank
            BancoAudio = new WaveBank(MotorAudio, "Content\\Audio\\Wave Bank.xwb");  //xna wave bank
        }
        /// <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)
        {
            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();
            // Código para leer el estado del Gamepad de una XBOX. Se considera que hay un jugador al menos.
            GamePadState estadoControl = GamePad.GetState(PlayerIndex.One);
            //Como hay que tener en cuenta los controles del XBOX llamados thumbstick, se
            //observa que botón del XBOX oprimió, eso genera una constante algo grande por lo que se multiplica por 0.1
            lanzador.rotacion += estadoControl.ThumbSticks.Left.X * 0.1f;
//Esta es una compilación condicional. El teclado y el mouse solo son leídos si la aplicación ejecuta en un PC
#if !XBOX
            //Código para leer el teclado
            KeyboardState estadoTeclado = Keyboard.GetState();
            if (estadoTeclado.IsKeyDown(Keys.Left)) lanzador.rotacion -= 0.1f;  //Gira el lanzador hacia la izquierda
            if (estadoTeclado.IsKeyDown(Keys.Right)) lanzador.rotacion += 0.1f; //Gira el lanzador hacia la derecha
            //Dispara un solo cohete.
            //Chequea si el usuario mantiene presionada la tecla de disparo por lo que hace caso omiso a eso, 
            //el usuario debe presionar y soltar la tecla de disparo para lanzar mas misiles.
            if (estadoTeclado.IsKeyDown(Keys.Space) && anteriorTeclado.IsKeyUp(Keys.Space))
                DispararCohete();
            //Se actualiza el estado del teclado
            anteriorTeclado = estadoTeclado;
            //Código para leer el ratón
            MouseState Raton = Mouse.GetState();
            //Si movió el ratón entonces el lanzador cambia de ángulo 
            if (Raton != anteriorRaton)
            {
                int DiferX = Raton.X - anteriorRaton.X; //La diferencia entre la anterior posición del ratón y la nueva.
                lanzador.rotacion += (float)DiferX / 100; //El movimiento en X del ratón cambia el ángulo del lanzador
            }
            //Se actualiza el estado del ratón
            anteriorRaton = Raton;
#endif
            //Esta instrucción limita entre 0 y 90 grados el giro del lanzador. Recordar que se hace uso de radianes.
            lanzador.rotacion = MathHelper.Clamp(lanzador.rotacion, -MathHelper.PiOver2, 0);
            //Actualiza los cohetes
            ActualizaCohetes();
            //Actualiza los enemigos
            ActualizaEnemigos();
            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
            //Se inicia el spritebatch (Entre Begin y End se dibuja en cada unidad de tiempo los sprites)
            spriteBatch.Begin(SpriteBlendMode.AlphaBlend);
            //Dibujar el fondo combinando el color blanco con el fondo
            spriteBatch.Draw(Fondo, rectFondo, Color.White);
            //Dibuja la base del lanzador combinando con blanco
            spriteBatch.Draw(baselanzador.sprite, baselanzador.posicion, Color.White);
            /* Dibuja el lanzador como tal, estos son los parámetros
             * Parámetro 1: El sprite del lanzador
             * Parámetro 2: La posición del lanzador
             * Parámetro 3: null porque es solo una imagen (no una sucesión de estas
             * Parámetro 4: Color.White, combinación de color
             * Parámetro 5: Angulo de rotación por defecto
             * Parámetro 6: Centro, el centro del sprite para girarlo después
             * Parámetro 7: Escala a dibujar 
             * Parametro 8: Dibujar tal como es el sprite (no reflejo vertical ni horizontal)
             * Parámetro 9: Ponerlo en la capa superior */
            spriteBatch.Draw(lanzador.sprite, lanzador.posicion, null, Color.White, lanzador.rotacion, lanzador.centro, 0.6f, SpriteEffects.None, 0);
            //Dibuja cada cohete
            foreach (ObjetosJuego cohete in cohetes)
                if (cohete.esta_activo == true)
                    spriteBatch.Draw(cohete.sprite, cohete.posicion, null, Color.White, cohete.rotacion, cohete.centro, 0.2f, SpriteEffects.None, 0);
            //Dibuja cada enemigo
            foreach (ObjetosJuego enemigo in enemigos)
                if (enemigo.esta_activo == true)
                    spriteBatch.Draw(enemigo.sprite, enemigo.posicion, null, Color.White, enemigo.rotacion, enemigo.centro, 0.2f, SpriteEffects.None, 0);
            //Dibuja el puntaje
            spriteBatch.DrawString(fuente, "Destruido: " + Puntaje.ToString(), new Vector2(80, 60), Color.White);
            //Finaliza el "ciclo" de los sprite
            spriteBatch.End();
            base.Draw(gameTime);
        }
        //Metodo llamado desde Update
        public void DispararCohete()
        {
            //Busca un cohete inactivo
            foreach (ObjetosJuego cohete in cohetes)
            {
                //Si encuentra un cohete inactivo
                if (cohete.esta_activo == false)
                {
                    //Activa el cohete (para que sea dibujado)
                    cohete.esta_activo = true;
                    //El cohete inicia en la posición del lanzador
                    cohete.posicion = lanzador.posicion;
                    //En que dirección y a que velocidad sale el cohete. Hay que tener en cuenta la rotación del lanzador
                    cohete.velocidad = new Vector2((float)Math.Cos(lanzador.rotacion), (float)Math.Sin(lanzador.rotacion)) * 4.0f;
                    //Rote el sprite del cohete para que coincida con el del lanzador
                    cohete.rotacion = lanzador.rotacion;
                    //Sonido del cohete
                    BancoSonido.PlayCue("disparo");
                    return;
                }
            }
        }
        //Método llamado desde Update
        public void ActualizaCohetes()
        {
            //Va de cohete en bala
            foreach (ObjetosJuego cohete in cohetes)
                if (cohete.esta_activo == true)
                {
                    //Solo es actualizar la velocidad porque el vector se actualiza gracias a esa magnitud
                    cohete.posicion += cohete.velocidad;
                    //Chequea la colisión
                    //Deduce el rectángulo del cohete y debe tener en cuenta el tamaño con que se esté dibujando en pantalla en Draw()
                    Rectangle rectCohete = new Rectangle((int)cohete.posicion.X, (int)cohete.posicion.Y, (int) (cohete.sprite.Width*0.2), (int) (cohete.sprite.Height*0.2));
                    //Chequea de enemigo en enemigo si el cohete lo colisiona
                    foreach (ObjetosJuego enemigo in enemigos)
                    {
                        //Deduce el rectángulo del enemigo y debe tener en cuenta el tamaño con que se esté dibujando en pantalla en Draw()
                        Rectangle rectEnemigo = new Rectangle((int)enemigo.posicion.X, (int)enemigo.posicion.Y, (int) (enemigo.sprite.Width*0.2), (int) (enemigo.sprite.Height*0.2));
                        //Si ambos rectángulos se intersectan
                        if (rectCohete.Intersects(rectEnemigo) == true)
                        {
                            enemigo.esta_activo = false; //inactiva el enemigo
                            cohete.esta_activo = false; //inactiva el cohete
                            Puntaje++;
                            //Sonido de la explosion
                            BancoSonido.PlayCue("explosion");
                            break;
                        }
                    }
                    //Si el cohete se sale de la pantalla entonces se desactiva
                    if (rectFondo.Contains(new Point((int)cohete.posicion.X, (int)cohete.posicion.Y)) == false)
                        cohete.esta_activo = false;
                }
        }
        //Método llamado desde Update
        public void ActualizaEnemigos()
        {
            foreach (ObjetosJuego enemigo in enemigos)
            {
                if (enemigo.esta_activo == true)
                {
                    //El enemigo avanza a determinada velocidad
                    enemigo.posicion += enemigo.velocidad;
                    //Si el enemigo se sale de la pantalla
                    if (rectFondo.Contains(new Point((int)enemigo.posicion.X, (int)enemigo.posicion.Y)) == false)
                        enemigo.esta_activo = false;
                }
                else
                {
                    //Activa el enemigo
                    enemigo.esta_activo = true;
                    //Interpolación. Posición Y aleatoria.
                    enemigo.posicion = new Vector2(rectFondo.Right, MathHelper.Lerp((float)rectFondo.Height * alturaMin, (float)rectFondo.Height * alturaMax, (float)aleatorio.NextDouble()));
                    //Velocidad del enemigo. Aleatoria.
                    enemigo.velocidad = new Vector2(MathHelper.Lerp(-velocidadMin, -velocidadMax, (float)aleatorio.NextDouble()), 0);
                }
            }
        }
    }
}

 

 

Volver al Inicio Célula Microsoft. Universidad Libre