Отобразить карту плитки с помощью javascript

Я ищу логическое понимание с примерами идей реализации при использовании такой таблицы:

http://thorsummoner.github.io/old-html-tabletop-test/pallete/tilesets/fullmap/scbw_tiles.png

И рендеринг в логическом виде, например:

http://thorsummoner.github.io/old-html-tabletop-test/

Я вижу, что все плитки есть, но я не понимаю, как они помещаются таким образом, что формирует фигуры.

Мое понимание рендеринга плиток до сих пор прост и очень ручное. Петля через массив карт, где есть числа (1, 2, 3, что угодно), визуализируйте указанный фрагмент.

var mapArray = [
    [0, 0, 0, 0 ,0],
    [0, 1, 0, 0 ,0],
    [0, 0, 0, 0 ,0],
    [0, 0, 0, 0 ,0],
    [0, 0, 1, 1 ,0]
];

function drawMap() {
    background = new createjs.Container();      
    for (var y = 0; y < mapArray.length; y++) {
        for (var x = 0; x < mapArray[y].length; x++) {
            if (parseInt(mapArray[y][x]) == 0) {
                var tile = new createjs.Bitmap('images/tile.png');
            }
            if (parseInt(mapArray[y][x]) == 1) {
                var tile = new createjs.Bitmap('images/tile2.png'); 
            }
            tile.x = x * 28;
            tile.y = y * 28;
            background.addChild(tile);
        }
    }
    stage.addChild(background);     
}   

Получает меня:

enter image description here

Но это означает, что я должен вручную определить, где каждая плитка идет в массиве, чтобы были сделаны логические формы (скальные образования, патча травы и т.д.).

Очевидно, что парень, который сделал вышеприведенный код github, использовал другой метод. Любое руководство по пониманию логики (с простым псевдокодом) было бы очень полезно

Ответ 1

Там нет никакой логики.

Если вы проверите источник страницы, вы увидите, что последний тег script в теле имеет огромный массив координат плитки.

В этом примере нет магии, которая демонстрирует "интеллектуальную" систему для определения того, как формировать фигуры.

Теперь, что сказано, есть такие вещи...... но они не слишком просты.

Что более просто и управляемо, это редактор карт.


Редакторы плитки

из коробки:

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

Tiled (http://mapeditor.org) - один из таких примеров.
Есть и другие, но Плитка - это первая, о которой я мог думать, свободен и на самом деле вполне приличный.

плюсы:
Непосредственным плюсом является то, что вы получаете приложение, которое позволяет загружать фрагменты изображений и рисовать их на картах.
Эти приложения могут даже поддерживать добавление уровней конфликтов и уровней сущностей (поставить противника на [2,1], включить питание в [3,5] и триггер "больного игрока" по лаве).

минусы: ... недостатком является то, что вам нужно точно знать, как эти файлы отформатированы, чтобы вы могли прочитать их в своих игровых движках.
Теперь выходы этих систем относительно стандартизированы... так что вы можете подключить эти данные к карте в разные игровые движки (в чем дело, в противном случае?), А в то время как игровые движки не все используют файлы плитки, которые точно те же самые, самые хорошие редакторы плитки позволяют экспортировать в несколько форматов (некоторые позволят вам определить свой собственный формат).

... так что, альтернатива (или действительно то же самое решение, только ручная работа), было бы создать собственный редактор плитки.

DIY
Вы можете создать его в Canvas, так же легко, как создать движок для рисования плиток.
Главное различие заключается в том, что у вас есть карта плиток (например, tilemap.png из StarCr... erm... "найденное искусство" из примера, там). Вместо того, чтобы перебирать массив, находить координаты плитки и рисовать их по координатам мира, которые соответствуют этому индексу, то, что вы сделали бы, это выбрать фрагмент с карты (например, выбрать цвет в MS Paint), а затем где угодно вы нажимаете (или перетаскиваете), вычисляете, к какой точке массива относится, и устанавливаете этот индекс равным этому фрагменту.

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

базовая реализация
Хотя я обычно стараюсь сделать эту опрятную и дружественную JS-парадигму, это приведет к большому количеству кода. Поэтому я попытаюсь обозначить, где это, вероятно, должно быть разбито на отдельные модули.

// assuming images are already loaded properly
// and have fired onload events, which you've listened for
// so that there are no surprises, when your engine tries to
// paint something that isn't there, yet


// this should all be wrapped in a module that deals with
// loading tile-maps, selecting the tile to "paint" with,
// and generating the data-format for the tile, for you to put into the array
// (or accepting plug-in data-formatters, to do so)
var selected_tile = null,
    selected_tile_map = get_tile_map(), // this would be an image with your tiles
    tile_width  = 64, // in image-pixels, not canvas/screen-pixels
    tile_height = 64, // in image-pixels, not canvas/screen-pixels

    num_tiles_x = selected_tile_map.width  / tile_width,
    num_tiles_y = selected_tile_map.height / tile_height,

    select_tile_num_from_map = function (map_px_X, map_px_Y) {
        // there are *lots* of ways to do this, but keeping it simple
        var tile_y = Math.floor(map_px_Y / tile_height), // 4 = floor(280/64)
            tile_x = Math.floor(map_px_X / tile_width ),

            tile_num = tile_y * num_tiles_x + tile_x;
            // 23 = 4 down * 5 per row + 3 over

        return tile_num;
    };

    // won't go into event-handling and coordinate-normalization
    selected_tile_map.onclick = function (evt) {
        // these are the coordinates of the click,
        //as they relate to the actual image at full scale
        map_x, map_y;
        selected_tile = select_tile_num_from_map(map_x, map_y);
    };

Теперь у вас есть простая система для определения того, какая плитка была нажата.
Опять же, есть много способов построения этого, и вы можете сделать его более OO,
и создать правильную структуру данных "плитки", которую вы ожидаете прочитать и использовать на своем движке.

Прямо сейчас, я просто возвращаю нулевой номер плитки, читая слева направо, сверху вниз.
Если в строке указано 5 плиток, а кто-то выбирает первую плитку второй строки, это плитка №5.

Затем для "живописи" вам просто нужно прослушать щелчок на холсте, выяснить, что такое X и Y, выяснить, где в мире, что есть, и какое место в массиве, равное.
Оттуда вы просто сбрасываете значение selected_tile, и об этом.

// this might be one long array, like I did with the tile-map and the number of the tile
// or it might be an array of arrays: each inner-array would be a "row",
// and the outer array would keep track of how many rows down you are,
// from the top of the world
var world_map = [],

    selected_coordinate = 0,

    world_tile_width  = 64, // these might be in *canvas* pixels, or "world" pixels
    world_tile_height = 64, // this is so you can scale the size of tiles,
                            // or zoom in and out of the map, etc

    world_width  = 320,
    world_height = 320,


    num_world_tiles_x = world_width  / world_tile_width,
    num_world_tiles_y = world_height / world_tile_height,

    get_map_coordinates_from_click = function (world_x, world_y) {
        var coord_x = Math.floor(world_px_x / num_world_tiles_x),
            coord_y = Math.floor(world_px_y / num_world_tiles_y),

            array_coord = coord_y * num_world_tiles_x + coord_x;

        return array_coord;
    },

    set_map_tile = function (index, tile) {
        world_map[index] = tile;
    };

    canvas.onclick = function (evt) {
        // convert screen x/y to canvas, and canvas to world
        world_px_x, world_px_y;
        selected_coordinate = get_map_coordinates_from_click(world_px_x, world_px_y);

        set_map_tile(selected_coordinate, selected_tile);
    };

Как вы можете видеть, процедура его выполнения практически такая же, как и процедура для другого (потому что она - задана x и y в одном наборе координат, преобразует ее в другую шкалу/набор).

Таким образом, процедура рисования плиток почти полностью противоположна.
Учитывая мировой индекс и номер плитки, работайте в обратном порядке, чтобы найти мир-x/y и tilemap-x/y.
Вы также можете увидеть эту часть в вашем примере кода.

Эта плитка - традиционный способ сделать 2d-карты, независимо от того, говорим ли мы о StarCraft, Zelda или Mario Bros.
Не у всех из них была роскошь иметь редактор "paint with tiles" (некоторые из них были вручную в текстовых файлах или даже в электронных таблицах, чтобы получить интервал справа), но если вы загружаете StarCraft или даже WarCraft III (который 3D), и зайдите в их редакторы, художник-плит - это именно то, что вы получаете, и именно так Blizzard сделала эти карты.

дополнения

С базовой предпосылкой, у вас теперь есть другие "карты", которые также необходимы: вам понадобится карта столкновения, чтобы узнать, из какой из этих плиток вы могли/не могли ходить, карты сущностей, чтобы показать, где есть двери, или бонусы или минералы, или вражеские икру, триггеры для роликов...

Не все из них должны работать в том же координатном пространстве, что и карта мира, но это может помочь.

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

... способ сохранить как информацию о фрагментах (не только X/Y, но и другую информацию о плитке), так и сохранить готовый массив "map", заполненный плитками.

Даже просто копирование JSON и вставка его в собственный файл...


Процедурное поколение

Другой способ сделать это, то, как вы предложили ранее ( "знать, как соединить камни, траву и т.д." ), называется процедурным поколением.
Это намного сложнее, и LOT больше задействован.
Такие игры, как Diablo, используют это, так что вы играете в другой случайной среде, каждый раз, когда играете. Warframe - это FPS, который использует процессуальное поколение для выполнения того же самого.

Предпосылка:
В принципе, вы начинаете с плиток, а вместо того, чтобы просто быть плиткой, являющейся образом, плитка должна быть объектом, у которого есть изображение и позиция, но ТАКЖЕ имеет список вещей, которые, вероятно, будут вокруг него. Когда вы положите патч травы, у этой травы будет вероятность получить больше травы рядом с ней.
Трава может сказать, что есть 10% -ный шанс воды, 20% -ный шанс на скалы, 30-процентный шанс на грязь и 40% -ный шанс больше травы в любом из четырех направлений вокруг нее.

Конечно, это действительно не так просто (или это может быть, если вы ошибаетесь).

Хотя эта идея, сложная часть процессуального поколения фактически заключается в том, чтобы убедиться, что все работает без нарушения.
ограничения
Вы не могли, например, иметь стену скалы, в этом примере, появляться на внутренней стороне высокогорья. Он может появляться только там, где выше по высоте и справа, и внизу внизу и влево (и редактор StarCraft сделал это автоматически, как вы нарисовали). Рампы могут только соединять плитки, которые имеют смысл. Вы не можете стянуть дверь или обернуть мир в реку/озеро, которая мешает вам двигаться (или, что еще хуже, мешает вам достичь уровня).

профи
Действительно отлично подходит для долголетия, если вы можете получить все ваши пути и ограничения для работы - не только для псевдослучайной генерации ландшафта и макета, но также для размещения врагов, размещения лута и т.д.
Люди по-прежнему играют Diablo II, почти 14 лет спустя.

против
На самом деле трудно получить право, когда вы являетесь командой одного человека (который в свое свободное время не является математиком/ученым с данными).
Действительно плохо для гарантии того, что карты являются веселыми/сбалансированными/конкурентоспособными...
StarCraft никогда не могла использовать 100% случайное поколение для честного игрового процесса.
Процедурное поколение может использоваться как "семя".
Вы можете нажать кнопку "randomize", посмотреть, что вы получаете, а затем настроить и исправить оттуда, но будет так много исправлений для "баланса" или так много правил игры, написанных для ограничения распространения, ll в конечном итоге тратят больше времени на фиксацию генератора, чем просто нарисовать карту, самостоятельно.

Есть несколько учебных пособий, и изучение генетических алгоритмов, поиск путей и т.д. - все это отличные навыки, чтобы...... buuuut, для обучения чтению 2D сверху вниз плит-игр, путь-overkill, и, скорее, это то, что нужно изучить после того, как вы получите игру/двигатель или два под вашим поясом.