Search code examples
c#monogame

My ball and my rectangle wont collide properly (Monogame)


I am currently coding an arkanoid type game for my school project and just started out on monogame. I encountered a collision problem on the big red rectangle and the ball. I just cant figure out what is wrong with my code I appreciate all of your help in advance.

Collision Video: https://youtu.be/HOuUS8bUKn4

Game1.cs

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using System;
using System.Collections.Generic;

namespace TSA3
{
    public class Game1 : Game
    {
        private GraphicsDeviceManager graphics;
        private SpriteBatch spriteBatch;

        // Platform
        Platform platform;
        Texture2D platformTexture;
        Rectangle platformRectangle;
        Color platformColor;

        // Ball
        Ball ball;
        Texture2D ballTexture;
        Rectangle ballRectangle;
        Color ballColor;
        bool ballDirectionX = true, ballDirectionY = true;

        // Enemy
        Enemy enemy;
        Texture2D enemyTexture;
        Rectangle enemyRectangle;
        Color enemyColor;

        Random random = new Random();

        public const int ScreenW = 1200, ScreenH = 720;

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
            IsMouseVisible = true;

        }

        protected override void Initialize()
        {
            graphics.PreferredBackBufferWidth = ScreenW;
            graphics.PreferredBackBufferHeight = ScreenH;
            graphics.ApplyChanges();

            Window.AllowUserResizing = false;
            Window.AllowAltF4 = true;
            Window.Title = "Arkanoid";

            // Platform
            platformTexture = Content.Load<Texture2D>("platform");
            platformRectangle = new Rectangle(0, Window.ClientBounds.Height - 50, 100, 30);
            platformColor = Color.White;

            // Ball
            ballTexture = Content.Load<Texture2D>("ball");
            ballRectangle = new Rectangle(0, 0, 20, 20);
            ballColor = Color.DarkBlue;

            // Enemy
            enemyTexture = Content.Load<Texture2D>("enemyPiece");
            enemyRectangle = new Rectangle(Window.ClientBounds.Width / 2, Window.ClientBounds.Height / 2, 200, 200);
            enemyColor = Color.White;

            base.Initialize();
        }

        protected override void LoadContent()
        {
            // Player
            platform = new Platform(platformTexture, platformRectangle, platformColor, Window.ClientBounds.Width - 100);

            // Ball
            ball = new Ball(ballTexture, ballRectangle, ballColor, Window.ClientBounds.Width - 20, Window.ClientBounds.Height - 20, ballDirectionX, ballDirectionY);

            // Enemy
            enemy = new Enemy(enemyTexture, enemyRectangle, enemyColor);

            spriteBatch = new SpriteBatch(GraphicsDevice);

        }

        float spawn = 0;

        protected override void Update(GameTime gameTime)
        {
            spawn += (float)gameTime.ElapsedGameTime.TotalSeconds;

            ball.ballBounce(platform.PlatformRectangle);

            Keys[] k = Keyboard.GetState().GetPressedKeys();
            foreach (Keys key in k)
            {
                platform.platformMovement(key);
                break;
            }

            if (Keyboard.GetState().IsKeyDown(Keys.Space) && !ball.StartGame)
                ball.StartGame = true;

            ball.ballCollision(platform.PlatformRectangle);
            ball.enemyCollision(enemy.enemyRectangle);

            base.Update(gameTime);
        }


        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            spriteBatch.Begin();
            spriteBatch.Draw(ball.BallTexture, ball.BallRectangle, ball.BallColor);
            spriteBatch.Draw(platform.PlatformTexture, platform.PlatformRectangle, platform.PlatformColor);
            spriteBatch.Draw(enemy.enemyTexture, enemy.enemyRectangle, enemy.enemyColor);
            spriteBatch.End();


            base.Draw(gameTime);
        }
    }
}

Ball.cs

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

namespace TSA3
{
    public class Ball
    {
        Texture2D ballTexture;
        Rectangle ballRectangle;
        Color ballColor;

        int boundaryX, boundaryY;
        bool ballDirectionX, ballDirectionY;
        bool startGame;

        public const int BALL_SPEED = 7;

        public Ball(Texture2D ballTexture, Rectangle ballRectangle, Color ballColor, int boundaryX, int boundaryY, bool ballDirectionX, bool ballDirectionY)
        {
            this.ballTexture = ballTexture;
            this.ballRectangle = ballRectangle;
            this.ballColor = ballColor;
            this.boundaryX = boundaryX;
            this.boundaryY = boundaryY;
            this.ballDirectionX = ballDirectionX;
            this.ballDirectionY = ballDirectionY;

            startGame = false;
        }

