Code Review ::Pong Clone::

Started by
9 comments, last by Chad Smith 11 years ago

I just finished my first game in XNA 4.0 and would love some feedback on my code.

Game1:

[spoiler]


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

        public enum State {Menu, Playing, GameOver, Credits };

        // Ball
        Ball ball;

        // Top and Bottom bumbers
        Texture2D topBumper;
        Texture2D bottomBumper;
        Vector2 tBumperPos;
        Vector2 bBumperPos;

        // Paddles
        Paddle p1;
        Paddle p2;

        // Score Font
        SpriteFont scoreFont;
        Vector2 p1ScorePos;
        Vector2 p2ScorePos;

        // Background Music
        Song gameplayMusic;

        // Game State
        State gameState;

        // Main Menu State
        MainMenuState mainMenuState;
        ParallaxingBackground mainMenuParallaxingBackground;

        // Various buttons
        Buttons playButton;
        Buttons creditsButton;
        Buttons exitButton;

        // Indexes for Menu Selection
        int menuIndex = 0;

        // Keyboard states to determine button presses in menu
        KeyboardState previousKeyboardState;
        KeyboardState currentKeyboardState;

        // Credits Screen
        CreditsScreenState creditsBackground;

        // Game Over Screen
        MainMenuState gameOverScreen;
        Buttons playAgain;
        Buttons exitGameOver;

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            graphics.IsFullScreen = false;
            graphics.PreferredBackBufferHeight = 600;
            graphics.PreferredBackBufferWidth = 1024;
            Window.Title = "PRONG";
            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
            ball = new Ball();
            p1 = new Paddle();
            p2 = new Paddle();
            playButton = new Buttons();
            creditsButton = new Buttons();
            exitButton = new Buttons();

            // Main Menu
            mainMenuState = new MainMenuState();
            mainMenuParallaxingBackground = new ParallaxingBackground();

            // Credits Screen
            creditsBackground = new CreditsScreenState();

            // Start game in main menu
            gameState = State.Menu;

            // Credits Screen

            // Set Play to active by default
            playButton.active = true;
            creditsButton.active = false;
            exitButton.active = false;

            // Game Over Screen
            gameOverScreen = new MainMenuState();
            playAgain = new Buttons();
            exitGameOver = new Buttons();
            playAgain.active = true;
            exitGameOver.active = false;

            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

            // Load Ball
            ball.texture = Content.Load<Texture2D>("ball");
            // Starting position of ball
            ball.position.X = (1024 / 2) - ball.width / 2;
            ball.position.Y = (600 / 2) - ball.height / 2;

            // Load Bumpers
            topBumper = Content.Load<Texture2D>("topBumper");
            bottomBumper = Content.Load<Texture2D>("bottomBumper");
            tBumperPos.X = 0;
            tBumperPos.Y = 0;
            bBumperPos.X = 0;
            bBumperPos.Y = 600 - 24;

            // Load Paddles
            p1.texture = Content.Load<Texture2D>("paddle");
            p2.texture = Content.Load<Texture2D>("paddle");
            p1.position.X = 25;
            p1.position.Y = (600 / 2) - p1.height / 2;
            p2.position.X = 1024 - 25 - p2.width;
            p2.position.Y = (600 / 2) - p2.height / 2;

            // Load Score Font
            scoreFont = Content.Load<SpriteFont>("Score");
            p1ScorePos.X = 5;
            p1ScorePos.Y = 26;
            p2ScorePos.X = 750;
            p2ScorePos.Y = 26;

            // Load Gameplay Music
            gameplayMusic = Content.Load<Song>("discWars");

            // Start music right away
            PlayMusic(gameplayMusic);

            // Load Main Menu
            mainMenuState.texture = Content.Load<Texture2D>("mainMenuTemp");
            mainMenuState.position.X = 0;
            mainMenuState.position.Y = 0;

            // Main menu buttons

            // Load Position of Play button
            playButton.poition.X = (1024 / 2) - playButton.width / 2;
            playButton.poition.Y = 500 - playButton.height;

            // Load Position of Credits button
            creditsButton.poition.X = (1024 / 2) - creditsButton.width / 2;
            creditsButton.poition.Y = 535 - creditsButton.height;

            // Load Position of Exit button
            exitButton.poition.X = (1024 / 2) - exitButton.width / 2;
            exitButton.poition.Y = 570 - creditsButton.height;

            // Load Play button textures
            playButton.texture.Insert(0, Content.Load<Texture2D>("playIdle"));
            playButton.texture.Insert(1, Content.Load<Texture2D>("playHover"));

            // Load Credits button textures
            creditsButton.texture.Insert(0, Content.Load<Texture2D>("creditsIdle"));
            creditsButton.texture.Insert(1, Content.Load<Texture2D>("creditsHover"));

            // Load Exit button textures
            exitButton.texture.Insert(0, Content.Load<Texture2D>("exitIdle"));
            exitButton.texture.Insert(1, Content.Load<Texture2D>("exitHover"));

            // Load Parallaxing Background
            mainMenuParallaxingBackground.Initialize(Content, "movingBackground", GraphicsDevice.Viewport.Width, -0.3f);

            // Credits Background
            creditsBackground.texture = Content.Load<Texture2D>("creditsScreen");
            creditsBackground.position.X = 0;
            creditsBackground.position.Y = 0;

            // Game Over State
            gameOverScreen.texture = Content.Load<Texture2D>("gameOver");
            playAgain.texture.Insert(0, Content.Load<Texture2D>("playIdle"));
            playAgain.texture.Insert(1, Content.Load<Texture2D>("playHover"));
            exitGameOver.texture.Insert(0, Content.Load<Texture2D>("exitIdle"));
            exitGameOver.texture.Insert(1, Content.Load<Texture2D>("exitHover"));
            // Load Position of Play Again button
            playAgain.poition.X = (1024 / 2) - playButton.width / 2;
            playAgain.poition.Y = 500 - playButton.height;

            // Load Position of Exit button
            exitGameOver.poition.X = (1024 / 2) - creditsButton.width / 2;
            exitGameOver.poition.Y = 535 - creditsButton.height;
        }

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

            switch (gameState)
            {
                case State.Playing:
                    {
                         ball.Update(gameTime);
                         ball.UpdateBallSpeed(gameTime);
                         p1.Update();
                         p2.Update();

                         //Update player controls
                         PlayerControls();

                        // Update collisions
                        UpdateCollision();

                        // End game if score = 7
                        if (ball.score1 == 7 || ball.score2 == 7)
                        {
                            gameState = State.GameOver;
                            // Reset scores
                            ball.score1 = 0;
                            ball.score2 = 0;
                        }

                        break;
                    }
                case State.Menu:
                    {
                        mainMenuParallaxingBackground.Update();
                        MainMenuSelection();
                        break;
                    }
                case State.Credits:
                    {
                        mainMenuParallaxingBackground.Update();

                        currentKeyboardState = Keyboard.GetState();

                        if (currentKeyboardState.IsKeyDown(Keys.Escape) && previousKeyboardState.IsKeyUp(Keys.Escape))
                        {
                            gameState = State.Menu;
                        }

                        previousKeyboardState = currentKeyboardState;

                        break;
                    }
                case State.GameOver:
                    {
                        mainMenuParallaxingBackground.Update();
                        GameOverSelection();
                        break;
                    }
            }

            // TODO: Add your update logic here
           

            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.Black);

            // TODO: Add your drawing code here
            spriteBatch.Begin();

            switch (gameState)
            {
                case State.Playing:
                    {
                        // Draw score
                        spriteBatch.DrawString(scoreFont, "Player 1: " + ball.score1, p1ScorePos, Color.Teal);
                        spriteBatch.DrawString(scoreFont, "Player 2: " + ball.score2, p2ScorePos, Color.Teal);

                        // Draw ball
                        ball.Draw(spriteBatch);

                        // Draw Paddles
                        p1.Draw(spriteBatch);
                        p2.Draw(spriteBatch);

                        // Draw bumpers
                        spriteBatch.Draw(topBumper, tBumperPos, Color.White);
                        spriteBatch.Draw(bottomBumper, bBumperPos, Color.White);
                        break;
                    }
                case State.Menu:
                    {
                        mainMenuParallaxingBackground.Draw(spriteBatch);
                        mainMenuState.Draw(spriteBatch);
                        playButton.Draw(spriteBatch);
                        creditsButton.Draw(spriteBatch);
                        exitButton.Draw(spriteBatch);
                        break;
                    }
                case State.Credits:
                    {
                        mainMenuParallaxingBackground.Draw(spriteBatch);
                        creditsBackground.Draw(spriteBatch);
                        break;
                    }
                case State.GameOver:
                    {
                        mainMenuParallaxingBackground.Draw(spriteBatch);
                        gameOverScreen.Draw(spriteBatch);
                        playAgain.Draw(spriteBatch);
                        exitGameOver.Draw(spriteBatch);
                        break;
                    }
            }            

            spriteBatch.End();

            base.Draw(gameTime);
        }

        // Player Controls for Paddles
        private void PlayerControls()
        {
            // Player 1
            if (Keyboard.GetState(p1.pNumber).IsKeyDown(Keys.W))
            {
                p1.position.Y -= p1.speed;
            }
            if (Keyboard.GetState(p1.pNumber).IsKeyDown(Keys.S))
            {
                p1.position.Y += p1.speed;
            }

            // Player 2
            if (Keyboard.GetState(p2.pNumber).IsKeyDown(Keys.Up))
            {
                p2.position.Y -= p2.speed;
            }
            if (Keyboard.GetState(p2.pNumber).IsKeyDown(Keys.Down))
            {
                p2.position.Y += p2.speed;
            }
        }

        // Collision with paddles
        private void UpdateCollision()
        {
            Rectangle rectangle1;
            Rectangle rectangle2;
            Rectangle rectangle3;

            // Create rectangle for Player 1
            rectangle1 = new Rectangle((int)p1.position.X, (int)p1.position.Y, p1.width, p1.height);

            // Create rectangle for Player 2
            rectangle2 = new Rectangle((int)p2.position.X, (int)p2.position.Y, p2.width, p2.height);

            // Create rectangle for Ball
            rectangle3 = new Rectangle((int)ball.position.X, (int)ball.position.Y, ball.width, ball.height);

            // Do collisions between ball and Player 1
            if (rectangle1.Intersects(rectangle3))
            {
                if (ball.movingDownLeft)
                {
                    ball.movingDownLeft = false;
                    ball.movingDownRight = true;
                }
                if (ball.movingUpLeft)
                {
                    ball.movingUpLeft = false;
                    ball.movingUpRight = true;
                }
                ball.ballSoundEffect.Play();
            }

            // Do collisions between ball and Player 2
            if (rectangle3.Intersects(rectangle2))
            {
                if (ball.movingDownRight)
                {
                    ball.movingDownRight = false;
                    ball.movingDownLeft = true;
                }
                if (ball.movingUpRight)
                {
                    ball.movingUpRight = false;
                    ball.movingUpLeft = true;
                }
                ball.ballSoundEffect.Play();
            }
        }

        private void PlayMusic(Song song)
        {
            try
            {
                MediaPlayer.Play(song);
                MediaPlayer.IsRepeating = true;
            }
            catch { }
        }

        //Menu selections
        private void MainMenuSelection()
        {
            currentKeyboardState = Keyboard.GetState();

            // If player presses down arrow, scroll down through the menu
            if (currentKeyboardState.IsKeyDown(Keys.Down) && previousKeyboardState.IsKeyUp(Keys.Down))
            {
                menuIndex++;
            }

            if (menuIndex == 0)
            {
                // Activate play button
                playButton.active = true;
                creditsButton.active = false;
                exitButton.active = false;
            }
            if (menuIndex == 1)
            {
                // Activate credits button
                playButton.active = false;
                creditsButton.active = true;
                exitButton.active = false;
            }
            if (menuIndex == 2)
            {
                // Activate exit button
                playButton.active = false;
                creditsButton.active = false;
                exitButton.active = true;
            }
            // Loop back around if pressing down key
            if (menuIndex > 2)
            {
                menuIndex = 0;
            }

            // If player presses up arrow, scroll up through the menu
            if (currentKeyboardState.IsKeyDown(Keys.Up) && previousKeyboardState.IsKeyUp(Keys.Up))
            {
                menuIndex--;
            }

            if (menuIndex == 0)
            {
                // Activate play button
                playButton.active = true;
                creditsButton.active = false;
                exitButton.active = false;
            }
            if (menuIndex == 1)
            {
                // Activate credits button
                playButton.active = false;
                creditsButton.active = true;
                exitButton.active = false;
            }
            if (menuIndex == 2)
            {
                // Activate exit button
                playButton.active = false;
                creditsButton.active = false;
                exitButton.active = true;
            }
            // Loop back around if pressing up key
            if (menuIndex < 0)
            {
                menuIndex = 2;
            }

            previousKeyboardState = currentKeyboardState;

            // If player selects play
            if (currentKeyboardState.IsKeyDown(Keys.Enter))
            {
                if (playButton.active)
                {
                    gameState = State.Playing;
                }
                else if (creditsButton.active)
                {
                    gameState = State.Credits;
                }
                else if (exitButton.active)
                {
                    this.Exit();
                }
            }
        }
        //Menu selections
        private void GameOverSelection()
        {
            currentKeyboardState = Keyboard.GetState();

            // If player presses down arrow, scroll down through the menu
            if (currentKeyboardState.IsKeyDown(Keys.Down) && previousKeyboardState.IsKeyUp(Keys.Down))
            {
                menuIndex++;
            }

            if (menuIndex == 0)
            {
                // Activate play button
                playAgain.active = true;
                exitGameOver.active = false;
            }
            if (menuIndex == 1)
            {
                // Activate exit button
                playAgain.active = false;
                exitGameOver.active = true;
            }
            // Loop back around if pressing down key
            if (menuIndex > 1)
            {
                menuIndex = 0;
            }

            // If player presses up arrow, scroll up through the menu
            if (currentKeyboardState.IsKeyDown(Keys.Up) && previousKeyboardState.IsKeyUp(Keys.Up))
            {
                menuIndex--;
            }

            if (menuIndex == 0)
            {
                // Activate play button
                playAgain.active = true;
                exitGameOver.active = false;
            }
            if (menuIndex == 1)
            {
                // Activate exit button
                playAgain.active = false;
                exitGameOver.active = true;
            }
            // Loop back around if pressing up key
            if (menuIndex < 0)
            {
                menuIndex = 1;
            }

            previousKeyboardState = currentKeyboardState;

            // If player selects play
            if (currentKeyboardState.IsKeyDown(Keys.Enter))
            {
                if (playAgain.active)
                {
                    gameState = State.Playing;
                }
                else if (exitGameOver.active)
                {
                    this.Exit();
                }
            }
        }
    }
}

[/spoiler]

Ball Class:

[spoiler]


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace TronPongClone
{
    class Ball : Microsoft.Xna.Framework.Game
    {
        // Position of the ball
        public Vector2 position;

        // Texture of the ball
        public Texture2D texture;

        // Speed of the ball
        public float speed;

        // Height of the ball
        public int height;

        // Width of the ball
        public int width;

        // Movement directions
        public bool movingDownRight, movingDownLeft, movingUpRight, movingUpLeft;

        // Player 1 Score
        public int score1;

        // PLayer 2 Score
        public int score2;
        
        // SoundEffect when ball hits walls
        public SoundEffect ballSoundEffect;

        // The rate at which the ball speeds up
        TimeSpan increaseBallSpeed;
        TimeSpan previousBallSpeed;

        // Time to give player to reset after score is made
        TimeSpan resetTime;
        TimeSpan previousResetTime;
        //Update the previousResetTime every 0.1 seconds for more acurate delay
        TimeSpan updatePreviousTime;

        // DelayTimer
        public int timer;

        public Ball()
        {
            Content.RootDirectory = ("Content");
            texture = null;
            position = Vector2.Zero;
            height = 20;
            width = 20;
            movingDownLeft = true;
            movingDownRight = false;
            movingUpLeft = false;
            movingUpRight = false;
            score1 = 0;
            score2 = 0;
            ballSoundEffect = Content.Load<SoundEffect>("blip");
            increaseBallSpeed = TimeSpan.FromSeconds(10.0f);
            previousBallSpeed = TimeSpan.Zero;
            resetTime = TimeSpan.FromSeconds(1.0f);
            previousResetTime = TimeSpan.Zero;
            updatePreviousTime = TimeSpan.FromSeconds(0.1f);
            speed = 6.0f;
            timer = 0;
        }

        public void Update(GameTime gameTime)
        {
            // Ball moving Down and Left
            if (movingDownLeft)
            {
                position.Y += speed;
                position.X -= speed;
            }

            // Ball moving Down and Right
            if (movingDownRight)
            {
                position.Y += speed;
                position.X += speed;
            }

            // Ball moving Up and Left
            if (movingUpLeft)
            {
                position.Y -= speed;
                position.X -= speed;
            }

            // Ball moving Up and Right
            if (movingUpRight)
            {
                position.Y -= speed;
                position.X += speed;
            }

            // Ball moving down and left bouncing off bottom wall
            if (movingDownLeft && position.Y >= 600 - 24 - height)
            {
                movingDownLeft = false;
                movingUpLeft = true;
                ballSoundEffect.Play();
            }

            // Ball moving up and left bouncing off left wall
            if (movingUpLeft && position.X <= 0)
            {
                movingUpLeft = false;
                movingUpRight = false;
                // Add score to player 2
                score2++;
                // Reset ball speed
                speed = 6.0f;
                // Play sound
                ballSoundEffect.Play();
                //Set Delay Timer
                timer = 1;
            }

            // Ball moving up and right bouncing off top wall
            if (movingUpRight && position.Y <= 0 + 24)
            {
                movingUpRight = false;
                movingDownRight = true;
                ballSoundEffect.Play();
            }

            // Ball moving down and right bouncing off right wall
            if (movingDownRight && position.X >= 1024 - width)
            {
                movingDownRight = false;
                movingDownLeft = false;
                // Add score to player 1
                score1++;
                // Reset speed
                speed = 6.0f;
                // Play sound
                ballSoundEffect.Play();
                timer = 2;
            }

            // Ball moving up and left bouncing off top wall
            if (movingUpLeft && position.Y <= 0 + 24)
            {
                movingUpLeft = false;
                movingDownLeft = true;
                ballSoundEffect.Play();
            }

            // Ball moving down and left bouncing off left wall
            if (movingDownLeft && position.X <= 0)
            {
                movingDownLeft = false;
                movingDownRight = false;
                // Add score to player 2
                score2++;
                // Reset speed
                speed = 6.0f;
                // Play sound
                ballSoundEffect.Play();
                timer = 3;
            }

            // Ball moving down and right bouncing off bottom wall
            if (movingDownRight && position.Y >= 600 - 24 - height)
            {
                movingDownRight = false;
                movingUpRight = true;
                ballSoundEffect.Play();
            }

            // Ball moving up and right bouncing off right wall
            if (movingUpRight && position.X >= 1024 - width)
            {
                movingUpRight = false;
                movingUpLeft = false;
                // Add score to player 1
                score1++;
                // Reset speed
                speed = 6.0f;
                // Play sound
                ballSoundEffect.Play();
                timer = 4;
            }
            if (timer == 1)
            {
                if (gameTime.TotalGameTime - previousResetTime > resetTime)
                {
                    previousResetTime = gameTime.TotalGameTime;
                    // Reset ball position going toward player 1
                    position.X = (1024 / 2) - width / 2;
                    position.Y = (600 / 2) - height / 2;
                    movingUpLeft = true;
                    timer = 0;
                }
            }
            else if (timer == 2)
            {
                if (gameTime.TotalGameTime - previousResetTime > resetTime)
                {
                    previousResetTime = gameTime.TotalGameTime;
                    // Reset ball position going toward player 2
                    position.X = (1024 / 2) - width / 2;
                    position.Y = (600 / 2) - height / 2;
                    movingDownRight = true;
                    timer = 0;
                }
            }
            else if (timer == 3)
            {
                if (gameTime.TotalGameTime - previousResetTime > resetTime)
                {
                    previousResetTime = gameTime.TotalGameTime;
                    // Reset ball position going toward player 1
                    position.X = (1024 / 2) - width / 2;
                    position.Y = (600 / 2) - height / 2;
                    movingDownLeft = true;
                    timer = 0;
                }
            }
            else if (timer == 4)
            {
                if (gameTime.TotalGameTime - previousResetTime > resetTime)
                {
                    previousResetTime = gameTime.TotalGameTime;
                    // Reset ball position going toward player 1
                    position.X = (1024 / 2) - width / 2;
                    position.Y = (600 / 2) - height / 2;
                    movingUpRight = true;
                    timer = 0;
                }
            }
            else if (gameTime.TotalGameTime - previousResetTime > updatePreviousTime)
                {
                    previousResetTime = gameTime.TotalGameTime;
                }
        }

        public void UpdateBallSpeed(GameTime gameTime)
        {
            // Icrease the speed of the ball every 10 seconds
            if (gameTime.TotalGameTime - previousBallSpeed > increaseBallSpeed)
            {
                previousBallSpeed = gameTime.TotalGameTime;
                speed = speed + 0.5f;
            }
        }

        public void Draw(SpriteBatch spriteBatch)
        {
            spriteBatch.Draw(texture, position, Color.White);
        }
    }
}

[/spoiler]

Paddle Class:

[spoiler]


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;

namespace TronPongClone
{
    class Paddle
    {
        // Paddle Texture
        public Texture2D texture;

        // Paddle position
        public Vector2 position;

        // Player Number
        public PlayerIndex pNumber;

        // Paddle Height
        public int height;

        // Paddle Width
        public int width;

        // Paddle speed
        public float speed;

        public Paddle()
        {
            texture = null;
            position = Vector2.Zero;
            pNumber = PlayerIndex.One;
            width = 35;
            height = 150;
            speed = 20.0f;
        }

        public void Update()
        {
            // Keep paddles within play field
            if (position.Y <= 24)
            {
                position.Y = 24;
            }

            if (position.Y >= 600 - 24 - height)
            {
                position.Y = 600 - 24 - height;
            }
        }

        public void Draw(SpriteBatch spriteBatch)
        {
            spriteBatch.Draw(texture, position, Color.White);
        }
    }
}

[/spoiler]

Button Class:

[spoiler]


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;

namespace TronPongClone
{
    class Buttons
    {
        // Button texture at Idle
        public List<Texture2D> texture;

        // Button height
        public int height;

        // Button width
        public int width;

        // Button position
        public Vector2 poition;

        // Button state
        public bool active;

        public Buttons()
        {
            texture = new List<Texture2D>();
            height = 100;
            width = 300;
            poition = Vector2.Zero;
            this.active = true;
        }

