Monday, July 1, 2013

VII. Improve our tank game - Adding Sound Files

[This topic is the continuation of the my previous 2D tutorial, Click Here to go to the main post.]
[How to create and use XACT audio File - To upload soon]
We're going to add a new class called soundManager, in your solution explorer. Add a new class name it soundManager.

Paste the following Codes inside the class, make sure the namespace is same with your Game1.cs namespace.

To use this class, we need the ff packages
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Input;

namespace tankGame
{
    class soundManager
    {
        //Creates soundManager class methods, variables
        public AudioEngine audioEngine; //The engine that plays the sound.
        public WaveBank waveBank; //A collection of waves
        public Cue engineSound = null;
        public SoundBank soundBank; //A collection of Sounds
        public soundManager()
        {

        }
        public void loadcontent(ContentManager content)
        {
            audioEngine = new AudioEngine("Content/Audio/sound.xgs"); //Set's the location of the compiled XACT(xgs extension)
            waveBank = new WaveBank(audioEngine, "Content/Audio/Wave Bank.xwb"); //Compiled waveback (xwb extension)
            soundBank = new SoundBank(audioEngine, "Content/Audio/Sound Bank.xsb");//Compiled SoundBound(xsb)
        }
        public void Update(GameTime gameTime)
        {
            audioEngine.Update(); //UPDATES THE SOUND ENGINE
        }  
    }
}
To use this class, you must have a XACT FILE, a wavebank and soundbank which are within the xact file.
We successfully created a class that will play different sounds depending on input, what we need to do is to download and import the sound file(XACT) on our game content. To do this..

Download and unzip this on your game content..
Next go to your game content, to know your game content: View the attached image.

[Copy and paste the rar file> Extract Here]


[Add a folder called Audio Then import the sound files]

[Import it to the game. Add > existing item> browse to your game Content]


[After importing, On your properties:Select all the imported files and set Copy to output Directory : Copy always]


[Change the property of the XACT file("sound"), XACT FILES NEED TO BE COMPILED. Set the Build action to Compile]


After this run the game. The game will automatically compile the xact file to xgs format. The wavebank will be complied to xwb and the soundbank will be compiled to xsb.
Now we cleared all the conditions to use the sound manager class. 

GO TO YOUR Game1.cs, declare a soundManager at the top of the class.

 soundManager soundManager;

On our loadContent method, we need to set soundmanager as new soundmanager then load the content of the soundmanager class..

    soundManager = new soundManager(); 
    soundManager.loadcontent(this.Content ); // passes the Contentmanager of the game and loads the soundmanager class resources.
    soundManager.soundBank.PlayCue("BGM"); //PLAYS THE BGM CUE, the cues are made upon creating a xact file. Which means, you need to open the Xact file then click soundBank to see the cue names on it.

In this xact file that you downloaded, there are 4 cues i made.
"BGM" = background music.
"fire" = sound effect for firing bullets.
 "move" = sound effect for moving tanks.
"explosion" = sound effect to give impact to the explosion methods.


Using the fire cue -  goto to our fireBullets and fireAIBullets, add the line to play the fire cue whenever we fire a bullet..

 private void fireBullets()
        {
            if (player.numberOfBullets > 0)
            {
                gameObject bulletFire = new gameObject();
                bulletFire.alive = true;
                bulletFire.texture = Content.Load("bullet");
                bulletFire.rotation = player.rotation;
                bulletFire.velocity.X = (float)Math.Cos(bulletFire.rotation);
                bulletFire.velocity.Y = (float)Math.Sin(bulletFire.rotation);
                bulletFire.position = new Vector2(player.position.X + bulletFire.velocity.X * 100,
                    player.position.Y + bulletFire.velocity.Y * 100);
                bullet.Add(bulletFire);
                player.numberOfBullets--;
                soundManager.soundBank.PlayCue("fire");
            }

        }
        private void fireAIBullets()
        {
            if (enemy.numberOfBullets > 0)
            {
                gameObject bulletFire = new gameObject();
                bulletFire.alive = true;
                bulletFire.texture = Content.Load("bullet");
                bulletFire.rotation = enemy.rotation;
                bulletFire.velocity.X = (float)Math.Cos(bulletFire.rotation);
                bulletFire.velocity.Y = (float)Math.Sin(bulletFire.rotation);
                bulletFire.position = new Vector2(enemy.position.X + enemy.velocity.X * 100,
                    enemy.position.Y + bulletFire.velocity.Y * 100);
                bullet.Add(bulletFire);
                soundManager.soundBank.PlayCue("fire");
                enemy.numberOfBullets--;
            }

        }


