Динамически изменять или уничтожать Texture2D для рисования и обнаружения столкновений.

Я использую XNA для 2D-проекта. У меня есть проблема, и я не знаю, как ее решить. У меня есть текстура (изображение), которая рисуется на экране, например:

|+++|+++|
|---|---|
|+++|+++|

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

|+++|
|---|---|
|+++|+++|

так что коллизия теперь будет работать и для нового изображения.

Каким способом лучше решить эту проблему:

  1. Замените всю текстуру на другую текстуру, прозрачную в местах разрушения.
  2. Используйте некоторые хитрости с spriteBatch.Draw(sourceRectangle, destinationRectangle) для получения желаемых прямоугольников, а также каким-то образом выполняйте проверку столкновений с этим.
  3. Разделите текстуру на 4 меньшие текстуры, каждая из которых будет отвечать за собственное обнаружение отрисовки/столкновений.
  4. Используйте какой-то другой хитрый способ, о котором я не знаю.

Любая помощь будет оценена по достоинству. Дайте мне знать, если вам нужно больше разъяснений/примеров.

РЕДАКТИРОВАТЬ: Чтобы уточнить, я приведу пример использования для этого. Представьте себе кусок стены размером 4x4, в который при выстреле разрушается небольшая часть 1x1.


person Andriy Drozdyuk    schedule 27.04.2009    source источник
comment
Было бы полезно немного больше информации о проблеме. Например, что представляет собой текстура в игре? Следует ли разрушение объекта предсказуемой схеме или оно полностью динамическое/случайное?   -  person Steven Richards    schedule 29.04.2009
comment
Что-то вроде стены или ящика, который разрушается по частям при выстреле.   -  person Andriy Drozdyuk    schedule 30.04.2009


Ответы (4)


Я выберу третий вариант:

3 — разделите текстуру на 4 меньшие текстуры, каждая из которых будет отвечать за собственный рисунок/обнаружение столкновений.

Это нетрудно сделать. В основном это то же самое, что и структура TileSet. Однако вам нужно будет изменить свой код, чтобы он соответствовал этому подходу. Прочитайте немного о тайлах на: http://www-cs-students.stanford.edu/~amitp/gameprog.html#tiles Многие сайты и книги говорят о тайлах и о том, как их использовать для построения игровых миров. Но вы можете применить эту логику ко всему, что целиком представляет собой компост из маленьких частей.

Позвольте мне быстро отметить другие варианты:

1 — заменить всю текстуру другой текстурой, прозрачной в местах, где она разрушена.

Нет... иметь разный образ для каждой разной позиции - это плохо. Если вам нужно изменить текстуру? Будете ли вы переделывать каждое изображение снова?

2. Используйте некоторые хитрости с spriteBatch.Draw(sourceRectangle, destinationRectangle) для получения нужных прямоугольников, а также каким-то образом выполняйте проверку столкновений с этим.

К сожалению, это не работает, потому что spriteBatch.Draw работает только с прямоугольниками :(

4 Использовать какой-то другой хитрый способ, о котором я не знаю.

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

person Gustavo Cardoso    schedule 30.04.2009

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

person Community    schedule 29.04.2009
comment
Это интересно и кажется чем-то, что я могу использовать, но я не могу понять это, так как это немного сложно. Я не уверен, как он достигает эффекта. - person Andriy Drozdyuk; 30.04.2009
comment
В двух словах, он использует попиксельное столкновение, чтобы определить, какие пиксели перекрываются. Затем он делает эти пиксели прозрачными, создавая ощущение, что земля была деформирована. Имейте в виду, что это может быть дорогостоящей операцией. - person ; 30.04.2009
comment
Спасибо, но это слишком сложно для моих нужд. - person Andriy Drozdyuk; 04.05.2009

Вариант №3 подойдет.

Более надежная система (если вы не хотите ограничиваться рамками) будет использовать обнаружение столкновений для каждого пикселя. Процесс в основном работает следующим образом:

  1. Рассчитать ограничивающую рамку (или круг) для каждого объекта
  2. Проверьте, не перекрываются ли два объекта
  3. Для каждого перекрытия перенесите спрайты на скрытую поверхность, сравнивая значения пикселей по мере продвижения. Если пиксель уже установлен, когда вы пытаетесь нарисовать пиксель из второго спрайта, возникает коллизия.

Вот хороший пример XNA (на самом деле, еще одна статья Ziggyware): Обнаружение коллизий 2D Per Pixel

Еще несколько ссылок:

Может ли кто-нибудь объяснить обнаружение столкновений для каждого пикселя

XNA 2-мерное попиксельное столкновение

person Steven Richards    schedule 30.04.2009
comment
Спасибо, но как решение Джо, это больше, чем мне нужно на данный момент. - person Andriy Drozdyuk; 04.05.2009

В итоге я выбрал вариант 3. По сути, у меня есть класс Tile, который содержит текстуру и размер. Размерность n означает, что внутри этой плитки имеется n*n подфрагментов. У меня также есть массив, который отслеживает, какие плитки уничтожены или нет. Мой класс выглядит так в псевдокоде:

 class Tile
     texture
     dimention
     int [,] subtiles; //0 or 1 for each subtile

     public Tile() // constructor
         subtiles = new int[dimention, dimention];
         intialize_subtiles_to(1);

     public Draw() // this is how we know which one to draw
        //iterate over subtiles
        for(int i..
          for(int j ...)
             if(subtiles[i,j] == 1)
                Vector2 draw_pos = Vector2(i*tilewidth,
                                      j*tileheight)                       
                spritebatch.Draw(texture, draw_pos)

Аналогичным образом у меня есть метод столкновения, который проверяет наличие столкновения:

   public bool collides(Rectangle rect)
       //iterate over subtiles 
       for i...
          for j..
              if(subtiles[i,j]==0) continue;

              subtile_rect = //figure out the rect for this subtile
              if(subtile_rect.intersects(rect))
                   return true;

       return false;

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

person Andriy Drozdyuk    schedule 04.05.2009