-1

Here is a game I made in school, I've been going back through it and am looking for ways to improve it. If anyone has any ideas or critical feedback that'd be great :^)

public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;

        const int
            INSERT_COIN = 0,
            PLAYING = 1,
            GAME_OVER = 2;
        int state = 0;

        Texture2D backgroundTexture;
        Texture2D shipSpriteSheet;
        Texture2D submarineSpriteSheet;
        Texture2D torpedoSpriteSheet;
        Texture2D depthChargeSpriteSheet;
        SpriteFont messageFont;
        SpriteFont scoreFont;

        ShipSprite ship;
        SubmarineSprite submarine;
        TorpedoSprite torpedo;
        DepthChargeSprite depthCharge;

        int updateCount = 0;
        int score = 0;

        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
            backgroundTexture = this.Content.Load<Texture2D>("Background");
            shipSpriteSheet = this.Content.Load<Texture2D>("Ship");
            submarineSpriteSheet = this.Content.Load<Texture2D>("Submarine");
            torpedoSpriteSheet = this.Content.Load<Texture2D>("Torpedo");
            depthChargeSpriteSheet = this.Content.Load<Texture2D>("DepthCharge");
            messageFont = this.Content.Load<SpriteFont>("MessageFont");
            scoreFont = this.Content.Load<SpriteFont>("ScoreFont");
        }

        /// <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();

            // TODO: Add your update logic here
            KeyboardState kbState = Keyboard.GetState();
            updateCount++;

            switch (state)
            {
                case INSERT_COIN:
                    ship = null;
                    submarine = null;
                    torpedo = null;
                    depthCharge = null;

                    updateCount = 0;
                    score = 0;

                    if (kbState.IsKeyDown(Keys.Escape)) state = PLAYING;
                    break;

                case PLAYING:
                    if (torpedo == null) torpedo = new TorpedoSprite(torpedoSpriteSheet, this, 100);
                    if (depthCharge == null) depthCharge = new DepthChargeSprite(depthChargeSpriteSheet, this, 100);
                    if (submarine == null) submarine = new SubmarineSprite(submarineSpriteSheet, this, 150);
                    if (ship == null) ship = new ShipSprite(shipSpriteSheet, this, 180);
                    
                    if (kbState.IsKeyDown(Keys.Down)) depthCharge.Drop = true;

                    ship.Update(kbState);
                    depthCharge.Update(ship, submarine);
                    submarine.Update(ship, torpedo);
                    torpedo.Update(ship, submarine);

                    if (submarine.Destroyed && submarine.Finished) score += 20;

                    if (submarine.Finished) submarine = null;
                    if (torpedo.Finished) torpedo = null;
                    if (depthCharge.Finished) depthCharge = null;
                    if (ship.Finished && submarine == null) { updateCount = 0; state = GAME_OVER; }
                    break;

                case GAME_OVER:
                    if (updateCount > 120) state = INSERT_COIN;
                    break;

                default:
                    break;
            }

            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
            spriteBatch.Begin();
            switch (state)
            {
                case INSERT_COIN:
                    spriteBatch.DrawString(messageFont, "Press ESC key to start game", 
                                           new Vector2(220, 300), Color.White);
                    break;

                case PLAYING:
                    spriteBatch.Draw(backgroundTexture, new Vector2(0, 0), Color.White);
                    
                    //Draws the sprites if not equal to null
                    if (ship != null) ship.Draw(spriteBatch);                 //Draws ship sprite
                    if (submarine != null) submarine.Draw(spriteBatch);       //Draws Submarine sprite
                    if (torpedo != null) torpedo.Draw(spriteBatch);           //Draws Torpedo sprite
                    if (depthCharge != null) depthCharge.Draw(spriteBatch);   //Draws Depth Charge sprite

                    spriteBatch.Draw(submarineSpriteSheet, new Vector2(630, 45), new Rectangle(0, 0, 150, 80),
                    Color.White, 0f, new Vector2(0, 0), 0.4f, SpriteEffects.None, 0.5f);
                    spriteBatch.DrawString(scoreFont, "" + score, new Vector2(700, 50), Color.White);
                    break;

                case GAME_OVER:
                    spriteBatch.Draw(backgroundTexture, new Vector2(0, 0), Color.White);
                    spriteBatch.Draw(submarineSpriteSheet, new Vector2(630, 45), new Rectangle(0, 0, 150, 80),
                    Color.White, 0f, new Vector2(0, 0), 0.4f, SpriteEffects.None, 0.5f);
                    spriteBatch.DrawString(scoreFont, "" + score, new Vector2(700, 50), Color.White);
                    spriteBatch.DrawString(messageFont, "GAME OVER", new Vector2(330, 300), Color.Red);
                    break;

                default:
                    break;
            }
        
            spriteBatch.End();

            base.Draw(gameTime);
        }
    }
class ShipSprite : BasicSprite
    {
        public const int
            START = 0,      //Set start position
            SAILING = 1,    //Moving ship along X-axis
            SINKING = 2,    //Hit by torpedo, sink animation
            DESTROYED = 3,  //Starts timer
            END = 4;        //End state

        // States for finite state machines
        int _state;
        int _timer;

        const int LEFT_SCREEN = 0;              //Position of left side of screen
        const int RIGHT_SCREEN = 800;           //Position of right side of screen
        const int X_START_POS = 300;            //X co-ord for ship start point
        const int Y_START_POS = 150;            //Y co-ord for ship start point
        const int SHIP_DESTROY_DELAY = 120;     //Time delay for ship destruction

        // Message from Torpedo: ship has been hit and is sinking
        bool _hitByTorpedo;
        public bool HitByTorpedo { set { _hitByTorpedo = value; } }

        // Message for the Game1 and Submarine: the ship is sailing normally
        public bool Sailing { get { return _state == SAILING; } }

        // Constructor
        public ShipSprite(Texture2D image,
                          Game game,
                          int frameWidth)
            : base(image, game, frameWidth,
                   0, 0, 1000000,   // Turn off default animation
                   90, 75)          // Image offset
        {
            _state = START;
        }

        // Update the ship's position using the keyboard
        public void Update(KeyboardState kbState)
        {
            switch (_state)
            {
                case START:
                    //Sets ship starting position
                    X = X_START_POS;
                    Y = Y_START_POS;
                    Show = true;
                    _state = SAILING;
                    break;

                case SAILING:

                    //If left key is pressed and ship is on the screen...
                    if (kbState.IsKeyDown(Keys.Left) && X > LEFT_SCREEN)
                    {
                        //Move ship left
                        X--;
                        //Flip sprite image
                        FlipHorizontally = true;
                    }

                    //If right key is pressed and ship is on the screen...
                    if (kbState.IsKeyDown(Keys.Right) && X < RIGHT_SCREEN)
                    {
                        //Move ship right
                        X++;
                        FlipHorizontally = false;
                    }

                    //If hit by torpedo...
                    if (_hitByTorpedo)
                    {
                        HitByTorpedo = true;
                        //Display animation (first frame, last frame, framerate)
                        SetCycle(0, 5, 10);
                        _state = SINKING;
                    }
                    break;

                case SINKING:
                    //If last frame of animation
                    if(FrameNumber == 4)
                    {
                        //End animation
                        this.SetCycle(4, 4, 1000);
                        _state = DESTROYED;
                    }
                    break;

                case DESTROYED:
                    //Increment timer
                    _timer++;

                    //If timer equals destroy delay...
                    if (_timer == SHIP_DESTROY_DELAY)
                    {
                        _state = END;
                    }
                    break;

                case END:
                    // This sprite is now finished
                    Show = false;
                    Finished = true;
                    break;

                default:
                    // Should never get here
                    _state = END;
                    break;
            }

            // Call the BasicSprite Update to allow animation
            base.Update();
        }
    }
class DepthChargeSprite : VectoredSprite
    {
        public const int
            START = 0,       //Waits for drop command/confirms ship direction
            IN_AIR = 1,      //Deploy depth charge in air
            SINKING = 2,     //Depth charge in water
            EXPLODING = 3,   //Hit or miss submarine
            END = 4;         //End state

        // State for finite state machine
        int _state;

        // Trigger from user to start depth charge drop/explode sequence
        bool _drop;
        public bool Drop { set { _drop = value; } }

        const int SEA_LEVEL = 150;              //Y value of sea level
        const double VELOCITY_IN_AIR = 3;       //Speed of depth charge in air
        const double VELOCITY_IN_WATER = 2.5;   //Speed of depth charge in water
        const double DEPLOY_ROTATION = 0.1;     //Rotation which depth charge is deployed
                
        // Constructor
        public DepthChargeSprite(Texture2D image,
                                 Game game,
                                 int frameWidth)
            : base(image, game, frameWidth,
                   0, 0, 1000000,       // No animation required for frame 0
                   50, 50)              // Image origin
        {
            _state = START;
        }

        // Update to be called from Game1 class. 
        // ship required as parameter to establish starting position
        // submarine required to establish explosion depth and whether submarine destroyed.
        public void Update(ShipSprite ship,
                           SubmarineSprite submarine)
        {
            switch (_state)
            {
                case START:
                    //If depth charge dropped and ship is facing right...
                    if(_drop && ship.FlipHorizontally == false)
                    {
                        X = ship.X - 50;
                        Y = ship.Y;
                        Angle = 0;
                        Velocity = VELOCITY_IN_AIR;
                        Rotation = -DEPLOY_ROTATION;
                        Scale = 0.3;
                        Show = true;
                        _state = IN_AIR;
                    }

                    //If depth charge dropped and ship is facing left...
                    if (_drop && ship.FlipHorizontally == true)
                    {
                        X = ship.X + 50;
                        Y = ship.Y;
                        Angle = 0;
                        Velocity = VELOCITY_IN_AIR;
                        Rotation = DEPLOY_ROTATION;
                        Scale = 0.3;
                        Show = true;
                        _state = IN_AIR;
                    }
                    break;

                case IN_AIR:
                    //If depth charge is in the sea...
                    if (Y >= SEA_LEVEL)
                    {
                        Angle = Math.PI;
                        Rotation = 0;
                        Velocity = VELOCITY_IN_WATER;
                        _state = SINKING;
                    }

                    break;

                case SINKING:
                    //If depth charge Y reaches submarine Y...
                    if (Y >= submarine.Y)
                    {
                        //Display animation
                        SetCycle(0, 6, 10);
                        Velocity = 0;
                        Angle = 0;
                        Scale = 1;
                        _state = EXPLODING;
                    }
                    break;

                case EXPLODING:

                    //Draw bounding box for depth charge
                    Rectangle depthChargeBox = new Rectangle((int)X, (int)Y, 100, 100);
                    //Draw bounding box for submarine
                    Rectangle submarineBox = new Rectangle((int)submarine.X, (int)submarine.Y, 150, 80);

                    //If depth charge box intersects with submarine box...
                    if(depthChargeBox.Intersects(submarineBox))
                    {
                        //Submarine is hit
                        submarine.HitByDepthCharge = true;
                    }
                    //If last frame of animation...
                    if (FrameNumber == 6)
                    {
                        _state = END;
                    }
                    break;

                case END:
                    Finished = true;
                    Show = false;
                    break;

                default:
                    // Should never reach here
                    _state = END;
                    break;
            }
            // Call the VectoredSprite Update to perform any movement and animation
            base.Update();
        }
    }
class SubmarineSprite : MovingSprite
    {
        public const int
            START = 0,          // Newly created sprite
            SAILING = 1,        // Sailing across the screen
            SINKING = 2,        // Hit by depth charge and sinking
            DESTROYED = 3,      // Destroyed by depth charge
            END = 4;            // Finished
            

        const int MIN_DISTANCE = 60;        // Minimum distance to ship for launching torpedo
        const int SUB_START_LEFT = 0;       //Position of left side screen
        const int SUB_START_RIGHT = 800;    //Position of right side screen
        const int TORPEDO_DELAY = 80;       //Time between firing torpedos
        const int DESTROY_DELAY = 60;       //Destroy duration
        const int SUB_VELOCITY = 2;         //Speed of submarines


        // State for finite state machine
        int _state;
        int _timer;

        // Signal from depth charge sprite: submarine has been hit
        bool _hitByDepthCharge;
        public bool HitByDepthCharge { set { _hitByDepthCharge = value; } }
        
        // Signal to Game1 class: submarine destroyed by depth charge
        bool _destroyed;
        public bool Destroyed { get { return _destroyed; } }

        // Constructor
        public SubmarineSprite(Texture2D image,
                               Game game,
                               int frameWidth)
            : base(image, game, frameWidth,
                   0, 0, 1000000,
                   75, 50)
        {
            _state = START;
        }


        // Update to be called from Game1 class. 
        // ship required as parameter to establish whether in range for torpedo
        // torpedo required as parameter to trigger torpedo launch
        public void Update(ShipSprite ship,
                           TorpedoSprite torpedo)
        {
            switch (_state)
            {
                case START:

                    Random randomNumber = new Random();
                    //Stores random number as randomNum
                    int randomNum = randomNumber.Next(0, 2);
                    Random randomN = new Random();
                    //Stores random number as randomY
                    int randomY = randomN.Next(250, 550);

                    //If randomNum is below 0.5...
                    if(randomNum < 0.5)
                    {
                        X = SUB_START_LEFT;
                        Y = randomY;
                        VelocityX = SUB_VELOCITY;
                        FlipHorizontally = false;
                        Show = true;
                    }

                    //If randomNum is above or equal to 0.5...
                    if (randomNum >= 0.5)
                    {
                        X = SUB_START_RIGHT;
                        Y = randomY;
                        VelocityX = -SUB_VELOCITY;
                        FlipHorizontally = true;
                        Show = true;
                    }
                    _state = SAILING;
                    break;

                case SAILING:
                    //Increments timer
                    _timer++;

                    //If timer is larger than torpedo delay, 
                    //the ship is infront of the sub and torpedo is not in running state
                    if (_timer > TORPEDO_DELAY && this.IsShipAhead(ship) && torpedo.Running == false)
                    {
                        //Launch torpedo
                        torpedo.Launch = true;
                        _state = SAILING;
                    }

                    ////If submarine goes off of screen...
                    if (X > SUB_START_RIGHT || X < SUB_START_LEFT)
                    {
                        Finished = true;
                        Show = false;
                        _state = END;
                    }

                    //If sub is hit by depth charge...
                    if (_hitByDepthCharge == true)
                    {
                        //Display animation
                        SetCycle(0, 4, 10);
                        VelocityX = 0;
                        _state = SINKING;
                    }

                    break;

                case SINKING:
                    //If animation is on final frame...
                    if (FrameNumber == 4)
                    {
                        //End animation
                        SetCycle(4, 4, 10);
                        _destroyed = true;
                        _timer = 0;
                        _state = DESTROYED;
                    }
                    break;

                case DESTROYED:
                    //Increment timer
                    _timer++;
             
                    //If timer is larger than or equal to destroy elay...
                    if (_timer >= DESTROY_DELAY)
                    {
                        _state = END;
                    }
                    break;

                case END:
                    // This sprite is now finished
                    Show = false;
                    Finished = true;
                    break;

                default:
                    // Should never reach here
                    _state = END;
                    break;
            }

            // Call the BasicSprite Update to allow animation
            base.Update();
        }

        // Return true if the ship is ahead of the submarine, taking into account
        // whether the sub is facing left or right
        private bool IsShipAhead(ShipSprite ship)
        {
            // Function result
            bool result = false;

            // Which direction is the sub facing?
            if (!FlipHorizontally)
                result = (X < ship.X - MIN_DISTANCE);
            else
                result = (X > ship.X + MIN_DISTANCE);

            // Confirm ship is in the SAILING state
            result = result & ship.Sailing;
            return result;
        }
    }
