Friday, June 28, 2013

VI. Battle City? Rip off (tank game)


[Watch the project output]

Lesson VI objectives..

-Use math related commands,
-Player state management
-Build or Create computer AI
-Importance of Inheritance and OOP

Create a new project name it tankGame

Project Files:



[save as background]

[save as tank]


[save as bullet]



First of all, let's create a new class name gameObject. The class will hold a number of variables that will make it easier for us to edit and manipulate it's value..
To create a new class, see attached image.

[Figure 1: creating a new class]


Once you created a new class named gameObject, add the following lines at the top of your source code.

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;


Now declare the values we need, set it public so we can easily manipulate their values..

 class gameObject
    {
       public Vector2 position = Vector2.Zero;
       public float rotation = 0f;
       public int numberOfBullets = 5;
       public  Texture2D texture;
       public bool alive = true;
       public int life =100;
  public Vector2 velocity = Vector2.Zero;
    }

Go to your game.cs source code and create a new instance of gameObject..
Declare the following variables.

gameObject enemy, player;
const float moveSpeed = 2f;
const int MaxBullet = 5;
At your loadContent, set the gameobject as new gameobject..

 player = new gameObject();
 enemy = new gameObject();
 player.texture = Content.Load("tank");
 enemy.texture = Content.Load("tank");
 enemy.position = new Vector2(400, 100);
Vector2 tempposition;
 player.position = new Vector2(100,100);

Declare a variable for the background..
Texture2D background;

At the load content, set it's value..
background = Content.Load("background"); 
// MAKE SURE TO DOWNLOAD AND IMPORT THE TEXTURE IN YOUR GAME CONTENT

At your draw method, draw the background and the gameObject We need to draw it first so that it is on the lowest layer of drawables..

 spriteBatch.Draw(background,  Vector2.Zero, Color.White );
 spriteBatch.Draw(enemy.texture, enemy.position, Color.White);
 spriteBatch.Draw(player.texture, player.position, Color.White);

RUN THE GAME



[SCREENSHOT WILL NOT THE SAME WITH YOUR GAME SINCE I EDITED THE TANK TEXTURE]


After running the game, you'll notice that the texture of the tank are too big for the game screen bounds..
Also, at this lesson we declared a float variable name rotation. We need to update the rotation of the texture depending on the input. To make this possible, we are going to draw the texture in the detailed way..

 spriteBatch.Draw(enemy.texture, enemy.position,
               null, Color.White, enemy.rotation,
               new Vector2 (enemy .texture .Width /2, enemy .texture .Height /2),
               0.5f, SpriteEffects.None, 0);
[SCREENSHOT WILL NOT THE SAME WITH YOUR GAME SINCE I EDITED THE TANK TEXTURE]

To use the 6th usage of spriteBatch.Draw, we need to know the
-Texture
-Positon
-Source Rectangle.. this will draw a specific rectangle in a texture.. in this lesson we'll set it to null so that the entire texture will be drawn..
-Color
-Rotation
-Origin - the middile point of the texture
-scale
-SpriteEffect - flip horizontal, vertical..
-Layer ( back =1 , front = 0)

We set the the scale to 0.5f so it will be resize to size * 0.5
Run the game..
[SCREENSHOT WILL NOT THE SAME WITH YOUR GAME SINCE I EDITED THE TANK TEXTURE]
You'll notice that the texture has been resize into 0.5f scale.. 
Next draw the player tank..
if(player.alive){
  spriteBatch.Draw(player.texture, player.position,
            null, Color.White, player.rotation,
            new Vector2(player.texture.Width / 2, player.texture.Height / 2),
            0.5f, SpriteEffects.None, 0);
}
if (enemy.alive)
            {
                spriteBatch.Draw(enemy.texture, enemy.position,
                   null, Color.White, enemy.rotation,
                   new Vector2(enemy.texture.Width / 2, enemy.texture.Height / 2),
                   0.5f, SpriteEffects.None, 0);
             }

