Как я могу выполнить обрезку повернутых прямоугольников? - PullRequest
5 голосов
/ 10 февраля 2011

Итак, у меня есть этот класс Panel.Это немного похоже на окно, где вы можете изменять размеры, закрывать, добавлять кнопки, ползунки и т. Д. Очень похоже на экран состояния в Morrowind, если кто-нибудь из вас помнит.Мне нужно поведение, когда спрайт находится за пределами панели, он не рисуется, а если он находится частично снаружи, то рисуется только часть внутри.То, что он делает сейчас, это сначала получает прямоугольник, который представляет границы панели, и прямоугольник для спрайта, он находит прямоугольник пересечения между ними, а затем переводит это пересечение в локальные координаты прямоугольника спрайта и использует , что для исходного прямоугольника.Это работает, и, насколько я чувствую, код, я не могу избавиться от ощущения, что есть лучший способ сделать это.Кроме того, с этой настройкой я не могу использовать матрицу глобального преобразования для моей 2D-камеры, все в «мире» должно быть передано аргументом камеры для рисования.В любом случае, вот код, который у меня есть:
для пересечения:

     public static Rectangle? Intersection(Rectangle rectangle1, Rectangle rectangle2)
     {
        if (rectangle1.Intersects(rectangle2))
        {
            if (rectangle1.Contains(rectangle2))
            {
                return rectangle2;
            }
            else if (rectangle2.Contains(rectangle1))
            {
                return rectangle1;
            }
            else
            {
                int x = Math.Max(rectangle1.Left, rectangle2.Left);
                int y = Math.Max(rectangle1.Top, rectangle2.Top);
                int height = Math.Min(rectangle1.Bottom, rectangle2.Bottom) - Math.Max(rectangle1.Top, rectangle2.Top);
                int width = Math.Min(rectangle1.Right, rectangle2.Right) - Math.Max(rectangle1.Left, rectangle2.Left);
                return new Rectangle(x, y, width, height);
            }
        }
        else
        {
            return null;
        }
     }

и для фактического рисования на панели:

    public void DrawOnPanel(IDraw sprite, SpriteBatch spriteBatch)
    {
        Rectangle panelRectangle = new Rectangle(
           (int)_position.X,
           (int)_position.Y,
           _width,
           _height);
        Rectangle drawRectangle = new Rectangle();

        drawRectangle.X = (int)sprite.Position.X;
        drawRectangle.Y = (int)sprite.Position.Y;
        drawRectangle.Width = sprite.Width;
        drawRectangle.Height = sprite.Height;

        if (panelRectangle.Contains(drawRectangle))
        {
            sprite.Draw(
                spriteBatch,
                drawRectangle,
                null);
        }
        else if (Intersection(panelRectangle, drawRectangle) == null)
        {
            return;
        }
        else if (Intersection(panelRectangle, drawRectangle).HasValue)
        {
            Rectangle intersection = Intersection(panelRectangle, drawRectangle).Value;

            if (Intersection(panelRectangle, drawRectangle) == drawRectangle)
            {
                sprite.Draw(spriteBatch, intersection, intersection);
            }
            else
            {
                sprite.Draw(
                    spriteBatch,
                    intersection,
                    new Rectangle(
                        intersection.X - drawRectangle.X,
                        intersection.Y - drawRectangle.Y,
                        intersection.Width,
                        intersection.Height));
            }
        }
    }

Так что я думаю, мой вопрос, есть лилучший способ сделать это?

Обновление: только что узнал о свойстве ScissorRectangle.Это похоже на достойный способ сделать это;он требует создания объекта RasterizerState и его передачи в перегрузку spritebatch.Begin, которая его принимает.Похоже, что это может быть лучшим выбором, хотя.Есть также видовой экран, который я могу изменить.Мысли?:)

Ответы [ 2 ]

1 голос
/ 14 февраля 2011

Один из способов сделать это - простое столкновение на пиксель. Хотя это плохая идея, если спрайты большие или многочисленные, это может быть очень простой и быстрый способ выполнить работу с небольшими спрайтами. Во-первых, выполните проверку ограничивающего круга или столкновения ограничивающего квадрата с панелью, чтобы увидеть, нужно ли вам вообще распознавать пиксели.

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

Наконец, если оба из них терпят неудачу, мы должны сделать столкновение за пиксель. Пройдите и проверьте каждый пиксель в спрайте, чтобы увидеть, находится ли он в пределах панели. Если он не установлен, альфа-значение пикселя равно 0.

Вот и все.

1 голос
/ 11 февраля 2011

Есть несколько способов ограничить рисование частью экрана. Если область имеет прямоугольную форму (что здесь имеет место), вы можете установить область просмотра (см. GraphicsDevice) на поверхность панели.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...