Столкновение спрайтов

Последнее обновление: 14.11.2015

Одним из ключевых моментов в игре является столкновения игровых объектов. Например, герой натыкается со стеной, пуля попадает в героя и так далее.

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

Прямоугольник в MonoGame представлен классом Rectangle. Его метод Intersects() позволяет узнать, пересекается ли он с другим прямоугольником.

Например, пусть у нас есть два спрайта good.png и evil.png, импортированные в проект.

good.png
evil.png

Определим их столкновение, и если столкновение имеется, тогда окрасим игровое поле в красный цвет:

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace Game1
{
    public class Game1 : Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        Texture2D goodTexture; // наш спрайт
        Texture2D evilTexture; // второй спрайт
        Vector2 goodSpritePosition; // позиция нашего спрайта
        Vector2 evilSpritePosition; // позиция второго спрайта
        Point goodSpriteSize; // размер нашего спрайта
        Point evilSpriteSize; // размер второго спрайта
        float goodSpriteSpeed = 5f;
        float evilSpriteSpeed = 2f;

        Color color = Color.CornflowerBlue;

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
            goodSpritePosition = Vector2.Zero;
			//  помещаем второй спрайт на середину по оси Х
            evilSpritePosition = new Vector2(Window.ClientBounds.Width / 2, 0);
        }

        protected override void Initialize()
        {
            base.Initialize();
        }

        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);
            goodTexture = Content.Load<Texture2D>("good");
            evilTexture = Content.Load<Texture2D>("evil");
			// Устанавливаем размеры спрайтов
            goodSpriteSize = new Point(goodTexture.Width, goodTexture.Height);
            evilSpriteSize = new Point(evilTexture.Width, evilTexture.Height);

        }

        protected override void UnloadContent()
        {
        }

        protected override void Update(GameTime gameTime)
        {
            KeyboardState keyboardState = Keyboard.GetState();
            
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || keyboardState.IsKeyDown(Keys.Escape))
                Exit();

            // перемещаем второй спрайт
            evilSpritePosition.X += evilSpriteSpeed;
            if (evilSpritePosition.X > Window.ClientBounds.Width - evilTexture.Width || evilSpritePosition.X < 0)
                evilSpriteSpeed *= -1;

            // перемещаем наш спрайт клавиатурой
            if (keyboardState.IsKeyDown(Keys.Left))
                goodSpritePosition.X -= goodSpriteSpeed;
            if (keyboardState.IsKeyDown(Keys.Right))
                goodSpritePosition.X += goodSpriteSpeed;
            if (keyboardState.IsKeyDown(Keys.Up))
                goodSpritePosition.Y -= goodSpriteSpeed;
            if (keyboardState.IsKeyDown(Keys.Down))
                goodSpritePosition.Y += goodSpriteSpeed;

            // проверяем, не убежал ли наш спрайт с игрового поля
            if (goodSpritePosition.X < 0)
                goodSpritePosition.X = 0;
            if (goodSpritePosition.Y < 0)
                goodSpritePosition.Y = 0;
            if (goodSpritePosition.X > Window.ClientBounds.Width - goodSpriteSize.X)
                goodSpritePosition.X = Window.ClientBounds.Width - goodSpriteSize.X;
            if (goodSpritePosition.Y > Window.ClientBounds.Height - goodSpriteSize.Y)
                goodSpritePosition.Y = Window.ClientBounds.Height - goodSpriteSize.Y;

            if (Collide())
                color = Color.Red;
            else
                color = Color.CornflowerBlue;

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

            spriteBatch.Begin();

            spriteBatch.Draw(goodTexture, goodSpritePosition, Color.White);

            spriteBatch.Draw(evilTexture, evilSpritePosition, Color.White);

            spriteBatch.End();
            base.Draw(gameTime);
        }

        protected bool Collide()
        {
            Rectangle goodSpriteRect = new Rectangle((int)goodSpritePosition.X,
                (int)goodSpritePosition.Y, goodSpriteSize.X, goodSpriteSize.Y);
            Rectangle evilSpriteRect = new Rectangle((int)evilSpritePosition.X,
                (int)evilSpritePosition.Y, evilSpriteSize.X, evilSpriteSize.Y);

            return goodSpriteRect.Intersects(evilSpriteRect);
        }
    }
}

Нашим спрайтом мы управляем клавиатурой, а второй спрайт просто перемещается вперед и назад по оси X.

Столкновение спрайтов в MonoGame

Вся обработка столкновений заключена в методе Collide():

protected bool Collide()
{
    Rectangle goodSpriteRect = new Rectangle((int)goodSpritePosition.X,
        (int)goodSpritePosition.Y, goodSpriteSize.X, goodSpriteSize.Y);
    Rectangle evilSpriteRect = new Rectangle((int)evilSpritePosition.X,
        (int)evilSpritePosition.Y, evilSpriteSize.X, evilSpriteSize.Y);

    return goodSpriteRect.Intersects(evilSpriteRect);
}

В данном случае формируем два прямоугольника и применяем метод Intersects(). Если он возвращает true, значит оба прямоугольника пересекаются.

Это довольно простой способ проверки столкновения двухмерных объектов, в то же время он не идеален. Так как вполне возможно, что у нас могут быть более сложные игровые персонажи, которые не являются прямоугольными. Такие объекты либо надо разбивать на отдельные прямоугольники и затем эти прямоугольники проверять на пересечение. Либо пожертвовать точностью вычислений столкновения, и определять его приблизительно на основе пересечения спрайтов.

Создание паузы

В некоторых играх есть такое действие, как остановка игры, когда пользователь, например, убирает мышку с игрового поля. В своей игре мы можем добавить подобное поведение, причем довольно легко. Для этого изменим код метода Update():

protected override void Update(GameTime gameTime)
{
    if(IsActive)
    {
        KeyboardState keyboardState = Keyboard.GetState();

        if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || keyboardState.IsKeyDown(Keys.Escape))
            Exit();

        // остальной код метода

        base.Update(gameTime);
    }
}

Флаг IsActive указывает, активно ли приложение. И если мы выведем указатель мыши за пределы игрового окна, то игровой цикл приостановится.

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850