        public Texture2D BallTexture { get => ballTexture; }
        public Rectangle BallRectangle { get => ballRectangle; }
        public Color BallColor { get => ballColor; }
        public bool StartGame { get => startGame; set => startGame = value; }

        public void ballBounce(Rectangle platformRectangle)
        {
            if (startGame)
            {
                if (ballRectangle.X <= 0)
                    ballDirectionX = true;
                else if (ballRectangle.X >= boundaryX)
                    ballDirectionX = false;

                if (ballRectangle.Y <= 0)
                {
                    ballDirectionY = true;
                }
                else if (ballRectangle.Y >= boundaryY)
                {
                    startGame = false;
                }

                if (ballDirectionX)
                    ballRectangle.X += BALL_SPEED;
                else
                    ballRectangle.X -= BALL_SPEED;

                if (ballDirectionY)
                    ballRectangle.Y += BALL_SPEED;
                else
                    ballRectangle.Y -= BALL_SPEED;
            }
            else
            {
                ballRectangle.Location = new Point(platformRectangle.X + (platformRectangle.Width / 2) - 10, platformRectangle.Y - (ballRectangle.Height - 5));
            }
        }

        public void ballCollision(Rectangle platform)
        {
            if (ballRectangle.Intersects(platform))
                ballDirectionY = false;    
        }

        public void enemyCollision(Rectangle enemyRectangle)
        {
            if (ballRectangle.Intersects(enemyRectangle))
                ballDirectionY = false;
        }


    }
}

Enemy.cs

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

namespace TSA3
{
    public class Enemy
    {
        public Texture2D enemyTexture;
        public Rectangle enemyRectangle;
        public Color enemyColor;

        public bool isVisible = true;

        Random random = new Random();

        public Enemy(Texture2D enemyTexture, Rectangle enemyRectangle, Color enemyColor)
        {
            this.enemyTexture = enemyTexture;
            this.enemyRectangle = enemyRectangle;
            this.enemyColor = enemyColor;
        }

        public Texture2D EnemyTexture { get => enemyTexture; }
        public Rectangle EnemyRectangle { get => enemyRectangle; }
        public Color EnemyColor { get => enemyColor; }
    }
}

Platform.cs

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using System;
using System.Collections.Generic;
using System.Text;

namespace TSA3
{
    public class Platform
    {
        Texture2D platformTexture;
        Rectangle platformRectangle;
        Color platformColor;

        int boundaryX;

        public const int PLATFORM_SPEED = 10;

        public Platform(Texture2D platformTexture, Rectangle platformRectangle, Color platformColor, int boundaryX)
        {
            this.platformTexture = platformTexture;
            this.platformRectangle = platformRectangle;
            this.platformColor = platformColor;
            this.boundaryX = boundaryX;
        }

        public Texture2D PlatformTexture { get => platformTexture; }
        public Rectangle PlatformRectangle { get => platformRectangle; }
        public Color PlatformColor { get => platformColor; }

        public void platformMovement(Keys controls)
        {
            if (controls == Keys.A && platformRectangle.X > 0)
                platformRectangle.X -= PLATFORM_SPEED;

            if (controls == Keys.D && platformRectangle.X < boundaryX)
                platformRectangle.X += PLATFORM_SPEED;
        }

    }
}

Thank you in advance to anyone who will help!


Solution

  • This method is missing the necessary code to function properly to approach the block from any side:

    public void enemyCollision(Rectangle enemyRectangle)
    {
        if (ballRectangle.Intersects(enemyRectangle))
            ballDirectionY = false;
    }
    

    Currently it only works the same as your platform does: set the Y direction upwards on collision.
    This works fine for the platform, as it's thin and close to the edge of the screen, so it doesn't need other collision checks.

    Try improving this method similair with what you've done with the ball collisions on the edges of the screen.

    What would be important here, is knowing the positions of the corners of the red rectangle, so you can calculate at which position the ball is hitting the rectangle.

    As far I know, you cannot have the exact borders, but you can measure the same with calculating the positions of the corners. you could for example take the EnemyRectangle and get their x/y position, that would be it's top-left, than you can add the rectangle's width, and you'll have the top-right (same also works with the height for the bottom corners). If you calculate the balls position along with the rectangle corners, you'll know at which side the ball is colliding with the screen.

    An example of a collision on top:

    public void enemyCollision(Rectangle enemyRectangle)
    {
        if (ballRectangle.Intersects(enemyRectangle))
        {
            if (ballRectangle.x > enemyRectangle.x && 
                ballRectangle.x < enemyRectangle.x + enemyRectangle.Width && 
                ballRectangle.y > enemyRectangle.y)
                 ballDirectionY = false;
        }
    }