Задать вопрос

Как рассчитать позицию отрисовки тайла на изометрической сетке?

Имеется изометрическая сетка, на сетке необходимо разместить объекты. Особенность сетки в том, что каждая ее ячейка имеет подъячейки:
property int mapWidth: 6 // количество клеток по горизонтали
property int mapHeight: 6 // количество клеток по вертикали
property int cellSize: 128 // размер клетки
property int cellDivider: 2 // делитель клетки (каждая клетка имеет 4 подклетки)
// property int cellDivider: 3 // каждая клетка имеет 9 подклеток

55c579aeacc74757bf99f50d5d303c3c.png

Стандартный тайл должен занимать ровно одну клетку (ячейку), описывается он таким образом:
{ 
    "row": 4, // строка
    "col": 2, // колонка
    "wsize": 2, // занимаемая ширина в "подклетках"
    "hsize": 2, // занимаемая высота в "подклетках"
    "wpos": 1, // позиция в строке "подклетки"
    "hpos": 1, // позиция в колонке "подклетки"
    "source": "/tiles/tree1.png", // путь к изображению
    "width": 300, // оригинальный размер изображения
    "height": 200,
}


Для размещения такого тайла на карте вывел такие жутковатые формулы:
property int tileWidth: 128 // ширина стандартного тайла
property int tileHeight: tileWidth/2 // высота стандартного тайла

function createTile(tileInfo) {
    // тут нормализуется размер тайла
    var tile_w = tileWidth * tileInfo.wsize / cellDivider
    var tile_h = tileWidth/tileInfo.width * tileInfo.height * tileInfo.hsize / cellDivider
    // tileWidth/tileInfo.width => ratio

    var tile_x = (map.width/2 + tileInfo.col*tileWidth/2 - tileInfo.row*tileWidth/2 - tileWidth/2)
    var tile_y = (tileInfo.row*tileHeight/2 + tileInfo.col*tileHeight/2) - tile_h + tileHeight/2
    /* ... */
}

где:
  • map.width - полная ширина карты: map.width = mapWidth * cellSize (6 * 128)
  • tileInfo - информация о тайле
  • - tile_h + tileHeight/2 - тут отнимается высота полученного изображения, чтобы разметить картинку в центре клетки


Ну вроде получилось и нарисовалось:
52286b12bcee475ea52aef80bce60175.png

Но теперь нужно нарисовать маленький "тайлик" в пол клетки:
{ 
    "row": 4,  // строка
    "col": 2, // колонка
    "wsize": 1, // занимаемая ширина в "подклетках"
    "hsize": 1, // занимаемая высота в "подклетках" 
    "wpos": 1, // позиция в строке "подклетки"
    "hpos": 1, // позиция в колонке "подклетки"
    "source": "/tiles/smalltile.png", 
    "width": 300, 
    "height": 200,
}

и вот куда он нарисовался:
2720d679dcfb42739b51bc45ace0a567.png
Большая синяя клетка - это как бы представление координат "подклеток"
Маленькая синяя клетка под деревом - это та "подклетка", где по идее должен был разместится тайл, но представленная формула не обрабатывает параметры wpos и xpos, потому что я не смог впихать их правильно :-) что-бы я не пытался сделать, разноразмерные тайлы начинали прыгать относительно основной клетки в разные стороны.

Собственно, сам вопрос: как правильно составить формулу по исходным данным?
И еще попутный вопрос: насколько такой подход правилен/неправилен? Может есть метод проще/лучше?
  • Вопрос задан
  • 881 просмотр
Подписаться 4 Оценить 4 комментария
Пригласить эксперта
Ответы на вопрос 3
@wxmaper Автор вопроса
В общем получилось вот что:
property var mapObjects: [
        { "row": 4, "col": 2, "wsize": 1, "hsize": 1, "wpos": 0, "hpos": 0,
            "source": "qrc:/tiles/002-000-00.png", "width": 500, "height": 373 },
        { "row": 4, "col": 2, "wsize": 2, "hsize": 2, "wpos": 1, "hpos": 1,
            "source": "qrc:/tiles/001-001-00.png", "width": 2079, "height": 3249 }, // tree
        { "row": 4, "col": 3, "wsize": 2, "hsize": 2, "wpos": 1, "hpos": 1,
            "source": "qrc:/tiles/001-002-00.png", "width": 1100, "height": 823 }, // tree
        { "row": 4, "col": 2, "wsize": 1, "hsize": 1, "wpos": 1, "hpos": 1,
            "source": "qrc:/tiles/002-000-00.png", "width": 500, "height": 373 }, 
        { "row": 4, "col": 3, "wsize": 1, "hsize": 1, "wpos": 1, "hpos": 0,
            "source": "qrc:/tiles/002-000-00.png", "width": 500, "height": 373 },
        { "row": 4, "col": 3, "wsize": 1, "hsize": 1, "wpos": 1, "hpos": 1,
            "source": "qrc:/tiles/002-000-00.png", "width": 500, "height": 373 },
    ]

function createMapObjects() {
    mapObjects.map(function(tileInfo) {
        // нормализация размера создаваемого тайла
        var tile_w = tileWidth * tileInfo.wsize / cellDivider
        var tile_h = tileWidth/tileInfo.width * tileInfo.height * tileInfo.hsize / cellDivider

        // левая верхняя координата описывающего клетку прямоугольника
        var tile_sx = (map.width/2 + tileInfo.col*tileWidth/2 - tileInfo.row*tileWidth/2 - tileWidth/2)
        var tile_sy = (tileInfo.row*tileHeight/2 + tileInfo.col*tileHeight/2) - tile_h

        // координата создаваемого тайла
        var tile_x = tile_sx + tileWidth/cellDivider * tileInfo.wsize/cellDivider
                + (tileWidth/cellDivider * tileInfo.wsize/cellDivider * tileInfo.wpos) * (cellDivider - tileInfo.wsize)
                - (tileHeight/cellDivider * tileInfo.hsize * tileInfo.hpos)

        var tile_y = tile_sy + tileHeight/cellDivider * tileInfo.hsize/cellDivider
                + (tileHeight/cellDivider * tileInfo.hsize/cellDivider * tileInfo.hpos) * (cellDivider - tileInfo.hsize)
                + (tileHeight/cellDivider * tileInfo.wsize/cellDivider * tileInfo.wpos) * (cellDivider - tileInfo.wsize)
    })
}


Формулы дикие и, как выяснилось, подходят только для cellDivider = 2 ;-(
уверен, можно сделать проще и правильнее :D

2cff51d94cac4f358074b1df04ea80ed.png
Ответ написан
Комментировать
Taraflex
@Taraflex
Ищу работу. Контакты в профиле.
Тут описаны некоторые подходы
habrahabr.ru/post/269653
Ответ написан
xmoonlight
@xmoonlight
https://sitecoder.blogspot.com
Используйте все расчеты на сетке с ячейкой одного размера - "пиксель".
При формировании случайных зарослей - используйте группу пикселей = размер "кисти".
Заполнение с помощью такой кисти прописывается заранее: проценты мелких тайлов.
При нанесении - кисть ЗАМЕНЯЕТ все, что попало в её поле.
Посмотртите редактор карт Age of Empires II для примера: https://www.youtube.com/watch?v=TX4bg98uYZ8
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы