Предыдущая часть:
Блок это основной элемент игры. Он содержит необходимые атрибуты для управления логикой движения, и также содержит атрибут GаmeObject, который используется в движке Unity.
Блоки будут делаться чисто программно. Для этого к GameObject добавляются компоненты MeshRenderer и MeshFilter. И задаётся собственно меш. Как это всё делается, я уже описывал в этом материале.
А здесь посмотрим на конкретную реализацию.
Я задал 8 вершин и пометил каждую из них на схеме в комментариях. Используются переменные w и h – это ширина и высота блока. Ширина блока может быть разной, но высота всегда одинаковая, как и глубина, поэтому h используется и для высоты, и для глубины.
Одна вершина может быть общей у трёх граней, поэтому её нужно дублировать для каждой грани отдельно, чтобы между ними была чёткая граница. (Если использовать просто общую вершину, между гранями произойдёт сглаживание и кубик не будет выглядеть как кубик.)
Так что список вершин будет выглядеть так:
Далее задаются грани. Каждая грань состоит из двух треугольников, а треугольник это три индекса из массива _vervices.
0, 1, 2 – это треугольник, построенный по вершинам с индексами 0, 1, 2, то есть это вершины v0, v1, v5, затем идёт треугольник 0, 2, 3, и т.д.
Наконец, задаются нормали:
Нормали задаются для каждой вершины и нужны для освещения. Так как первые 4 вершины в списке принадлежат грани, которая смотрит влево, то первые 4 нормали это Vector3.left, и т.д.
Ещё раз, всё это уже описывалось в предыдущих материалах.
Далее, для работы физического движка добавляем компоненты RigidBody и BoxCollider.
В RigidBody ставим флаг isKinematic=true, потому что движение блоков будет осуществляться программно, и useGravity=false, потому что на блоки не должна действовать гравитация.
Сразу посмотрим на метод Reshape(), который назначает блоку новый размер и цвет. Это нужно для того, чтобы не создавать новые блоки, а использовать их повторно.
Если текущая ширина блока совпадает с новой шириной, мы вообще ничего не делаем, а только меняем цвет. Если же нужно установить новую ширину, то модифицируется та часть массива _vertices, где используется w.
Далее нужно добыть из текущего GameObject компонент MeshFilter и заменить ему vertices на новые. После этого, чтобы вся геометрия работала правильно, нужно вызвать RecalculateBounds(). Также я пересчитываю размеры и центральную координату коллайдера. (Оказалось, что всё это нужно делать вручную, так как при изменении меша ничего само не пересчитывается.)
Наконец, метод SetColor():
Здесь просто назначается цвет материалу рендерера. Но интереснее другое – как этот цвет получается. В задании было указано, что все блоки имеют случайный цвет. При этом они не должны быть белого цвета (это цвет игрока) и серого (цвет фона).
Есть два способа это сделать. Первый – создать массив заранее заданных цветов, и брать случайный цвет из этого массива. Так всё будет предсказуемо.
Второй способ это генерировать полностью случайный цвет. Формат цвета – 32-битное число, поэтому любое случайное число будет соответствовать какому-то цвету. Однако полная случайность здесь работает плохо – цвета будут получаться скорее мутными и плохо отличимыми друг от друга.
В следующих выпусках рассмотрим этот вопрос. Также я даю ссылку на весь проект на гитхабе:
Читайте дальше: