Делаем универсальную сетку

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

Для начала нам понадобится сам объект, который мы будем расставлять по сетке. DefaultItem это обычный спрайт с текстовым полем, чтобы быть уверенным, что элементы расположены именно в таком порядке какой нам нужен.

Сетка предназначена для объектов с нулевой точкой регистрации и при отрисовке нашего спрайта нужно об этом помнить. Сам спрайт будет шириной и высотой в 72px.

Код DefaultItem.as

package {
    import flash.display.*;
    import flash.text.*;
    import flash.geom.*;

    public class DefaultItem extends Sprite {
        private const COLOR:uint = 0x900000;
        private const WIDTH:int = 72;
        private const HEIGHT:int = 72;
       
        public var label:TextField;
              
        public function DefaultItem(labelText:String = "") {
            graphics.beginFill(COLOR);
            graphics.drawRect(-WIDTH * 0.5, -HEIGHT * 0.5, WIDTH, HEIGHT);
            graphics.endFill();
           
            label = new TextField();
            label.autoSize = TextFieldAutoSize.CENTER;
            label.defaultTextFormat = new TextFormat("Tahoma", 14, 0xFFFFFF);
            label.text = labelText;    
            label.x = -label.width * 0.5;
            label.y = -label.height * 0.5;
            addChild(label);
        }
    }
}

Для самой сетки нам понадобятся набор параметров определяющий внешний вид отображения.

  • GRID_WIDTH - количество элементов по горизонтали
  • GRID_HEIGHT - количество элементов по вертикали
  • GRID_POSITION_X - центр сетки по горизонтали
  • GRID_POSITION_Y - центр сетки по вертикали
  • SPACING - расстояние между элементами
  • CELL_WIDTH - ширина ячейки
  • CELL_HEIGHT - высота ячейки

Сам ролик будет размером 640x480 и сетка будет располагаться строго по центру.

Код Grid.as

package {
    import flash.display.*;
    import flash.events.*;
    
    [SWF(width="640", height="480", backgroundColor="0x222222", frameRate="30")]
    public class Grid extends Sprite {
        private const GRID_POSITION_X:int = 320;
        private const GRID_POSITION_Y:int = 240;
       
        private const GRID_WIDTH:int = 6;
        private const GRID_HEIGHT:int = 3;
       
        private const CELL_WIDTH:int = 72;
        private const CELL_HEIGHT:int = 72;
       
        private const SPACING:int = 2;

        public function Grid() {
            var cellWidth:int = CELL_WIDTH + SPACING;
            var cellHeight:int = CELL_HEIGHT + SPACING;
           
            var ofsetX:Number = GRID_POSITION_X - (GRID_WIDTH * cellWidth) * 0.5;
            var ofsetY:Number = GRID_POSITION_Y - (GRID_HEIGHT * cellHeight) * 0.5;
       
            var inc:int = 1;
           
            for (var i:int = 0; i < GRID_HEIGHT; i++) {
                for (var j:int = 0; j < GRID_WIDTH; j++) {
                    var cx:Number = ofsetX + j * cellWidth;
                    var cy:Number = ofsetY + i * cellHeight;
                    cx = cx + cellWidth * 0.5;
                    cy = cy + cellHeight * 0.5;
                   
                    var item:DefaultItem = new DefaultItem("Item "+inc);
                    item.x = cx; item.y = cy;
                    addChild(item);
                   
                    inc++;
                }
            }
        }
    }
}

Так как у нас при построении сетки идет двойной цикл - в коде есть переменая inc, которая начинается с единицы и прибавляется на одну единицу при создании очередного элемента, помогая нам указывать какой именно по счету элемент был добавлен.

Теперь можно протестировать ролик и посмотреть результат:

Дополнение: у нас в сетке 6*3 = 18 элементов. Как быть если в сетке должно располагаться, к примеру, 15 элементов? Сделать это довольно просто. Нам нужна еще одна константа с максимальным количеством элементов:

private const TOTAL_ITEMS:int = 15;

После этого нужно добавить еще одну строчку в код, как раз перед добавлением элемента:

if (inc > TOTAL_ITEMS) continue;

Таким образом новые объекты уже не будут добавляться. Тестируем: