Я продолжаю сталкиваться с этой проблемой при создании игровых движков, где мои классы хотят выглядеть так:
interface Entity {
draw();
}
class World {
draw() {
for (e in entities)
e.draw();
}
}
Это просто псевдокод, чтобы показать, как происходит рисование. Каждый подкласс субъекта реализует собственный чертеж. Мир проходит через все сущности, не имеющие особого порядка, и говорит им, чтобы они рисовали друг за другом.
Но с графикой на основе шейдеров это, как правило, ужасно неэффективно или даже невозможно. У каждого типа сущности, вероятно, будет своя собственная программа шейдеров. Чтобы свести к минимуму изменения программы, все объекты каждого конкретного типа необходимо объединить. Простые типы сущностей, например частицы, могут также захотеть агрегировать их рисунок другими способами, например, использовать один большой массив вершин. И это становится действительно волосатым с смешиванием и таким, где некоторые типы сущностей должны быть визуализированы в определенное время относительно других или даже в несколько раз для разных проходов.
То, что я обычно получаю, - это своего рода рендеринг singleton для каждого класса сущности, который хранит список всех экземпляров и выводит их все сразу. Это не так уж плохо, поскольку он отделяет рисунок от логики игры. Но рендерингу необходимо выяснить, какое подмножество объектов нужно рисовать, и ему нужен доступ к нескольким частям графического конвейера. Здесь моя объектная модель имеет тенденцию становиться беспорядочной, с большим количеством дублированного кода, плотной связью и другими плохими вещами.
Итак, мой вопрос: что такое хорошая архитектура для такого игрового рисунка, который эффективен, универсален и модулен?