Search code examples
c#artificial-intelligencemonogamepong

When implementing simple Pong AI, two paddles are created and flicker


So, me being a new programmer, instead doing actual AI implementation, I used the following solution for making paddle on the right follow the ball:

if(ball.position.Y > p2.position.Y)
{
    p2.position.Y += ball.position.Y;
}
else if (ball.position.Y < p2.position.Y)
{
    p2.position.Y -= ball.position.Y;
}

However this happens (okay I tried taking a screencap with PrtScn and it semmed to pause the game for a microsecond and capture a single paddle instead of two flickering ones) So what can I do to make the paddle 2 appear as one?

Full Code of Program:

Game1.cs

namespace Pong
{
  public class Game1 : Game
  {
    //Variables
    GraphicsDeviceManager graphics;
    SpriteBatch spriteBatch;
    //Borders
    Texture2D borders;
    //Paddles
    Paddle p1 = new Paddle();
    Paddle p2 = new Paddle();
    //Ball
    Ball ball = new Ball();
    //Positions
    Vector2 bordersPos;
    //Constructor
    public Game1()
        : base()
    {
        graphics = new GraphicsDeviceManager(this);
        graphics.IsFullScreen = false;
        graphics.PreferredBackBufferHeight = 800;
        graphics.PreferredBackBufferWidth = 800;
        //Content Loader
        Content.RootDirectory = "Content";
    }
    //Initialize
    protected override void Initialize()
    {

        base.Initialize();
    }
    //Load Content
    protected override void LoadContent()
    {
        spriteBatch = new SpriteBatch(GraphicsDevice);
        //Assigning Textures
        p1.texture = Content.Load<Texture2D>("paddle1");
        p2.texture = Content.Load<Texture2D>("paddle1");
        borders = Content.Load<Texture2D>("borders");
        ball.texture = Content.Load<Texture2D>("ball");
        //Positions
        p1.position.X = 50;
        p1.position.Y = graphics.GraphicsDevice.Viewport.Height / 2 - (p1.height / 2);
        p2.position.X = graphics.GraphicsDevice.Viewport.Width - 50 - p2.width;
        p2.position.Y = graphics.GraphicsDevice.Viewport.Height / 2 - (p2.height / 2);
        bordersPos.Y = 0;
        bordersPos.X = 0;
        ball.position.X = 800 / 2 - ball.width / 2;
        ball.position.Y = 800 / 2 - ball.height / 2;
    }
    protected override void UnloadContent()
    {

    }
    //Update
    protected override void Update(GameTime gameTime)
    {
        //Exit
        if (Keyboard.GetState().IsKeyDown(Keys.Escape))
            Exit();
        //Update Player Controls
        PlayerInput();
        p1.Update();
        p2.Update();
        ball.Update();
        //Paddle Collision
        if (padCol1())
        {
            if (ball.movingDownLeft)
            {
                ball.movingDownRight = true;
                ball.movingDownLeft = false;
            }
            else if (ball.movingUpLeft)
            {
                ball.movingUpRight = true;
                ball.movingUpLeft = false;
            }
        }
        if (padCol2())
        {
            if (ball.movingDownRight)
            {
                ball.movingDownLeft = true;
                ball.movingDownRight = false;
            }
            else if (ball.movingUpRight)
            {
                ball.movingUpLeft = true;
                ball.movingUpRight = false;
            }
        }
        //AI
        if(ball.position.Y > p2.position.Y){
            p2.position.Y += ball.position.Y;
        }
        else if (ball.position.Y < p2.position.Y)
        {
            p2.position.Y -= ball.position.Y;
        }

        base.Update(gameTime);
    }
    //Draw
    protected override void Draw(GameTime gameTime)
    {
        GraphicsDevice.Clear(Color.Black);

        spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend);
        //Paddles
        p1.Draw(spriteBatch);
        p2.Draw(spriteBatch);
        //Borders
        spriteBatch.Draw(borders, bordersPos, Color.White);
        //Ball
        ball.Draw(spriteBatch);
        spriteBatch.End();
        base.Draw(gameTime);
    }
    //Player Input
    public void PlayerInput()
    {
        //Player 1
        if (Keyboard.GetState(p1.pNumber).IsKeyDown(Keys.W)) 
        {
            p1.position.Y -= p1.speed;
        }
        else if (Keyboard.GetState(p1.pNumber).IsKeyDown(Keys.S))
        {
            p1.position.Y += p1.speed;
        }
    }
    //Paddle Collision
    public bool padCol1()
    {
        if (ball.position.Y >= p1.position.Y && ball.position.X > p1.position.X && ball.position.X < (p1.position.X + p1.width) && ball.position.Y < (p1.position.Y + p1.height))
        {
            return true;
        }
        else
            return false;
    }
    public bool padCol2()
    {
        if (ball.position.Y >= p2.position.Y && ball.position.X > p2.position.X && ball.position.X < (p2.position.X + p2.width) && ball.position.Y < (p2.position.Y + p2.height))
        {
            return true;
        }
        else
            return false;
    }
}
}

