2013-09-16 3 views
2

Я разрабатываю свой собственный физический движок для школьного проекта, и в последнее время я столкнулся с проблемой: на пиксельные столкновения на больших спрайтах мой FPS выпал ЛОТ.Оптимизация столкновений с пикселями

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

private bool PerPixelCollision(IObject a, IObject b) 
{ 

    Color[] bitsA = new Color[a.Texture.Width * a.Texture.Height]; 
    a.Texture.GetData(bitsA); 
    Color[] bitsB = new Color[b.Texture.Width * b.Texture.Height]; 
    b.Texture.GetData(bitsB); 

    // Calculate the intersecting rectangle 
    int x1 = Math.Max(a.Bounds.X, b.Bounds.X); 
    int x2 = Math.Min(a.Bounds.X + a.Bounds.Width, b.Bounds.X + b.Bounds.Width); 

    int y1 = Math.Max(a.Bounds.Y, b.Bounds.Y); 
    int y2 = Math.Min(a.Bounds.Y + a.Bounds.Height, b.Bounds.Y + b.Bounds.Height); 

    Color c; 
    Color d; 
    // For each single pixel in the intersecting rectangle 
    for (int y = y1; y < y2; ++y) 
    { 
     for (int x = x1; x < x2; ++x) 
     { 
      // Get the color from each texture 
      c = bitsA[(x - a.Bounds.X) + (y - a.Bounds.Y) * a.Texture.Width]; 
      d = bitsB[(x - b.Bounds.X) + (y - b.Bounds.Y) * b.Texture.Width]; 

      if (c.A != 0 && d.A != 0) // If both colors are not transparent (the alpha channel is not 0), then there is a collision 
      { 
       return true; 
      } 
     } 
    } 
    // If no collision occurred by now, we're clear. 
    return false; 
} 

В примере я использую для тестирования я сбросив 4 спрайтов в другой спрайт, который представляет слово (736x79). Когда я изменяю спрайт, представляющий пол, для большего спрайта (3600x270), FPS падает. Я знаю, проблема в столкновении пикселей, потому что я использую профилировщик.

Кто-нибудь знает, как оптимизировать столкновение?

P.S .: Извините, если я не был достаточно ясен о своей проблеме. Мой английский не так хорош.

EDIT: первая проблема была решена с помощью решения, предоставленного @pinckerman, но я нашел еще один, связанный с обнаружением столкновений пикселей. Когда спрайт сталкивается с прозрачной частью текстуры, мы получаем часть, которая пересекается и проверяет все пиксели этой части. Проблема заключается в следующем: когда прозрачная часть достаточно большая, чтобы покрыть весь спрайт, я проверяю всю текстуру этого спрайта (в настоящее время использую текстуры 50x50, которые составляют 2500 пикселей). Есть ли способ не проверять всю текстуру?

Благодаря

+2

Я не эксперт, но я не думаю, что вы должны выполнить проверку на столкновение пикселов на чем-то наподобие пола. Если вы хотите столкнуться с рельефом местности, выполните некоторую проверку столкновения полигонов. Или, если пол просто плоский, сделайте прямоугольник или даже проверку пересечения линии. Извините, но я не могу помочь вам с оптимизацией вашего алгоритма. –

+0

не используйте это. это убийца перемирия. использовать линию, поле, круг, столкновение многоугольников. или все вместе в сочетании, но не столкновение пикселей. это просто трата ресурсов. –

+0

Я чувствую, что нужно добавить свой голос в толпу и указать, что вы всегда будете сталкиваться с проблемами производительности, делающими такое обнаружение столкновений.Вызов 'GetData()' на текстуре _ называет конвейер рендеринга_, что предотвращает совместную работу графического процессора и ЦПУ с максимальной эффективностью. В большинстве случаев лучше использовать геометрическое обнаружение столкновений - хотя, конечно, нет ничего плохого в такого рода вещах, как учебное упражнение. См. [Эту статью] (http://blogs.msdn.com/b/shawnhar/archive/2008/04/14/stalling-the-pipeline.aspx) для получения дополнительной информации. –

ответ

2

Я уверен, что ваш FPS падение так много, потому что вы делаете

Color[] bitsA = new Color[a.Texture.Width * a.Texture.Height]; 
a.Texture.GetData(bitsA); 
Color[] bitsB = new Color[b.Texture.Width * b.Texture.Height]; 
b.Texture.GetData(bitsB); 

в начале вашего метода.
Предположим, вы звоните в ваш PerPixelCollision каждый цикл Update, создавая и справляясь с миллионами значений каждого игрового цикла, это не очень эффективная вещь.

Большой спрайт создает огромный массив Color[]: чем больше ваши массивы, тем медленнее будет этот метод.

EDIT:

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

PS: Я вижу, что вы получаете пересекающийся Rectangle по своему усмотрению, возможно, вы могли бы найти полезный this method.

+2

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

+0

@ColeCampbell Полностью согласен. – pinckerman

+0

Спасибо @pinckerman! Проблема была решена :) но я нашел еще один x.x. Пожалуйста, прочтите примечание по редактированию сообщения –

Смежные вопросы