class TorpedoSprite : VectoredSprite
    {
        public const int
            START = 0,              // Waiting for launch command
            RUNNING = 1,            // Running towards target ship
            HIT_TARGET = 2,         // Hit the ship and exploding
            END = 3;                // End state

            const int TORPEDO_OFFSET = 75;        //Sets where the torpedo is fired from in relation to sub
            const double TORPEDO_VELOCITY = 1.5;  //Torpedo Speed
            const double TORPEDO_SCALE = 0.5;     //Scales torpedo
            const double ANGLE_CHANGE = 0.5;      //Angle difference for torpedo

        // State for finite state machine
        int _state;

        // Target: position of ship when torpedo launched
        double _targetX, _targetY;

        // Signal from submarine to launch this torpedo
        bool _launch;
        public bool Launch { set { _launch = value; } }

        // Status flag for submarine
        public bool Running { get { return _state == RUNNING; } }

        // Constructor for torpedo sprite
        public TorpedoSprite(Texture2D image,
                             Game game,
                             int frameWidth)
            : base(image, game, frameWidth,
                   0, 0, 1000000,           // No animation required for torpedo
                   50, 50)                  // Image origin
        {
            _state = START;
        }

        // Update to be called from Game1 class. 
        // ship required as parameter to establish target position
        // submarine required to establish torpedo's starting position
        public void Update(ShipSprite ship, 
                           SubmarineSprite submarine)
        {
            switch (_state)
            {
                case START:
                        //If torpedo launched and sub is facing right...
                        if (_launch && submarine.FlipHorizontally == false)
                        {
                            X = submarine.X + TORPEDO_OFFSET;
                            Y = submarine.Y;
                            Angle = Math.PI/2;
                            _targetX = ship.X;
                            _targetY = ship.Y;
                            Velocity = TORPEDO_VELOCITY;
                            Scale = TORPEDO_SCALE;
                            Show = true;
                            _state = RUNNING;
                        }
                        //If torpedo launched and sub is facing left...
                        if (_launch && submarine.FlipHorizontally == true)
                        {
                            X = submarine.X - TORPEDO_OFFSET;
                            Y = submarine.Y;
                            Angle = -Math.PI/2;
                            _targetX = ship.X;
                            _targetY = ship.Y;
                            Velocity = TORPEDO_VELOCITY;
                            Scale = TORPEDO_SCALE;
                            Show = true;
                            _state = RUNNING;
                        }
                        
                    break;

                case RUNNING:
                    //Creats a new angle
                    double newAngle = Math.Atan2(_targetX - X, Y - _targetY);

                    //If submarine is facing left...
                    if (submarine.FlipHorizontally == true)
                    {
                        //Sets angle
                        Angle = newAngle - ANGLE_CHANGE;
                    }
                    //If submarine is facing right...
                    if (submarine.FlipHorizontally == false)
                    {
                        //Sets angle
                        Angle = newAngle + ANGLE_CHANGE;
                    }

                    //Draws bounding box for torpedo
                    Rectangle torpedoBox = new Rectangle((int)X, (int)Y, 50, 50);
                    //Tells where to place the bounding box for torpedo
                    Vector2 torpedoPosition = new Vector2((float)X, (float)Y);

                    //Draws bounding box for ship
                    Rectangle shipBox = new Rectangle((int)ship.X, (int)ship.Y, 180, 100);
                    //Bounding box position for ship
                    Vector2 shipPosition = new Vector2((float)ship.X, (float)ship.Y);

                    //If torpedo box contains ships target position...
                    if (torpedoBox.Contains(new Point((int)_targetX,(int)_targetY)))
                    {
                        //If torpedo and ship interect...
                        if(torpedoBox.Intersects(shipBox))
                        {
                            ship.HitByTorpedo = true;
                            SetCycle(0, 5, 5);
                            Scale = 1;
                            Velocity = 0;
                            Angle = 0;
                            Show = false;
                            Finished = true;
                            _state = HIT_TARGET;
                        }
                        //If they don't intersect...
                        else
                        {
                            Show = false;
                            Finished = true;
                            _state = END;
                        }
                    }
                    //If torpedo position is equal to target position...
                    if (X == _targetX && Y == _targetY)
                    {
                        ship.HitByTorpedo = false;
                        _state = END;
                    }
                    break;

                case HIT_TARGET:
                    //If animation is finished...
                    if(FrameNumber == 5)
                    {
                        Show = false;
                        Finished = true;
                        _state = END;
                    }
                    break;

                case END:
                    // This sprite is finished
                    Show = false;
                    Finished = true;
                
                    break;

                default:
                    _state = END;
                    break;
            }
            // Call the VectoredSprite Update to allow movement and animation
            base.Update();
        }
    }

Edited by peter_budo: Keep It Organized - For easy readability, always wrap programming code within posts in [code] (code blocks)

Votes + Comments
don't dump your code like that
2
Contributors
4
Replies
6
Views
7 Years
Discussion Span
Last Post by Xomy
0
class BasicSprite
    {
        // Fields for a basic animated sprite
        Texture2D _image;
        protected Game _game;
        Vector2 _origin;
        int _frameWidth, _frameHeight;
        int _frameNumber;
        int _frameCount;
        int _cycleStart, _cycleEnd, _frameRate;
        int _updateCount;
        double _positionX, _positionY;
        bool _flipHorizontally, _flipVertically;
        bool _show;
        bool _finished;

        Color _tint;
        double _angle;
        double _scale;

        public double X { get { return _positionX; } set { _positionX = value; } }
        public double Y { get { return _positionY; } set { _positionY = value; } }
        public double Angle { get { return _angle; } set { _angle = value; } }
        public double Scale { get { return _scale; } set { _scale = value; } }
        public Color Tint { get { return _tint; } set { _tint = value; } }
        public int FrameNumber { get { return _frameNumber; } set { _frameNumber = value; } }
        public bool Show { get { return _show; } set { _show = value; } }
        public bool FlipHorizontally { get { return _flipHorizontally; } set { _flipHorizontally = value; } }
        public bool FlipVertically { get { return _flipVertically; } set { _flipVertically = value; } }
        public bool Finished { get { return _finished; } protected set { _finished = value; } }

        // Constructor for Basic Sprite
        public BasicSprite(Texture2D image,
                           Game game,
                           int frameWidth,
                           int cycleStart, int cycleEnd, int frameRate,
                           int originX, int originY)
        {
            // Save image, game and frame size from parameter list
            _image = image;
            _game = game;
            _frameWidth = frameWidth;
            _frameHeight = image.Height;

            // Calculate the frame count from the full image width and frame width
            _frameCount = image.Width / frameWidth;

            // Set up the sprite origin position
            _origin = new Vector2(originX, originY);

            // Set up the default animation cycle
            SetCycle(cycleStart, cycleEnd, frameRate);

            // Initialise remaining fields to reasonable values
            _updateCount = 0;
            _positionX = 0.0; _positionY = 0.0;
            _flipHorizontally = false; _flipVertically = false;
            _show = false;
            _tint = Color.White;
            _angle = 0.0;
            _scale = 1.0;
        }

        // Set up the animation cycle
        public void SetCycle(int cycleStart, int cycleEnd, int frameRate)
        {
            _updateCount = 0;
            _cycleStart = cycleStart;
            _cycleEnd = cycleEnd;
            _frameRate = frameRate;

            // Check that we don't run off the end of the sprite sheet
            if (_cycleEnd > _frameCount)
            {
                _cycleEnd = _frameCount;
            }
        }

        // Update and cycle through the next frame
        // (Note: We mark it virtual so we can define other versions in MovingSprite etc)
        public virtual void Update()
        {
            // Count the number of updates
            _updateCount++;

            // Is it time to move on to the next frame?
            if (_updateCount > _frameRate)
            {
                _updateCount = 0;
                IncrementFrame();
            }
        }

        // Method to increment the frame number 
        private void IncrementFrame()
        {
            // Increment the number and check if we've gone past the end
            _frameNumber++;
            if (_frameNumber > _cycleEnd)
            {
                // If the cycle start value is value go back to it
                if (_cycleStart >= 0)
                {
                    // Go back to the cycle start
                    _frameNumber = _cycleStart;
                }
                else
                {
                    // End of cycle and no valid start - stop the sprite from showing
                    _show = false;
                }
            }
        }

        // Draw the sprite using the supplied sprite batch
        public void Draw(SpriteBatch spriteBatch)
        {
            // Only draw the sprite if the draw flag is true
            if (_show)
            {
                // Set up the position and source rectangle
                Vector2 position = new Vector2 ((float) _positionX, (float) _positionY);
                Rectangle source = new Rectangle(_frameWidth*_frameNumber, 0, _frameWidth, _frameHeight);

                // See if any flipping effects are required
                SpriteEffects effects = SpriteEffects.None;
                if (_flipHorizontally) effects = SpriteEffects.FlipHorizontally;
                if (_flipVertically) effects = SpriteEffects.FlipVertically;

                // Draw the sprite now!
                spriteBatch.Draw(_image, position, source, _tint, (float) _angle, 
                                 _origin, (float)_scale, effects, 0.5f);
            }
        }
    }
class MovingSprite : BasicSprite
    {
        double _velocityX, _velocityY;      // Sprite X and Y velocity
        double _rotation;                   // Rotational speed - radians per update

        public double VelocityX { get { return _velocityX; } set { _velocityX = value; } }
        public double VelocityY { get { return _velocityY; } set { _velocityY = value; } }
        public double Rotation { get { return _rotation; } set { _rotation = value; } }

        // Constructor for MovingSprite - also calls constructor for BasicSprite
        public MovingSprite(Texture2D image,
                            Game game,
                            int frameWidth,
                            int cycleStart, int cycleEnd, int frameRate,
                            int originX, int originY)
            : base(image, game, frameWidth,
                   cycleStart, cycleEnd, frameRate, originX, originY)   // Basic sprite constructor
        {
            // Initialise newly declared fields to zero
            _velocityX = 0.0;
            _velocityY = 0.0;
            _rotation = 0.0;
        }

        // Update method - updates the sprites position
        public override void Update()
        {
            // Adjust the sprite's X,Y position and its angle
            // (Note: refers to the public PROPERTIES defined in BasicSprite)
            X = X + _velocityX;
            Y = Y + _velocityY;
            Angle = Angle + _rotation;

            // Now ask BasicSprite to perform any animation on this sprite image
            // (Note: the "base" refers to the parent of this class - BasicSprite)
            base.Update();
        }

        // There is no need for a Draw() method since we inherit one from BasicSprite which does all we need
    }
class VectoredSprite : MovingSprite
    {
        // This class has a velocity and uses Angle inherited from BasicSprite
        double _velocity;

        // Public property to allow access to the velocity
        public double Velocity { get { return _velocity; } set { _velocity = value; } }

        // Constructor for this class - calls the MovingSprite constructor
        public VectoredSprite(Texture2D image,
                              Game game,
                              int frameWidth,
                              int cycleStart, int cycleEnd, int frameRate,
                              int originX, int originY)
            : base(image, game, frameWidth,
                   cycleStart, cycleEnd, frameRate, originX, originY)
        {
            // Default value for velocity
            _velocity = 0.0;
        }

        // Convenience method to set the velocity and angle in one call
        public void SetVector(double velocity, double angle)
        {
            _velocity = velocity;
            Angle = angle;
        }

        // Update the sprite's position
        public override void Update()
        {   
            // Recalculate the X and Y velocities
            this.VelocityX = _velocity * Math.Sin(this.Angle);
            this.VelocityY = -_velocity * Math.Cos(this.Angle);    

            // Move the sprite (MovingSprite) and also animate the sprite (BasicSprite)
            base.Update();
        }

        // The Draw() method is inherited from BasicSprite
    }

Edited by peter_budo: Keep It Organized - For easy readability, always wrap programming code within posts in [code] (code blocks)

1

Please post code with code tags... It's hard to notice something without code tags.
Ok, now about code. Here is some redundant code here:

//If depth charge dropped and ship is facing right...
if(_drop && ship.FlipHorizontally == false)
{
X = ship.X - 50;
Y = ship.Y;
Angle = 0;
Velocity = VELOCITY_IN_AIR;
Rotation = -DEPLOY_ROTATION;
Scale = 0.3;
Show = true;
_state = IN_AIR;
}

//If depth charge dropped and ship is facing left...
if (_drop && ship.FlipHorizontally == true)
{
X = ship.X + 50;
Y = ship.Y;
Angle = 0;
Velocity = VELOCITY_IN_AIR;
Rotation = DEPLOY_ROTATION;
Scale = 0.3;
Show = true;
_state = IN_AIR;
}