Now, let's declare the input handlers..
    KeyboardState currentKeyboardState, oldKeyboardState; // AT THE TOP OF THE CLASS
In the Update Method, configure the input handlers

  currentKeyboardState = Keyboard.GetState();
if (currentKeyboardState.IsKeyDown(Keys.Right) && oldKeyboardState.IsKeyDown(Keys.Right))
            {
              player.rotation += 0.1f;
            }
            if (currentKeyboardState.IsKeyDown(Keys.Left) && oldKeyboardState.IsKeyDown(Keys.Left))
            {
                 player.rotation -= 0.1f; 
            }
oldKeyboardState = currentKeyboardState;

Run the game and press left or right key, you'll notice that our tank is rotating..
Next the movement..

NOTE : I EDITED THE TANK TEXTURE,  THE OLD TEXTURE IS FACING UP.. I ROTATED IT FACING RIGHT SINCE XNA COORDINATE STARTS AT 3 OCLOCK..

ADD the following lines in your update method after the Keys.Left statement..
   if (currentKeyboardState.IsKeyDown(Keys.Up) && oldKeyboardState.IsKeyDown(Keys.Up))
            {
                player.position += player.velocity * moveSpeed;
            }
            if (currentKeyboardState.IsKeyDown(Keys.Down) && oldKeyboardState.IsKeyDown(Keys.Down))
            {
                player.position -= player.velocity * moveSpeed;
            }

If we press up, it will accelerate forward, else backward..
Then create a new method called updateTank..

 private void updateTank()
        {
            player.velocity.X = (float)Math.Cos(player.rotation )  ;
            player.velocity.Y = (float)Math.Sin(player.rotation)  ;
           
        }
To get the X velocity of an object, get it's Cos Rotation, and for Y sin Rotation..
The output datatype of Math.Cos and Math.Sin is double, so we need to convert it to float since position needs to be float.. example: 1.5f, 2.01 etc..

At the top of your update method add : 
  updateTank();

RUN THE GAME!!!!
Make your character Move..

We need to make sure if the player is dead, it can't update its position so wrap the input handlers with a new if statement..

    if (player.alive)
            {
                if (currentKeyboardState.IsKeyDown(Keys.Right) && oldKeyboardState.IsKeyDown(Keys.Right))
                {
                    player.rotation += 0.1f;
                }
                if (currentKeyboardState.IsKeyDown(Keys.Left) && oldKeyboardState.IsKeyDown(Keys.Left))
                {
                    player.rotation -= 0.1f;
                }
                if (currentKeyboardState.IsKeyDown(Keys.Up) && oldKeyboardState.IsKeyDown(Keys.Up))
                {
  tempposition = player.position;
                    player.position += player.velocity * moveSpeed;
                }
                if (currentKeyboardState.IsKeyDown(Keys.Down) && oldKeyboardState.IsKeyDown(Keys.Down))
                {
                    player.position -= player.velocity * moveSpeed;
  tempposition = player.position;
                }
            }

NOW PROJECTILES!!!!!

Declare the following lines..
  List bullet = new List();
We want to have a list of bullets since its number may vary..
Let's create a method for the projectiles, name it updateBullets.
Also create a method for firing projectiles call it fireBullets..

     private void updateBullets()
        {
        }
        private void fireBullets()
        {
        }

Now let's add a fire command in the input handler...

if (currentKeyboardState.IsKeyDown(Keys.Space) && oldKeyboardState.IsKeyUp (Keys.Space))
                {
                    fireBullets();
                }
Next: Build the events for firing bullets..
  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 * 80,
                    player.position.Y + bulletFire.velocity.Y * 80);
                bullet.Add(bulletFire);
            }

        }

