Клон Brickbreaker, столкновение шара с кирпичом и поведение шара при столкновении с кирпичом

Я начал изучать моноигру C # несколько недель назад, и я хотел начать свой проект. Выбранный мной проект - это клон-кирпич, и все идет хорошо. Но я наткнулся на то, что часами искал в Google без ответа. У меня проблема с обнаружением столкновения между мячом и кирпичами. Между лопастью и мячом у меня есть рабочее решение. Который :

// Collision between the ball and player
    public void Collision(Player player, Ball ball)
    {
        MinX = (int)player.PlayerPosition.X - ball.Width;
        MaxX = (int)player.PlayerPosition.X + player.Width + ball.Width;
        MinY = 0;
        MaxY = (int)player.PlayerPosition.Y - ball.Height;

        Rectangle BallRectangle = new Rectangle((int)ball.BallPosition.X, (int)ball.BallPosition.Y, ball.Width, ball.Height);
        Rectangle PlayerRectangle = new Rectangle((int)player.PlayerPosition.X, (int)player.PlayerPosition.Y, player.Width, player.Height);

        if (BallRectangle.Intersects(PlayerRectangle))
        {
            ball.BallPosition.Y = MathHelper.Clamp(ball.BallPosition.Y, MinY, MaxY);
            ball.BallPosition.X = MathHelper.Clamp(ball.BallPosition.X, MinX, MaxX);
            ball.BallSpeed.Y *= -1;

            float BallMiddlePoint = ball.BallPosition.X + (ball.Width / 2);
            float PlayerMiddlePoint = player.PlayerPosition.X + (player.Width / 2);

            ball.BallSpeed.X = (BallMiddlePoint - PlayerMiddlePoint) / 10 + ball.ExtraSpeedOverTime;
        }
    }

Теперь вернемся к моей проблеме, я использую Rectangle.Intersect (Rectangle) для проверки столкновения. Основная проблема: как сделать так, чтобы мяч правильно отскакивал от кирпичей?

Надеюсь, я предоставлю достаточно информации.

Мой класс мяча:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;

namespace BrickBreakerV2
{
    class Ball
    {
        // The texture of the ball
        Texture2D BallTexture;

        // The position of the ball
        public Vector2 BallPosition;

        // The speed of the ball
        public Vector2 BallSpeed;

        // The speed that gets added over time
        public float ExtraSpeedOverTime;

        // Time values used in incrementing the speed over time
        TimeSpan IncreaseSpeed;
        TimeSpan PreviousSpeedIncrease;

        // The "active" state of the ball
        public bool Active;

        // The state of movement of the ball
        public bool Moveball;

        // The Width of the ball
        public int Width
        {
            get { return BallTexture.Width; }
        }

        // The Height of the ball
        public int Height
        {
            get { return BallTexture.Height; }
        }

        // Construct a class for Boundaries
        CollisionHandler Collision = new CollisionHandler();


        public void Initialize(ContentManager Content, GraphicsDevice graphicsDevice, Player player)
        {
            BallTexture = Content.Load<Texture2D>("Graphics\\ball.png");

            BallPosition = new Vector2(player.PlayerPosition.X + (player.Width / 2) - (Width / 2), 
            player.PlayerPosition.Y - Height - 5);

            BallSpeed = new Vector2(5.0f, -5.0f);

            ExtraSpeedOverTime = 1.0f;

            IncreaseSpeed = TimeSpan.FromSeconds(12f);
            PreviousSpeedIncrease = TimeSpan.Zero;

            Active = true;

            Moveball = false;
        }

        public void Update(GraphicsDevice graphicsDevice, GameTime gameTime, Player player)
        {
            if (Moveball)
            {
                BallPosition += BallSpeed;
            }
            else
            {
                BallPosition = new Vector2(player.PlayerPosition.X + (player.Width / 2) - (Width / 2),
                player.PlayerPosition.Y - Height - 5);
            }

            if (gameTime.TotalGameTime - PreviousSpeedIncrease > IncreaseSpeed)
            {
                ExtraSpeedOverTime += 0.01f;

                BallSpeed.X *= ExtraSpeedOverTime;
                BallSpeed.Y *= ExtraSpeedOverTime;

                PreviousSpeedIncrease = gameTime.TotalGameTime;
            }

            // Makes sure that the ball doesn't go to fast
            if (BallSpeed.X > 10.50f)
                BallSpeed.X = 10.50f;
            if (BallSpeed.Y > 10.50f)
                BallSpeed.Y = 10.50f;
            if (BallSpeed.X < -10.50f)
                BallSpeed.X = -10.50f;
            if (BallSpeed.Y < -10.50f)
                BallSpeed.Y = -10.50f;

            // Keep the ball in the boundaries
            Collision.GetBoundaries(graphicsDevice, this);

            // Detect collision between ball and player
            Collision.Collision(player, this);
        }

        public void Update(Brick brick)
        {
            // Detect collision between ball and brick
            Collision.Collision(this, brick);
        }

        public void Draw(SpriteBatch spriteBatch)
        {
            spriteBatch.Draw(BallTexture, BallPosition, null, Color.White, 0f, Vector2.Zero, 1f, SpriteEffects.None, 1f);
        }
    }
}