        public void Update(SpriteBatch spriteBatch)
        {
        }

        public void Draw(SpriteBatch spriteBatch)
        {
            if (active == true)
            {
                spriteBatch.Draw(texture.ElementAt(1), poition, Color.White);
            }
            if (active == false)
            {
                spriteBatch.Draw(texture.ElementAt(0), poition, Color.White);
            }
        }
    }
}

[/spoiler]

MainMenuState Class:

[spoiler]


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 TronPongClone
{
    class MainMenuState
    {
        // Main menu texture
        public Texture2D texture;

        // Main menu poisition
        public Vector2 position;

        // Main menu height
        public int height;

        // Main menu width
        public int width;

        public KeyboardState state;


        public MainMenuState()
        {
            texture = null;
            position = Vector2.Zero;
            height = 600;
            width = 1024;
            state = Keyboard.GetState();
        }

        public void Update()
        {
        }

        public void Draw(SpriteBatch spriteBatch)
        {
            spriteBatch.Draw(texture, position, Color.White);
        }
    }
}

[/spoiler]

ParallaxingBackground Class:

[spoiler]


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 TronPongClone
{
    class ParallaxingBackground
    {
        // The image representing the parallaxing background
        Texture2D texture;

        // An array of poisitions of the parallaxing background
        Vector2[] poisitions;

        // The speed which the background is moving
        float speed;

        public void Initialize(ContentManager content, String texturePath, int screenWidth, float speed)
        {
            // Load the background texture we will be using
            texture = content.Load<Texture2D>(texturePath);

            // Set the speed of the background
            this.speed = speed;

            // If we divide the screen with the texture width then we can
            // determine the number of tiles needed
            // We add 1 to it so that we won't have a gap in the tiling
            poisitions = new Vector2[screenWidth / texture.Width + 1];

            // Set the initial positions of the parallaxing background
            for (int i = 0; i < poisitions.Length; i++)
            {
                // We need the tiles to be side by side to create a tiling effect
                poisitions = new Vector2(i * texture.Width, 0);
            }
        }

        public void Update()
        {
            // Update the position of the background
            for (int i = 0; i < poisitions.Length; i++)
            {
                // Update the position of the screen by adding the speed
                poisitions.X += speed;
                // If the speed has the background moving left
                if (speed <= 0)
                {
                    // Check the texture is out of view then put that texture
                    // at the end of the screen
                    if (poisitions.X <= -texture.Width)
                    {
                        poisitions.X = texture.Width * (poisitions.Length - 1);
                    }
                }
                // If the speed has the background moving to the right
                else
                {
                    // Check if the texture is out of view then position it to the start of the screen
                    if (poisitions.X >= texture.Width * (poisitions.Length - 1))
                    {
                        poisitions.X = -texture.Width;
                    }
                }
            }
        }

        public void Draw(SpriteBatch spriteBatch)
        {
            for (int i = 0; i < poisitions.Length; i++)
            {
                spriteBatch.Draw(texture, poisitions, Color.White);
            }
        }
    }
}