Then build the events for the updateBullets()

   private void updateBullets()
        {
            foreach (gameObject obj in bullet)
            {
                if (obj.alive)
                {
                    obj.position += obj.velocity * moveSpeed * 2;
                    spriteBatch.Draw(obj.texture, obj.position,
           null, Color.White, obj.rotation,
           new Vector2(obj.texture.Width / 2, obj.texture.Height / 2),
           0.5f, SpriteEffects.None, 0);
                }
            }
        }

ADD the updateBullets before the spritebatch.end at your draw method.. We are going to put it on draw method because updateBullets contains draws... 

updateBullets(); 



Run the GAME!!!


[OMG !! WE RELEASED PROJECTILES BUT IT DOESN'T HIT ANYTHING!!]

THE BULLET SEEMS TO BE UNLIMITED !!
To fix this, let's edit our fireBullets method..

 private void fireBullets()
        {
            if (player.numberOfBullets > 0)
            {
                gameObject bulletFire = new gameObject();
                bulletFire.alive = true; // WE JUST FIRED IT, SO MAKE IT ALIVE !!!
                bulletFire.texture = Content.Load("bullet"); // LOAD THE BULLET TEXTURE
                bulletFire.rotation = player.rotation; //THE BULLET ROTATION IS THE SAME WITH THE PLAYER ROTATION
                bulletFire.velocity.X = (float)Math.Cos(bulletFire.rotation); //TRIGO
                bulletFire.velocity.Y = (float)Math.Sin(bulletFire.rotation);//TRIGO
                bulletFire.position = new Vector2(player.position.X + bulletFire.velocity.X * 100,
                    player.position.Y + bulletFire.velocity.Y * 100); // HERE, WE ADDED THE BULLETVELOCITY * 100 to the player position.. the bullet will come out of the turret.. There are many methods to do this, but i felt lazy so i just copy paste it anyway..
                bullet.Add(bulletFire); //ADD THE BULLETFIRE INTO THE LIST OF BULLETS
               player.numberOfBullets--; //NO MORE CHEATS FOR YOU, subtract 1 bullet every Fire!!
            }
        }

OMFG !! MY BULLETS RAN OUT? WHAT SHOULD I DO??
Create an auto reload method.. Let's call it reloadBullets..
  void reloadBullets(GameTime gameTime) // USE THE GAMETIME FOR AUTO RELOAD BULLET
        {
             if (gameTime.TotalGameTime.Seconds % 5 == 0)//IN EVERY 5 seconds past, reload bullets!!!
             {
                 if (player .numberOfBullets  < MaxBullet )
                     player .numberOfBullets  += 1;
   if (enemy.numberOfBullets < MaxBullet)
                     enemy.numberOfBullets++;
             }
        }


Then at your update method add.. 
     reloadBullets(gameTime);

To check your bullets add this line to your draw method.. Draw it before the spritebatch.End...
 spriteBatch.DrawString(Content.Load("font"), "BULLETS: " + player.numberOfBullets.ToString(), Vector2.Zero, Color.White);
//I USED A SHORTCUT HERE SINCE I'M TOO LAZY AND SLEEPY TO SHOW EVERY DETAILED AS@RDASFASDJWDASD.. zzzzzzzzzzz
[Font Null?? At your game content > right Click > Add > New Item > click SpriteFont then name it font..]
           
RUN THE GAME!!!
[OMG 5-2 = 3 !! ] 

So we have a working method for updating and firing bullets. What we need next is to make a new method that will detect collision between the gameObjects. Let's write the detectCollisions(gameObject gameObject)

   private void detectCollisions(gameObject _bullets, gameObject _gameObject){
//_bullets will be from the bulletlist and _gameObject is the player that we want to check the collision with the bullets in the bullet list
             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;
                 }
             }
            }
         }