Can be written in more laconic form as:

if (_drop)
{
int direction = ((ship.FlipHorizontally)? 1:-1);
X = ship.X + 50 * direction;
Y = ship.Y;
Angle = 0;
Velocity = VELOCITY_IN_AIR;
Rotation = DEPLOY_ROTATION * direction;
Scale = 0.3;
Show = true;
_state = IN_AIR;
}

Next - You can in principle live without ship.FlipHorizontally property. All you need is object's position and speed. That's all. So instead of ship.FlipHorizontally? you could use ship.VelocityX > 0 ?

Edited by 0x69: n/a

0

Thanks for the quick reply Ox69! I will play around with what you suggested and try and get rid of the ship.FlipHorizontally if it isn't needed.

I also have another game we made in school however this one is a 3D shooter. I'm going to be concentrating on the 2D one for now but will be looking to work on this 3D one in a few weeks or so. If anyone has any advice up until then that would be great!

Thanks Daniwebbers :^)

0

GameObject Class:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
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 AssignmentTwo
{
    class GameObject
    {
        public Model model = null;
        public Quaternion rotation = Quaternion.Identity;
        public Vector3 position = Vector3.Zero;
        public Vector3 speed = Vector3.Zero;
        public Vector3 scale = new Vector3(1, 1, 1);
        public bool alive = false;
    }
}