Мой класс кирпича:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;

namespace BrickBreakerV2
{
    class Brick
    {
        // The texture of the brick
        public Texture2D BrickTexture;

        // The position of the bricks
        public Vector2 BrickPosition;

        // The color tint of the brick
        public Color ColorTint;

        // The "active" state of the brick
        public bool Active;

        // The width of the brick
        public int Width
        {
            get { return BrickTexture.Width; }
        }

        // The height of the brick
        public int Height
        {
            get { return BrickTexture.Height; }
        }

        // Construct a class for collisionhandler
        CollisionHandler Collision;

        public void Initialize(ContentManager Content)
        {
            BrickTexture = Content.Load<Texture2D>("Graphics\\brick.png");

            BrickPosition = new Vector2(600, 500);

            Active = true;

            ColorTint = Color.White;

            Collision = new CollisionHandler();
        }


        public void Update(Ball ball)
        {
            Collision.Collision(ball, this);
        }


        public void Draw(SpriteBatch spriteBatch)
        {
            spriteBatch.Draw(BrickTexture, BrickPosition, null, ColorTint, 0f, Vector2.Zero, 1f, SpriteEffects.None, 1f);
        }
    }
}

И мой блок кода, который обрабатывает столкновение между мячом и кирпичиками в CollisionHandler.cs:

    // Collision between ball and brick
    public void Collision(Ball ball, Brick brick)
    {
        Rectangle BallRectangle = new Rectangle((int)ball.BallPosition.X, (int)ball.BallPosition.Y, ball.Width, ball.Height);
        Rectangle BrickRectangle = new Rectangle((int)brick.BrickPosition.X, (int)brick.BrickPosition.Y, brick.Width, brick.Height);

        if (BallRectangle.Intersects(BrickRectangle))
        {
            int XOverlap;
            int YOverlap;

            if (BallRectangle.Center.X < BrickRectangle.Center.X)
            {
                XOverlap = (BallRectangle.X + ball.Width) - BrickRectangle.X;
            }
            else
            {
                XOverlap = (BrickRectangle.X + brick.Width) - BallRectangle.X;
            }

            if (BallRectangle.Center.Y < BrickRectangle.Center.Y)
            {
                YOverlap = (BallRectangle.Y + ball.Height) - BrickRectangle.Y;
            }
            else
            {
                YOverlap = (BrickRectangle.Y + brick.Height) - BallRectangle.Y;
            }


            if (XOverlap == YOverlap)
            {
                ball.BallSpeed.X *= -1;
                ball.BallSpeed.Y *= -1;
            }
            else if (XOverlap < YOverlap)
            {
                ball.BallSpeed.X *= -1;
            }
            else
            {
                ball.BallSpeed.Y *= -1;
            }

            brick.Active = false;
        }
    }

person Basecrosser    schedule 16.10.2013    source источник
comment
Этот другой ответ может помочь stackoverflow.com/ questions / 1561538 /   -  person craftworkgames    schedule 17.10.2013
comment
Спасибо за ответ. Я пробовал решение, которое было там дано, но стало еще хуже.   -  person Basecrosser    schedule 17.10.2013
comment
Дело в том, что на эти вопросы по отладке моего типа кода нелегко ответить, потому что они требуют большого количества конкретных знаний о вашем коде. Большинство людей не желают воспроизводить проблему из кода, который вы публикуете.   -  person craftworkgames    schedule 18.10.2013
comment
Да, я не ожидаю, что люди будут отлаживать мой код, я просто хотел предоставить достаточно информации для людей, которые хотят мне помочь. Помогло бы, если бы я разместил ссылку, по которой вы можете скачать проект?   -  person Basecrosser    schedule 18.10.2013
comment
Честно говоря, я увидел стену кода в вашем вопросе и не хотел вдаваться в подробности, чтобы выяснить проблему. Прочитав его еще раз, я думаю, что проблема заключается в вашем уровне понимания обнаружения столкновений и реагирования на них. Я думаю, вы легко сможете разобраться с этим, если потратите немного больше времени на поиск в Google и учебные пособия.   -  person craftworkgames    schedule 21.10.2013
comment
Спасибо за помощь, я возвращаюсь к учебному столу и узнаю больше об обнаружении столкновений.   -  person Basecrosser    schedule 21.10.2013


Ответы (1)


Я хочу помочь вам, но я не собираюсь отлаживать ваш код. К счастью, базовое двухмерное обнаружение столкновений и клоны для разбивания кирпичей уже выполнялись много раз.

Быстрый поиск в Google дал следующий учебник. Я сам этого не делал, но если бы я был там, где вы, я бы начал здесь:

http://xnagpa.net/xna4beginner.php

Удачи.

person craftworkgames    schedule 18.10.2013
comment
Спасибо за ответ. Я не жду, что кто-нибудь будет отлаживать мой код, я просто хотел дать достаточно информации? В учебнике, который вы мне дали, инвертируется скорость Y, а затем предлагается использовать отрезок линии, чтобы определить, в какую сторону кирпича попал мяч. Я попробую еще раз. - person Basecrosser; 18.10.2013
comment
Да, тестирование линейного сегмента кажется подходящим решением для такого рода вещей. - person craftworkgames; 21.10.2013