In this method, we set the origin to 1/4 of the texture. Why? because we re-sized the texture to 1/2, which means the result origin will be  (1/2 )/2 = 1/4.. 
OMG !! WTF is this BoundingBox?? 
BoundingBox are used in collision detections. 
Why did we use Bounding box instead of rectangle? 
We can use rectangle, but since our textures are rotating. It will be a hassle to use it, rectangles are hard to rotate. So let's introduce the boundingBox.. (See attached image for more info)

     if (_bullets.alive) //We don't want to have dead bullets killing us.. So if it's alive, check for who will get hit by it
             {
                 if (Player.Intersects(bulletBounds)) // if the bounding box of player intersects with the bounding box of bullet
                 {
                     _bullets.alive = false; // kill bullet first before inflicting the damage,
                     _gameObject.life -= 5; //inflict the damage
                 }
             }
Let's Add the collision detection to our game..
Go to your updateBullets method, add detect collision(obj(bullet), enemy and  another 1 for the player

 private void updateBullets()
        {
            foreach (gameObject obj in bullet)
            {
                if (obj.alive)
                {
                    obj.position += obj.velocity * moveSpeed * 0.5f;
                    spriteBatch.Draw(obj.texture, obj.position,
           null, Color.White, obj.rotation,
           new Vector2(obj.texture.Width / 2, obj.texture.Height / 2),
           0.5f, SpriteEffects.None, 0);
                    detectCollisions(obj, player); 
                    detectCollisions(obj, enemy);
                }
            }

        }
We added the following lines in the update bullets since we are updating bullets every one pass of draw method. What's next? Let's check for the life of the game object.. First let's draw the life value of the tanks in our screen so we can see if upon collision, 5 points will be deducted.

On your draw method, add the following lines before spritebatch.end..
spriteBatch.DrawString(Content.Load("font"), "LIFE: " + player.life.ToString(),
             new Vector2(player.position.X - player.texture.Width / 2, player.position.Y - player.texture.Height * 0.5f), Color.White);
            spriteBatch.DrawString(Content.Load("font"), "ENEMY LIFE: " + enemy.life.ToString(),
             new Vector2(GraphicsDevice .Viewport .Width - 200 ,0), Color.White);
            
Then let's make an if statement to check if the hp <= 0..
On your update method, add the following if statements..

   if (enemy.life <= 0)
            {
                enemy.alive = false;
            }
            if (player.life <= 0)
            {
                player.alive = false;
            }
Now we can kill the player if it has 0 HP..

What's next? Restrict the players to go off the game screen bounds..
At your update method, let's add the clamp..

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);
                    
clamp usage = MathHelper.Clamp(value,min,max)
For the X position, we want to clamp it to the graphicDevice Viewpoirt.Witdh - origin as it's max, and it's min is the origin of the texture..
For the Y position, we want to clamp it to the graphicDevice Viewpoirt.Height - origin as it's max, and it's min is the origin of the texture.

Now the player can't get out of bounds...



We're almost done, we only need to set an effect when the bullet hits a player. To do that, download this texture and import to your game..
[save as explosion]

I'll introduce you to a new method in drawing textures, we're going to use the BlendState.Additive..
From the word it self, we will blend the texture with another texture. On bulletCollision, we want to draw several explosions with random rotation making it look that it is moving. Let's start doing it's method..

First declare a list of gameobject for explosion..

        List Explosion = new List();

Next : 
    private void addExplosions(gameObject _bullet)
        {
            gameObject explode = new gameObject();
            explode.alive = true;
            explode.position = _bullet.position;
            explode.texture = Content.Load("explosion");
            explode.life = 100;
            Explosion.Add(explode);
        }
Then add it when a bullet hits someone, at your detectCollision method..

if (Player.Intersects(bulletBounds))
                 {
                     _bullets.alive = false;
                     _gameObject.life -= 5;
                     addExplosions(_bullets);
                 }