Game1 class

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 AssignmentTwo
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;

        //Game Objects
        GameObject drum = new GameObject();
        GameObject driveOne = new GameObject();
        GameObject driveTwo = new GameObject();
        GameObject smartie = new GameObject();
        GameObject rugby = new GameObject();
        GameObject planet = new GameObject();
        GameObject planetSurround = new GameObject();
        GameObject[] drums;
        GameObject[] missiles;

        //Constants
        const int DRUMAMOUNT = 100;
        const int MISSILEAMOUNT = 150;

        //Ints for screen text
        int missilesRemaining = 150;
        int drumsRemaining = 100;

        //Random number generator
        Random random = new Random();

        //Drum min and max locations
        Vector3 drumMinPos = new Vector3(-200, -200, -200);
        Vector3 drumMaxPos = new Vector3(200, 200, 200);

        Vector3 cameraOffset = Vector3.Zero;
        Vector3 cameraLookAt = new Vector3(0.0f, 0.0f, 0.0f);

        //Camera Matrixs
        Matrix cameraProjectionMatrix;
        Matrix cameraViewMatrix;

        //Audio
        AudioEngine audioEngine;
        SoundBank soundBank;
        WaveBank waveBank;

        //Quaternions
        Quaternion rotation = Quaternion.Identity;
        Quaternion driveRot = Quaternion.Identity;
        Quaternion driveRot2 = Quaternion.Identity;

        //Floats
        float moveShip = 0.0f;
        float driveRotationSpeed = 0.0f;
        float missileSpeed = 1.0f;
        float missileOffset = 2.0f;

        //Name of spritefont
        SpriteFont text;
       
        //Sets previous keyboard state
        KeyboardState previousKeyBoardState;

        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

            //Imports audio files
            audioEngine = new AudioEngine("Content\\Audio\\3DTutorialsXACTproject.xgs");
            waveBank = new WaveBank(audioEngine, "Content\\Audio\\Wave Bank.xwb");
            soundBank = new SoundBank(audioEngine, "Content\\Audio\\Sound Bank.xsb");
            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

            text = Content.Load<SpriteFont>("SpriteFont1");

            //What camera looks at
            cameraViewMatrix = Matrix.CreateLookAt(
                cameraOffset,
                cameraLookAt,
                Vector3.Up);

            //Field of view
            cameraProjectionMatrix = Matrix.CreatePerspectiveFieldOfView(
                MathHelper.ToRadians(45.0f),
                (float)graphics.GraphicsDevice.Viewport.Width /
                (float)graphics.GraphicsDevice.Viewport.Height,
                1.0f, //close
                1000.0f);//far


            //Loads content models and sets scales/positions
            smartie.model = Content.Load<Model>("Models\\newSmartie");

            driveOne.model = Content.Load<Model>("Models\\NewDrive1");

            driveTwo.model = Content.Load<Model>("Models\\NewDrive2");

            rugby.model = Content.Load<Model>("Models\\newRugby");
            rugby.scale = new Vector3(1f, 0.5f, 0.5f);

            planet.model = Content.Load<Model>("Models\\planet");
            planet.scale = new Vector3(3.0f, 3.0f, 3.0f);
            planet.position = new Vector3(0.0f, 0.0f, 40.0f);

            planetSurround.model = Content.Load<Model>("Models\\planetSurround");
            planetSurround.scale = new Vector3(4, 4, 4);


            drums = new GameObject[DRUMAMOUNT];
            //For every drum...
            for (int x = 0; x < DRUMAMOUNT; x++)
            {
                //Makes a new drum
                drums[x] = new GameObject();
                drums[x].model = Content.Load<Model>("Models\\drum");
                //Sets it to alive
                drums[x].alive = true;

                //Sets drum position to random places
                drums[x].position = new Vector3(
                      MathHelper.Lerp(drumMinPos.X,
                      drumMaxPos.X,
                      (float)random.NextDouble()),

                      MathHelper.Lerp(drumMinPos.Y,
                      drumMaxPos.Y,
                      (float)random.NextDouble()),

                      MathHelper.Lerp(drumMinPos.Z,
                      drumMaxPos.Z,
                      (float)random.NextDouble()));
            }


            missiles = new GameObject[MISSILEAMOUNT];
            //For every missile
            for (int x = 0; x < MISSILEAMOUNT; x++)
            {
                //Makes a new missile and scales it
                missiles[x] = new GameObject();
                missiles[x].model = Content.Load<Model>("Models\\missile");
                missiles[x].scale = new Vector3(0.2f, 0.2f, 0.2f); 
            }
            
        }

        /// <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();

            // TODO: Add your update logic here

            //Call update methods
            UpdateCameraPosition(new Vector3(12.0f, 5.0f, 0));
            KeyboardInputs(gameTime);
            UpdateShipPosition();
            UpdateMissiles();
                                                              
            base.Update(gameTime);
        }

        void KeyboardInputs(GameTime GT)
        {           
            float leftRightRotation = 0.0f;
            float upDownRotation = 0.0f;

            KeyboardState keyBoardState = Keyboard.GetState();
            //Uses rotation to calculate correct angle
            Vector3 addMovement = Vector3.Transform(new Vector3(-1, 0, 0), smartie.rotation); 

            if (keyBoardState.IsKeyDown(Keys.W))
            {
                //Drive forward
                smartie.position += 0.5f * addMovement;
                //Increment drive rotation
                driveRotationSpeed += 0.1f;
            }

            if (keyBoardState.IsKeyDown(Keys.S))
            {
                //Drive backwards
                smartie.position -= 0.5f * addMovement;
                //Decremen drive rotation (opposite direction)
                driveRotationSpeed -= 0.1f;
            }

            if (keyBoardState.IsKeyDown(Keys.A))
            {
                //Looks right
                UpdateCameraPosition(new Vector3(12.0f, 5.0f, 8.0f));
            }

            if (keyBoardState.IsKeyDown(Keys.D))
            {
                //Looks left
                UpdateCameraPosition(new Vector3(12.0f, 5.0f, -8.0f));
            }

            if (keyBoardState.IsKeyDown(Keys.Q))
            {
                //Looks down
                UpdateCameraPosition(new Vector3(12.0f, 14.0f, 0f));
            }

            if (keyBoardState.IsKeyDown(Keys.E))
            {
                //Looks up
                UpdateCameraPosition(new Vector3(12.0f, -8.0f, 0f));
            }

            if (keyBoardState.IsKeyDown(Keys.X))
            {
                //Enters first person camera view
                FirstPersonUpdateCameraPosition(new Vector3(-1f, 0f, 0f));
            }

            if (keyBoardState.IsKeyDown(Keys.Up))
            {
                //Decreases pitch
                upDownRotation -= 0.01f;
            }

            if (keyBoardState.IsKeyDown(Keys.Down))
            {
                //Increases pitch
                upDownRotation += 0.01f;
            }

            if (keyBoardState.IsKeyDown(Keys.Left))
            {
                //Increase yaw
                leftRightRotation += 0.01f;
            }

            if (keyBoardState.IsKeyDown(Keys.Right))
            {
                //Decrease yaw
                leftRightRotation -= 0.01f;              
            }

            if (keyBoardState.IsKeyDown(Keys.Space)&& previousKeyBoardState.IsKeyUp(Keys.Space))     
            {
                //Fires missile and decreases missiles remaining
                FireMissile();
                missilesRemaining = missilesRemaining - 1;
            }

            //Stores the last key used (makes user have to tap the fire button)
            previousKeyBoardState = keyBoardState;

            //Adds rotation around the vector axis
            Quaternion additionalRotation = Quaternion.CreateFromAxisAngle(new Vector3(0, 1, 0), leftRightRotation) *
                Quaternion.CreateFromAxisAngle(new Vector3(0, 0, 1), upDownRotation);

            smartie.rotation *= additionalRotation;

            //Calculates the correct direction
            Vector3 direction = Vector3.Transform(Vector3.Left, Matrix.CreateFromQuaternion(rotation));

            //Calculate the drive rotations
            Quaternion driveOneRotation = Quaternion.CreateFromYawPitchRoll(0f, driveRotationSpeed, 0f);
            Quaternion driveTwoRotation = Quaternion.CreateFromYawPitchRoll(0f, -driveRotationSpeed, 0f);
        
            smartie.position += direction * moveShip;

            //Sets the drive rotations
            driveOne.rotation = smartie.rotation * driveOneRotation;
            driveTwo.rotation = smartie.rotation * driveTwoRotation;           
        }

        void UpdateShipPosition()
        {

            driveOne.position = smartie.position;
            driveTwo.position = smartie.position;

            rugby.position = new Vector3(2.17f, 0, 0);
            //Keeps the rugby model with the smartie model
            rugby.position = Vector3.Transform(rugby.position, Matrix.CreateFromQuaternion(smartie.rotation));
            rugby.position += smartie.position;
            rugby.rotation = smartie.rotation;           
        }

        void UpdateCameraPosition(Vector3 cameraOffset)
        {
            Vector3 cameraUp = new Vector3(0, 1, 0);

            //Keeps the camera behind the ship
            cameraOffset = Vector3.Transform(cameraOffset, Matrix.CreateFromQuaternion(smartie.rotation));
            cameraOffset += smartie.position;      
            cameraUp = Vector3.Transform(cameraUp, Matrix.CreateFromQuaternion(smartie.rotation));

            //Sets what camera looks at
            cameraViewMatrix = Matrix.CreateLookAt(
                cameraOffset,
                smartie.position,
                cameraUp);
           
            //Sets the field of view
            cameraProjectionMatrix = Matrix.CreatePerspectiveFieldOfView(
              MathHelper.ToRadians(45.0f),
              (float)graphics.GraphicsDevice.Viewport.Width /
              (float)graphics.GraphicsDevice.Viewport.Height,
              1.0f,
              1000.0f);
        }

        void FirstPersonUpdateCameraPosition(Vector3 cameraOffset)
        {
            Vector3 cameraUp = new Vector3(0, 1, 0);

            //Keeps camera in line with ship rotation
            cameraOffset = Vector3.Transform(cameraOffset, Matrix.CreateFromQuaternion(smartie.rotation));
            cameraOffset += smartie.position;      
            cameraUp = Vector3.Transform(cameraUp, Matrix.CreateFromQuaternion(smartie.rotation));

            //Sets what the camera looks at
            Vector3 lookAtPosition = new Vector3(-10, 0, 0);

            //Keeps the look at postion in line with the ship rotation
            lookAtPosition = Vector3.Transform(lookAtPosition, Matrix.CreateFromQuaternion(smartie.rotation));
            lookAtPosition += smartie.position;

            //Sets what the camera looks at
            cameraViewMatrix = Matrix.CreateLookAt(
                cameraOffset,
                lookAtPosition,
                cameraUp);
           
            //Sets the field of view
            cameraProjectionMatrix = Matrix.CreatePerspectiveFieldOfView(
              MathHelper.ToRadians(45.0f),
              (float)graphics.GraphicsDevice.Viewport.Width /
              (float)graphics.GraphicsDevice.Viewport.Height,
              1.0f,
              1000.0f);
        }

        void UpdateMissiles()
        {
            //For every missile...
            foreach (GameObject missile in missiles)
            {
                if (missile.alive)
                {
                    missile.position += missile.speed;
                    //Runs collision function with current missile
                    TestCollision(missile);
                }

            }
        }

        void FireMissile()
        {
            //Sets the angle of the missile through flight
            Quaternion additionalRotation = Quaternion.CreateFromAxisAngle(new Vector3(0, 1, 0), 1.57f);

            //For every missile...
            foreach (GameObject missile in missiles)
            {
                //If not alive..
                if (!missile.alive)
                {
                    //Make alive
                    missile.alive = true;
                    //Sets missile speed, postion and rotation
                    missile.speed = MissileVelocity();
                    missile.position = MissilePosition();
                    missile.rotation = smartie.rotation * additionalRotation;   
                    //Plays sound
                    soundBank.PlayCue("missilelaunch");
                    break;
                }
            }
        }

        Vector3 MissileVelocity()
        {
            //Sets the correct rotation for the missile
            Matrix rotationMatrix = Matrix.CreateFromQuaternion(smartie.rotation);
            //Gets missile velocity
            return Vector3.Normalize(Vector3.Transform(new Vector3(-1.0f, 0f, 0f), rotationMatrix)) * missileSpeed;
        }

        Vector3 MissilePosition()
        {
            //Gets missile position
            return smartie.position + (Vector3.Normalize(MissileVelocity()) * missileOffset);                           
        }

        void TestCollision(GameObject missile)
        {
            //Creates new boundingsphere
            BoundingSphere missileSphere =
                missile.model.Meshes[0].BoundingSphere;

            missileSphere.Radius = 2;

            //Sets sphere to correct position
            missileSphere.Center = missile.position;

            foreach (GameObject drum in drums)
            {
                //If drum is alive...
                if (drum.alive)
                {
                    //Creates new boundingsphere
                    BoundingSphere drumSphere =
                        drum.model.Meshes[0].BoundingSphere;
                    drumSphere.Center = drum.position;

                    drumSphere.Radius = 2;

                    //If bounding spheres collide
                    if (drumSphere.Intersects(missileSphere))
                    {
                        soundBank.PlayCue("explosion");
                        //Kills missile and drum
                        missile.alive = false;
                        drum.alive = false;
                        //Decreases drums remaining
                        drumsRemaining = drumsRemaining - 1;
                    }
                }
            }
        }

        /// <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

            //Draws game objects
            DrawGameObject(driveOne);
            DrawGameObject(driveTwo);
            DrawGameObject(smartie);
            DrawGameObject(rugby);
            DrawGameObject(planet);
            DrawGameObject(planetSurround);

            //Allows 2D text on screen
            spriteBatch.Begin();
            spriteBatch.DrawString(text, "Missiles Remaining: " + missilesRemaining, new Vector2(30.0f, 30.0f), Color.White);
            spriteBatch.DrawString(text, "Drums Remaining: " + drumsRemaining, new Vector2(550.0f, 30.0f), Color.White);
            spriteBatch.End();


            foreach (GameObject missile in missiles)
            {
                if (missile.alive)
                {
                    //Draws missile if alive
                    DrawGameObject(missile);
                }
            }


            foreach (GameObject drum in drums)
            {
                if (drum.alive)
                {
                    //Draws drums that are alive
                    DrawGameObject(drum);
                }
            }

            base.Draw(gameTime);
        }
            

        void DrawGameObject(GameObject gameobject)
        {
            //Changes back 2D settings from text to 3D settings
            GraphicsDevice.RenderState.DepthBufferEnable = true;
            GraphicsDevice.SamplerStates[0].AddressU = TextureAddressMode.Wrap;
            GraphicsDevice.SamplerStates[0].AddressV = TextureAddressMode.Wrap;

            foreach (ModelMesh mesh in gameobject.model.Meshes)
            {
                foreach (BasicEffect effect in mesh.Effects)
                {
                    effect.EnableDefaultLighting();
                    effect.PreferPerPixelLighting = true;

                    effect.World = Matrix.CreateFromQuaternion(gameobject.rotation) *
                        Matrix.CreateScale(gameobject.scale) *
                        Matrix.CreateTranslation(gameobject.position);

                    Matrix.CreateTranslation(gameobject.position);


                    effect.Projection = cameraProjectionMatrix;
                    effect.View = cameraViewMatrix;
                }
                mesh.Draw();
            }
        }
    }
}
This topic has been dead for over six months. Start a new discussion instead.
Have something to contribute to this discussion? Please be thoughtful, detailed and courteous, and be sure to adhere to our posting rules.