Using the explosion cue - goto detect collision and play the explosion cue when collisions are detected
 private void detectCollisions(gameObject _bullets, gameObject _gameObject){
             Vector2 origin, origin1;
             origin = new Vector2(_bullets.texture.Width / 4, _bullets.texture.Height / 4);
             origin1 = new Vector2(_gameObject.texture.Width / 4, _gameObject.texture.Height / 4);
             BoundingBox bulletBounds = new BoundingBox();
             BoundingBox Player = new BoundingBox();
             Player.Min = new Vector3(_gameObject.position.X  - origin1 .X ,
                 _gameObject.position.Y - origin1.Y, 1f);
             Player.Max = new Vector3(origin1.X /2+ _gameObject .position .X ,
                 origin1.Y + _gameObject.position.Y, 1f);
             bulletBounds.Min = new Vector3(_bullets.position.X - origin.X  ,
                                 _bullets.position.Y-origin.Y , 1f);
             bulletBounds.Max = new Vector3(origin.X /2 + _bullets.position.X,
             origin.Y + _bullets.position.Y, 1f);
            if (_bullets.alive)
             {
                 if (_gameObject.alive)
                 {
                     if (Player.Intersects(bulletBounds))
                     {
                         _bullets.alive = false;
                         _gameObject.life -= 5;
                         soundManager.soundBank.PlayCue("explosion");
                         addExplosions(_bullets);
                     }
                 }
             }
         }

Using the move cue- go to your update method.
 if (currentKeyboardState.IsKeyDown(Keys.Up) && oldKeyboardState.IsKeyDown(Keys.Up))
                    {
                        player.position += player.velocity * moveSpeed;
                        player.position.X = MathHelper.Clamp(player.position.X, player.texture.Width / 4, GraphicsDevice.Viewport.Width - player.texture.Width / 4);
                        player.position.Y = MathHelper.Clamp(player.position.Y, player.texture.Height / 4, GraphicsDevice.Viewport.Height - player.texture.Height / 4);
                        soundManager.soundBank.PlayCue("move");
                    }
                    if (currentKeyboardState.IsKeyDown(Keys.Down) && oldKeyboardState.IsKeyDown(Keys.Down))
                    {

                        player.position -= player.velocity * moveSpeed;
                        player.position.X = MathHelper.Clamp(player.position.X, player.texture.Width / 4, GraphicsDevice.Viewport.Width - player.texture.Width / 4);
                        player.position.Y = MathHelper.Clamp(player.position.Y, player.texture.Height / 4, GraphicsDevice.Viewport.Height - player.texture.Height / 4);
     soundManager.soundBank.PlayCue("move");

                    }



ALSO PLAY MOVE CUE WHEN AI IS MOVING.

   private void AI(GameTime gameTime)
        {
            Random r = new Random();
            float x = player.position.X - enemy.position.X;
            float y = player.position.Y - enemy.position.Y;
            float desiredAngle = (float)Math.Atan2(y, x);
            enemy.rotation = desiredAngle;
            enemy.velocity.X = (float)Math.Cos(enemy.rotation);
            enemy.velocity.Y = (float)Math.Sin(enemy.rotation);
            if (gameTime.TotalGameTime .Seconds % 5 == 0)
            {         
                if (r.Next(1, 2) == 1)
                {

                    if (Vector2.Distance(enemy.position, player.position) > 150)
                    {
                        enemy.position += enemy.velocity * moveSpeed;
                        soundManager.soundBank.PlayCue("move");
                    }
                }
                else
                {
                    enemy.position -= enemy.velocity * moveSpeed;
                    soundManager.soundBank.PlayCue("move");
                }
            }
            
             if( gameTime .TotalGameTime  .Milliseconds % 500 == 0)
                fireAIBullets();
            
            enemy.position.X = MathHelper.Clamp(enemy.position.X, enemy.texture.Width / 4, GraphicsDevice.Viewport.Width - enemy.texture.Width / 4);
            enemy.position.Y = MathHelper.Clamp(enemy.position.Y, enemy.texture.Height / 4, GraphicsDevice.Viewport.Height - enemy.texture.Height / 4);

        }


NOW RUN THE GAME! MAKE SURE YOU ADDED ALL THE CODES IN THE RIGHT PLACE AND RIGHT TIME, ELSE YOU WILL GET AN ERROR.