Create a method that will draw explosions..

  private void drawExplosion(gameObject explosion)
        {
            spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.Additive);
            if (explosion.alive)
            {
                for (int x = 0; x <= 15; x++)
                {
                    Random r =new Random ();

                    spriteBatch.Draw(explosion.texture, explosion.position,
              null, Color.White, r.Next (1,4),
              new Vector2(explosion.texture.Width / 2, explosion.texture.Height / 2), 0.5f, SpriteEffects.None, 0);

                }
                explosion.life -=2  ;
                if (explosion.life <= 0)
                {
                    explosion.alive = false;
                }
            }
            spriteBatch.End();
        }

At the end of your draw method, before the "}".. Draw the explosion.. We don't want to put it inside the exisiting spritebatch process, we created a new spritebatch process with different settings. So it must be after the spriteBatch.End()

    foreach (gameObject explode in Explosion)
            {
                drawExplosion(explode);
            }
Run the game!!!


We don't want to make the 2 tanks collide with each other, so let's create a method that will keep the two tanks apart from each other..


   private void detectCollisionsAgainstObject(gameObject _gameObject1, gameObject _gameObject)
         {
             //_bullets will be from the bulletlist and _gameObject is the player that we want to check the collision with the bullets in the bullet list
             Vector2 origin, origin1;
             
             origin = new Vector2(_gameObject1.texture.Width / 4, _gameObject1.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(_gameObject1.position.X - origin.X,
                                 _gameObject1.position.Y - origin.Y, 1f);
             bulletBounds.Max = new Vector3(origin.X / 2 + _gameObject1.position.X,
                 origin.Y + _gameObject1.position.Y, 1f);
             if (_gameObject1.alive)
             {
                 if (_gameObject.alive)
                 {
                     if (Player.Contains (bulletBounds) != ContainmentType .Disjoint )
                     {
                         _gameObject1.position = tempposition;
                       
                     }
                 }
             }
         }

And put it on the update method..'
 detectCollisionsAgainstObject(player, enemy);

For the AI method add this line in your update, then write the AI method...

if(enemy.alive) AI(gameTime);

   private void AI(GameTime gameTime)
        {
            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)
            {
                Random r = new Random();
                if (r.Next(1, 2) == 1)
                {

                    if (Vector2.Distance(enemy.position, player.position) > 300)
                    {

                        enemy.position += enemy.velocity * moveSpeed;
                        
                    }
                }

                else
                {
                    enemy.position -= enemy.velocity * moveSpeed;
                }
            }
            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)
      if( gameTime .TotalGameTime  .Milliseconds % 500 == 0)
                fireAIBullets();
            
        }

Then create a fireAiBulletMethod..
      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);
                enemy.numberOfBullets--;
            }

        }

We;re almost done, we just need to show a message whenever a player dies..
In your draw method add a else statement on if (player.alive) and if(enemy.alive)..
    if (enemy.alive)
            {
                spriteBatch.Draw(enemy.texture, enemy.position,
                   null, Color.White, enemy.rotation,
                   new Vector2(enemy.texture.Width / 2, enemy.texture.Height / 2),
                   0.5f, SpriteEffects.None, 0);
            }
            else
            {
                spriteBatch.DrawString(Content.Load("font"), "YOU WIN!: ", new Vector2(GraphicsDevice.Viewport.Width / 2-14, GraphicsDevice.Viewport.Height / 2), Color.Red);
            }
            if (player.alive)
            {
                spriteBatch.Draw(player.texture, player.position,
                null, Color.White, player.rotation,
                new Vector2(player.texture.Width / 2, player.texture.Height / 2), 0.5f, SpriteEffects.None, 0);
            }
            else
            {
                spriteBatch.DrawString(Content.Load("font"), "GAME OVER!: ", new Vector2 (GraphicsDevice .Viewport .Width /2 -14, GraphicsDevice .Viewport .Height /2),Color.Red);
           
            }

RUN THE GAME!!


Now we're done..
I'll add more explanation next update...




THE SOURCE CODE SO FAR!!


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;

namespace tankGame
{
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        Texture2D background;
        gameObject enemy, player;
        KeyboardState currentKeyboardState, oldKeyboardState;
        const float moveSpeed = 2f;
        const int MaxBullet = 5;
        List bullet = new List();
        List Explosion = new List();
        Vector2 tempposition;
        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }
        protected override void Initialize()
        {
            base.Initialize();
        }

        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);
            background = Content.Load("background");
            player = new gameObject();
            enemy = new gameObject();
            player.texture = Content.Load("tank");
            enemy.texture = Content.Load("tank");
            enemy.position = new Vector2(400, 100);
            player.position = new Vector2(100, 100);
            
            
        }

        protected override void UnloadContent()
        {
        }
        protected override void Update(GameTime gameTime)
        {
            currentKeyboardState = Keyboard.GetState();
            updateTank();
            AI(gameTime );
                if (player.alive)
                {
                    tempposition = player.position;
                    if (currentKeyboardState.IsKeyDown(Keys.Right) && oldKeyboardState.IsKeyDown(Keys.Right))
                    {
                        player.rotation += 0.1f;
                    }
                    if (currentKeyboardState.IsKeyDown(Keys.Left) && oldKeyboardState.IsKeyDown(Keys.Left))
                    {
                        player.rotation -= 0.1f;
                    }
                    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);
                       
                    }
                    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);
                       
                    }
                    if (currentKeyboardState.IsKeyDown(Keys.Space) && oldKeyboardState.IsKeyUp(Keys.Space))
                    {
                        fireBullets();
                    }
                    
                }
                
            if (enemy.life <= 0)
            {
                enemy.alive = false;
            }
            if (player.life <= 0)
            {
                player.alive = false;
            }
            detectCollisionsAgainstObject(player, enemy);
            oldKeyboardState = currentKeyboardState;
            reloadBullets(gameTime);
            base.Update(gameTime);
        }
        private void updateTank()
        {
            player.velocity.X = (float)Math.Cos(player.rotation )  ;
            player.velocity.Y = (float)Math.Sin(player.rotation)  ;
           
        }
        private void updateBullets()
        {
            foreach (gameObject obj in bullet)
            {
                if (obj.alive)
                {
                    obj.position += obj.velocity * moveSpeed * 2f;
                    spriteBatch.Draw(obj.texture, obj.position,
           null, Color.White, obj.rotation,
           new Vector2(obj.texture.Width / 2, obj.texture.Height / 2),
           0.5f, SpriteEffects.None, 0);
                    detectCollisions(obj, player);
                    detectCollisions(obj, enemy);
                }
            }

        }
        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--;
            }

        }
        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);
                enemy.numberOfBullets--;
            }

        }
        void reloadBullets(GameTime gameTime)
        {

             if (gameTime.TotalGameTime.Seconds % 5 == 0)
             {

                 if (player .numberOfBullets < MaxBullet)
                     player .numberOfBullets  += 1;
                 if (enemy.numberOfBullets < MaxBullet)
                     enemy.numberOfBullets++;
             }
        }
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);
          
            spriteBatch.Begin();
            spriteBatch.Draw(background, Vector2.Zero, Color.White );
            if (enemy.alive)
            {
                spriteBatch.Draw(enemy.texture, enemy.position,
                   null, Color.White, enemy.rotation,
                   new Vector2(enemy.texture.Width / 2, enemy.texture.Height / 2),
                   0.5f, SpriteEffects.None, 0);
            }
            else
            {
                spriteBatch.DrawString(Content.Load("font"), "YOU WIN!: ", new Vector2(GraphicsDevice.Viewport.Width / 2-14, GraphicsDevice.Viewport.Height / 2), Color.Red);
            }
            if (player.alive)
            {
                spriteBatch.Draw(player.texture, player.position,
                null, Color.White, player.rotation,
                new Vector2(player.texture.Width / 2, player.texture.Height / 2), 0.5f, SpriteEffects.None, 0);
            }
            else
            {
                spriteBatch.DrawString(Content.Load("font"), "GAME OVER!: ", new Vector2 (GraphicsDevice .Viewport .Width /2 -14, GraphicsDevice .Viewport .Height /2),Color.Red);
           
            }
            updateBullets();
            spriteBatch.DrawString(Content.Load("font"), "BULLETS: " + player.numberOfBullets.ToString() + " " + player .rotation .ToString (), Vector2.Zero, Color.White);
            spriteBatch.DrawString(Content.Load("font"), "LIFE: " + player.life.ToString(),
             new Vector2(player.position.X - player.texture.Width / 2, player.position.Y - player.texture.Height * 0.5f), Color.White);
            spriteBatch.DrawString(Content.Load("font"), "ENEMY LIFE: " + enemy.life.ToString(),
             new Vector2(GraphicsDevice .Viewport .Width - 200 ,0), Color.White);
            spriteBatch.End();
            foreach (gameObject explode in Explosion)
            {
                drawExplosion(explode);
            }
            base.Draw(gameTime);
        }
         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;
                         addExplosions(_bullets);
                     }
                 }
             }
         }
         private void detectCollisionsAgainstObject(gameObject _gameObject1, gameObject _gameObject)
         {
             //_bullets will be from the bulletlist and _gameObject is the player that we want to check the collision with the bullets in the bullet list
             Vector2 origin, origin1;
             
             origin = new Vector2(_gameObject1.texture.Width / 4, _gameObject1.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(_gameObject1.position.X - origin.X,
                                 _gameObject1.position.Y - origin.Y, 1f);
             bulletBounds.Max = new Vector3(origin.X / 2 + _gameObject1.position.X,
                 origin.Y + _gameObject1.position.Y, 1f);
             if (_gameObject1.alive)
             {
                 if (_gameObject.alive)
                 {
                     if (Player.Contains (bulletBounds) != ContainmentType .Disjoint )
                     {
                         _gameObject1.position = tempposition;
                       
                     }
                 }
             }
         }
         public Texture2D DrawRectangle()
         {
             Color boundsColor;
             Texture2D texture = new Texture2D(GraphicsDevice , 1, 1);
             boundsColor = Color.Red;
             texture.SetData(new Color[] { boundsColor });
             return texture;
         }
        public Rectangle createBounds (Vector2 position, int w , int h){
            int positionx, positiony;
            positionx =(int)position.X -w/4;
            positiony =(int)position.Y - h/4;
           // bounds = new BoundingBox(new Vector3(position.X, position.Y, 1), new Vector3(positionx, positiony, 1));
            //Matrix rotation = Matrix.CreateRotationZ(MathHelper.ToDegrees (player.rotation));
           // Vector2 transformedPosition = Vector2.Transform(new Vector2(positionx, positiony), rotation);
            
            return new Rectangle(positionx  , positiony 
                , w / 2
                , h/2 + (int)Math.Cos (player.rotation * player .position .Y )
                );
           
        }
        private void drawExplosion(gameObject explosion)
        {
            spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.Additive);
            if (explosion.alive)
            {
                for (int x = 0; x <= 15; x++)
                {
                    Random r =new Random ();

                    spriteBatch.Draw(explosion.texture, explosion.position,
              null, Color.White, r.Next (1,4),
              new Vector2(explosion.texture.Width / 2, explosion.texture.Height / 2), 0.5f, SpriteEffects.None, 0);

                }
                explosion.life -=2  ;
                if (explosion.life <= 0)
                {
                    explosion.alive = false;
                }
            }
            spriteBatch.End();
        }
        private void addExplosions(gameObject _bullet)
        {
            gameObject explode = new gameObject();
            explode.alive = true;
            explode.position = _bullet.position;
            explode.texture = Content.Load("explosion");
            explode.life = 100;
            Explosion.Add(explode);
        }
        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;
                    }
                }
                else
                {
                    enemy.position -= enemy.velocity * moveSpeed;
                }
            }
            
             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);

        }
    }
}