[/spoiler]

CreditsScreenState Class:

[spoiler]


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;

namespace TronPongClone
{
    class CreditsScreenState
    {
        // Credits screen texture
        public Texture2D texture;

        // Credits screen position
        public Vector2 position;

        // Screen height
        public int height;

        // Screen width
        public int width;

        public CreditsScreenState()
        {
            texture = null;
            position = Vector2.Zero;
            height = 600;
            width = 1024;
        }

        public void Draw(SpriteBatch spriteBatch)
        {
            spriteBatch.Draw(texture, position, Color.White);
        }
    }
}


[/spoiler]

Cpl Alt, Travis A

USMC

Advertisement

I haven't read the whole thing, but based on the ball class my main piece of advice would be this:

Try to reduce the number of conditions. The more similar code paths you have, the more opportunities there are for mistakes, particularly copy&paste errors. For example, rather than your 4 "moving..." booleans use a single velocity Vector2. You can add that to your position every update, avoiding 4 if statements. Then to bounce off the walls you just do velocity.x = -velocity.x

___________________________________________________David OlsenIf I've helped you, please vote for PigeonGrape!
First off, finishing any game, no matter how small, is an accomplishment, so congratulations!

These are some things that jumped out at me when reviewing your code:
  • You've hard coded the width and height of the screen, and the playable area, in a number of locations. Consider having a single named constant for each of these values.
  • Why not create a class for the Bumpers?
  • You can probably move all the menu related stuff into the menu state class.
  • You're not making optimum use of constructors. Instead of code like this:
    
    someButton = new Button();
    someButton.active = true;
    
    someGameObject = new GameObject();
    someGameObject.position.x = /* ... */;
    someGameObject.position.y = /* ... */;
    // And so on...
    
    Consider writing a constructor that will allow you to specify this stuff:
    
    someButton = new Button(Button.State.Active); // Enums are easier than booleans to understand sometimes
    
    someGameObject = new GameObject(positionX, positionY, /* ... */);
    
  • You're making extensive use of direct access to public fields. This might be manageable for smaller games, but it will quickly spiral out of control when you start trying to write larger programs. The idea of object oriented design is to delegate object specific logic to the objects in question, by calling methods (or property accessors).

    For example, instead of:
    
    private void PlayerControls()
    {
    	// Player 1
    	if (Keyboard.GetState(p1.pNumber).IsKeyDown(Keys.W))
    	{
    		p1.position.Y -= p1.speed;
    	}
    	if (Keyboard.GetState(p1.pNumber).IsKeyDown(Keys.S))
    	{
    		p1.position.Y += p1.speed;
    	}
    
    	// Player 2
    	if (Keyboard.GetState(p2.pNumber).IsKeyDown(Keys.Up))
    	{
    		p2.position.Y -= p2.speed;
    	}
    	if (Keyboard.GetState(p2.pNumber).IsKeyDown(Keys.Down))
    	{
    		p2.position.Y += p2.speed;
    	}
    }
    
    Perhaps something like this:
    
    private void UpdatePlayer(Paddle paddle, Keys up, Keys down)
    {
    	PlayerIndex player = paddle.Player;
    	KeyboardState keyboard = Keyboard.GetState(player)
    	if (keyboard.IsKeyDown(up))
    	{
    		paddle.Up();
    	}
    	if (keyboard.IsKeyDown(down)
    	{
    		paddle.Down();
    	}
    }
    
    private void PlayerControls()
    {
    	UpdatePlayer(p1, Keys.W, Keys.S);
    	UpdatePlayer(p2, Keys.Up, Keys.Down);
    }
    
    The "Up" and "Down" methods would apply the (private) speed to the position,
  • The ball "is a" game?
    
    class Ball : Microsoft.Xna.Framework.Game
    
  • I don't think the ball should be responsible for keeping track of the player's score. This logic can be pushed to the calling code.
  • I notice that the members previousBallSpeed and increaseBallSpeed for the Ball are not actually speeds, they are timing related. Likewise, your "timer" is not in time units, it is actually used to remember the state you want to reset from.

    When dealing with primitives, it can be an easy mistake to accidentally use mix two values that are expressed in different units together. One way to guard against this is to be explicit and consistent in your naming of the variables.
  • I agree with RAZORUNREAL, having a single velocity will be easier to write and understand.

I had a lot of these similar issues when I posted my code for review. In fact, it was @rip-off who listed me things I needed to change. What I would recommend doing is copying this list into word, and deciding the easiest things to do first, do them, then highlight the bullet point. It shows you that you are making steady progress towards your goal, and keeps giving you that feeling of achievement.

Regards,

Stitchs.

With velocity it's going to be much easier.. you already have a time delta between updates given by "gameTime" in your update methods. So updating a Vector2 location with a velocity is a matter of taking the elapsed number of seconds as a float (elapsed) and doing this:

ballposition += velocity * elapsed

You need to used the elapsed time with a velocity to ensure that the ball speed is consistent across systems.

Thank you all for the different pointers. I honestly believe you can't get better unless you have constructive criticism. I really do appreciate all of you for looking through my code.

Cpl Alt, Travis A

USMC


You've hard coded the width and height of the screen, and the playable area, in a number of locations. Consider having a single named constant for each of these values.

Would that be in a separate class on it's own and other classes inherit from that class that I need the height and widths?

Cpl Alt, Travis A

USMC

No, inheritance would not be used for this. You can either make them public named constants in whichever class makes the most sense to you (e.g. Game1). If none of your existing classes suit, you can make a separate "Constants" class containing just these.

In addition, try to compute things from as few constants as possible. For instance, your three buttons are spaced 35 pixels apart, at 500, 535 and 570. Let use say you want to move the button list a bit. You must change each constant. If you wanted to increase this spacing to 40 pixels, you now have to modify the last two values.

However, you could also express this in terms of just two constants, TopButtonLocation and ButtonSpacing. So the first button is located at TopButtonLocation, the second at TopButtonLocation + ButtonSpacing and the last at TopButtonLocation + (2 * ButtonSpacing) (you could also express the second as playButton.position.X + ButtonSpacing.

Now, to shift the entire menu, just change the TopButtonLocation. To spread out the menu items, just change the ButtonSpacing.

You've hard coded the width and height of the screen, and the playable area, in a number of locations. Consider having a single named constant for each of these values.

Would that be in a separate class on it's own and other classes inherit from that class that I need the height and widths?

I usually have a "Class" (more of a file) called Globals.cs which looks like:


public static class Globals
{
        public static int SCREEN_WIDTH = 800;
        public static int SCREEN_HEIGHT = 600;
}

which allow you to access this anywhere by doing Globals.SCREEN_WIDTH = 1024; etc.

Thank you guys so much for the advise. I am going to start working on a Worm clone using all of your suggestions.....hopefully soon.....wife just bought me SCII: HotS... so it might be a few days before I start.

Cpl Alt, Travis A

USMC

This topic is closed to new replies.

Advertisement