Paddle.cs

namespace Pong
{
class Paddle : Game
{
    //Variables
    public Texture2D texture;
    public Vector2 position;
    public PlayerIndex pNumber;
    public int width, height;
    public float speed;
    //Constructor
    public Paddle()
    {
        texture = null;
        position = Vector2.Zero;
        pNumber = PlayerIndex.One;
        width = 64;
        height = 187;
        speed = 10.0f;
    }
    //Update
    public void Update()
    {
        //Set Boundaries
        if (position.Y <= 30) 
            position.Y = 30;
        if (position.Y >= 800 - 217)
            position.Y = 800 - 217;
    }
    //Draw
    public void Draw(SpriteBatch spriteBatch)
    {
        spriteBatch.Draw(texture, position, Color.White);
    }
}

} Ball.cs

namespace Pong
{
class Ball : Game
{
    //Variables
    public Vector2 position;
    public Texture2D texture;
    public int width, height;
    public float speed;
    public bool movingDownLeft, movingUpLeft, movingDownRight, movingUpRight;
    //Constructor
    public Ball()
    {
        Content.RootDirectory = ("Content");
        speed = 6.0f;
        width = 20;
        height = 20;
        movingDownLeft = true;
        movingUpRight = false;
        movingUpLeft = false;
        movingDownRight = false;
        position = Vector2.Zero;
    }
    //Draw
    public void Draw(SpriteBatch spriteBatch)
    {
        spriteBatch.Draw(texture, position, Color.White);
    }
    //Update
    public void Update()
    {
        //Directions
        if(movingUpLeft){
            position.Y -= speed;
            position.X -= speed;
        }
        if (movingDownLeft)
        {
            position.Y += speed;
            position.X -= speed;
        }
        if (movingUpRight)
        {
            position.Y -= speed;
            position.X += speed;
        }
        if (movingDownRight)
        {
            position.Y += speed;
            position.X += speed;
        }
        //Ball Wall Collision
        if(movingUpLeft && position.Y <= 30)
        {
            movingDownLeft = true;
            movingUpLeft = false;
        }
        //1
        else if (movingDownLeft && position.X <= 0)
        {
            movingDownRight = true;
            movingDownLeft = false;
        }
        //2
        else if (movingUpLeft && position.X <= 0)
        {
            movingUpRight = true;
            movingUpLeft = false;
        }
        //3
        else if (movingDownLeft && position.Y >= 800 - 45)
        {
            movingUpLeft = true;
            movingDownLeft = false;
        }
        //4
        else if (movingDownRight && position.X >= 800 - width)
        {
            movingDownLeft = true;
            movingDownRight = false;
        }
        //5
        else if (movingUpRight && position.Y <= 30)
        {
            movingDownRight = true;
            movingUpRight = false;
        }
        //6
        else if (movingDownRight && position.Y >= 800 - 45)
        {
            movingUpRight = true;
            movingDownRight = false;
        }
        //7
        else if (movingUpRight && position.X >= 800 - width)
        {
            movingUpLeft = true;
            movingUpRight = false;
        }
    }
}
}

Solution

  • I've never used MonoGame but this:

    if(ball.position.Y > p2.position.Y)
    {
        p2.position.Y += ball.position.Y;
    }
    else if (ball.position.Y < p2.position.Y)
    {
        p2.position.Y -= ball.position.Y;
    }
    

    Will always overshoot, then trigger the next update.

    Why don't you just do:

    p2.position.Y = ball.position.Y;
    

    EDIT: You should probably also make your input frame rate independent (unless MonoGame does this for you). It seems now you'll get higher movement speed on your paddles depending on your framerate.